aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md18
-rwxr-xr-xci/x86_64-linux-debug.sh2
-rwxr-xr-xci/x86_64-linux-release.sh2
-rw-r--r--lib/compiler/aro/aro/Builtins/Builtin.zig2
-rw-r--r--lib/compiler/aro/aro/Parser.zig2
-rw-r--r--lib/compiler/objcopy.zig7
-rw-r--r--lib/std/Build.zig2
-rw-r--r--lib/std/Build/Cache.zig9
-rw-r--r--lib/std/Build/Fuzz.zig18
-rw-r--r--lib/std/Build/Fuzz/WebServer.zig44
-rw-r--r--lib/std/Build/Step.zig23
-rw-r--r--lib/std/Build/Step/Compile.zig29
-rw-r--r--lib/std/Build/Step/InstallArtifact.zig49
-rw-r--r--lib/std/Build/Step/Run.zig5
-rw-r--r--lib/std/Build/Step/TranslateC.zig19
-rw-r--r--lib/std/c.zig132
-rw-r--r--lib/std/c/darwin.zig5
-rw-r--r--lib/std/crypto.zig5
-rw-r--r--lib/std/crypto/aes/soft.zig2
-rw-r--r--lib/std/crypto/blake2.zig4
-rw-r--r--lib/std/crypto/ml_kem.zig38
-rw-r--r--lib/std/crypto/pcurves/p384.zig2
-rw-r--r--lib/std/debug.zig2
-rw-r--r--lib/std/debug/Dwarf.zig8
-rw-r--r--lib/std/dwarf.zig1
-rw-r--r--lib/std/enums.zig2
-rw-r--r--lib/std/fs/get_app_data_dir.zig4
-rw-r--r--lib/std/hash/xxhash.zig2
-rw-r--r--lib/std/json/stringify.zig135
-rw-r--r--lib/std/json/stringify_test.zig50
-rw-r--r--lib/std/math.zig24
-rw-r--r--lib/std/math/hypot.zig1
-rw-r--r--lib/std/math/nextafter.zig2
-rw-r--r--lib/std/os/linux.zig460
-rw-r--r--lib/std/os/linux/mips.zig123
-rw-r--r--lib/std/os/linux/mips64.zig122
-rw-r--r--lib/std/os/linux/sparc64.zig60
-rw-r--r--lib/std/unicode.zig1
-rw-r--r--lib/std/zig/AstGen.zig137
-rw-r--r--lib/std/zig/Server.zig21
-rw-r--r--lib/std/zig/Zir.zig20
-rw-r--r--lib/std/zig/system/darwin/macos.zig5
-rw-r--r--src/Air.zig25
-rw-r--r--src/Air/types_resolved.zig1
-rw-r--r--src/Compilation.zig184
-rw-r--r--src/InternPool.zig4
-rw-r--r--src/Liveness.zig2
-rw-r--r--src/Liveness/Verify.zig1
-rw-r--r--src/Sema.zig216
-rw-r--r--src/Type.zig2
-rw-r--r--src/Zcu.zig23
-rw-r--r--src/Zcu/PerThread.zig28
-rw-r--r--src/arch/aarch64/CodeGen.zig31
-rw-r--r--src/arch/arm/CodeGen.zig30
-rw-r--r--src/arch/riscv64/CodeGen.zig22
-rw-r--r--src/arch/riscv64/Emit.zig24
-rw-r--r--src/arch/sparc64/CodeGen.zig13
-rw-r--r--src/arch/wasm/CodeGen.zig32
-rw-r--r--src/arch/x86_64/CodeGen.zig537
-rw-r--r--src/arch/x86_64/Emit.zig274
-rw-r--r--src/arch/x86_64/Lower.zig113
-rw-r--r--src/arch/x86_64/Mir.zig96
-rw-r--r--src/arch/x86_64/bits.zig39
-rw-r--r--src/arch/x86_64/encoder.zig27
-rw-r--r--src/codegen/c.zig7
-rw-r--r--src/codegen/llvm.zig34
-rw-r--r--src/codegen/spirv.zig4
-rw-r--r--src/introspect.zig7
-rw-r--r--src/link.zig22
-rw-r--r--src/link/C.zig19
-rw-r--r--src/link/Coff.zig10
-rw-r--r--src/link/Coff/lld.zig4
-rw-r--r--src/link/Dwarf.zig1238
-rw-r--r--src/link/Elf.zig207
-rw-r--r--src/link/Elf/Atom.zig26
-rw-r--r--src/link/Elf/ZigObject.zig274
-rw-r--r--src/link/Elf/merge_section.zig34
-rw-r--r--src/link/Elf/relocatable.zig46
-rw-r--r--src/link/Elf/relocation.zig40
-rw-r--r--src/link/MachO.zig30
-rw-r--r--src/link/MachO/ZigObject.zig13
-rw-r--r--src/link/MachO/load_commands.zig4
-rw-r--r--src/link/MachO/thunks.zig29
-rw-r--r--src/link/NvPtx.zig5
-rw-r--r--src/link/Plan9.zig10
-rw-r--r--src/link/SpirV.zig7
-rw-r--r--src/link/Wasm.zig11
-rw-r--r--src/link/Wasm/ZigObject.zig2
-rw-r--r--src/main.zig131
-rw-r--r--src/print_air.zig10
-rw-r--r--src/register_manager.zig2
-rw-r--r--test/behavior/maximum_minimum.zig2
-rw-r--r--test/behavior/vector.zig1
-rw-r--r--test/incremental/delete_comptime_decls2
-rw-r--r--test/incremental/modify_inline_fn23
-rw-r--r--test/incremental/move_src29
-rw-r--r--test/link/elf.zig57
-rw-r--r--test/link/macho.zig27
-rw-r--r--test/src/Debugger.zig160
-rw-r--r--test/standalone/build.zig.zon17
-rw-r--r--test/standalone/emit_asm_no_bin/build.zig19
-rw-r--r--test/standalone/emit_asm_no_bin/main.zig1
-rw-r--r--test/standalone/emit_llvm_no_bin/build.zig (renamed from test/standalone/issue_12588/build.zig)0
-rw-r--r--test/standalone/emit_llvm_no_bin/main.zig (renamed from test/standalone/issue_12588/main.zig)0
-rw-r--r--test/tests.zig48
-rw-r--r--tools/incr-check.zig43
106 files changed, 3875 insertions, 2103 deletions
diff --git a/README.md b/README.md
index 7c4adbf82a..865bd178b3 100644
--- a/README.md
+++ b/README.md
@@ -76,21 +76,25 @@ This produces a `zig2` executable in the current working directory. This is a
[without LLVM extensions](https://github.com/ziglang/zig/issues/16270), and is
therefore lacking these features:
- Release mode optimizations
-- aarch64 machine code backend
-- `@cImport` / `zig translate-c`
-- Ability to compile C files
-- Ability to compile assembly files
+- [aarch64 machine code backend](https://github.com/ziglang/zig/issues/21172)
+- [@cImport](https://github.com/ziglang/zig/issues/20630)
+- [zig translate-c](https://github.com/ziglang/zig/issues/20875)
+- [Ability to compile assembly files](https://github.com/ziglang/zig/issues/21169)
- [Some ELF linking features](https://github.com/ziglang/zig/issues/17749)
- [Most COFF/PE linking features](https://github.com/ziglang/zig/issues/17751)
- [Some WebAssembly linking features](https://github.com/ziglang/zig/issues/17750)
- [Ability to create import libs from def files](https://github.com/ziglang/zig/issues/17807)
-- [Automatic importlib file generation for Windows DLLs](https://github.com/ziglang/zig/issues/17753)
- [Ability to create static archives from object files](https://github.com/ziglang/zig/issues/9828)
-- Ability to compile C++, Objective-C, and Objective-C++ files
+- Ability to compile C, C++, Objective-C, and Objective-C++ files
However, a compiler built this way does provide a C backend, which may be
useful for creating system packages of Zig projects using the system C
-toolchain. In such case, LLVM is not needed!
+toolchain. **In this case, LLVM is not needed!**
+
+Furthermore, a compiler built this way provides an LLVM backend that produces
+bitcode files, which may be compiled into object files via a system Clang
+package. This can be used to produce system packages of Zig applications
+without the Zig package dependency on LLVM.
## Contributing
diff --git a/ci/x86_64-linux-debug.sh b/ci/x86_64-linux-debug.sh
index 04431ba960..f4a4e0e13b 100755
--- a/ci/x86_64-linux-debug.sh
+++ b/ci/x86_64-linux-debug.sh
@@ -64,7 +64,7 @@ stage3-debug/bin/zig build \
stage3-debug/bin/zig build test docs \
--maxrss 21000000000 \
- -Dlldb=$HOME/deps/lldb-zig/Debug-f96d3e6fc/bin/lldb \
+ -Dlldb=$HOME/deps/lldb-zig/Debug-62538077d/bin/lldb \
-fqemu \
-fwasmtime \
-Dstatic-llvm \
diff --git a/ci/x86_64-linux-release.sh b/ci/x86_64-linux-release.sh
index 57f17bdc76..f9ebad2ade 100755
--- a/ci/x86_64-linux-release.sh
+++ b/ci/x86_64-linux-release.sh
@@ -64,7 +64,7 @@ stage3-release/bin/zig build \
stage3-release/bin/zig build test docs \
--maxrss 21000000000 \
- -Dlldb=$HOME/deps/lldb-zig/Release-f96d3e6fc/bin/lldb \
+ -Dlldb=$HOME/deps/lldb-zig/Release-62538077d/bin/lldb \
-fqemu \
-fwasmtime \
-Dstatic-llvm \
diff --git a/lib/compiler/aro/aro/Builtins/Builtin.zig b/lib/compiler/aro/aro/Builtins/Builtin.zig
index 9564bfecb5..c5cf98608b 100644
--- a/lib/compiler/aro/aro/Builtins/Builtin.zig
+++ b/lib/compiler/aro/aro/Builtins/Builtin.zig
@@ -5165,7 +5165,7 @@ const dafsa = [_]Node{
.{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 4913 },
};
pub const data = blk: {
- @setEvalBranchQuota(3986);
+ @setEvalBranchQuota(30_000);
break :blk [_]@This(){
// _Block_object_assign
.{ .tag = @enumFromInt(0), .properties = .{ .param_str = "vv*vC*iC", .header = .blocks, .attributes = .{ .lib_function_without_prefix = true } } },
diff --git a/lib/compiler/aro/aro/Parser.zig b/lib/compiler/aro/aro/Parser.zig
index 956dc5e114..1cb5e18934 100644
--- a/lib/compiler/aro/aro/Parser.zig
+++ b/lib/compiler/aro/aro/Parser.zig
@@ -4802,6 +4802,7 @@ const CallExpr = union(enum) {
}
fn shouldPromoteVarArg(self: CallExpr, arg_idx: u32) bool {
+ @setEvalBranchQuota(2000);
return switch (self) {
.standard => true,
.builtin => |builtin| switch (builtin.tag) {
@@ -4902,6 +4903,7 @@ const CallExpr = union(enum) {
}
fn returnType(self: CallExpr, p: *Parser, callable_ty: Type) Type {
+ @setEvalBranchQuota(6000);
return switch (self) {
.standard => callable_ty.returnType(),
.builtin => |builtin| switch (builtin.tag) {
diff --git a/lib/compiler/objcopy.zig b/lib/compiler/objcopy.zig
index f3360c8108..b48fb52e82 100644
--- a/lib/compiler/objcopy.zig
+++ b/lib/compiler/objcopy.zig
@@ -201,9 +201,10 @@ fn cmdObjCopy(
if (seen_update) fatal("zig objcopy only supports 1 update for now", .{});
seen_update = true;
- try server.serveEmitBinPath(output, .{
- .flags = .{ .cache_hit = false },
- });
+ // The build system already knows what the output is at this point, we
+ // only need to communicate that the process has finished.
+ // Use the empty error bundle to indicate that the update is done.
+ try server.serveErrorBundle(std.zig.ErrorBundle.empty);
},
else => fatal("unsupported message: {s}", .{@tagName(hdr.tag)}),
}
diff --git a/lib/std/Build.zig b/lib/std/Build.zig
index 03743cf52e..82810bb02f 100644
--- a/lib/std/Build.zig
+++ b/lib/std/Build.zig
@@ -2373,7 +2373,7 @@ pub const LazyPath = union(enum) {
// basis for not traversing up too many directories.
var file_path: Cache.Path = .{
- .root_dir = gen.file.step.owner.build_root,
+ .root_dir = Cache.Directory.cwd(),
.sub_path = gen.file.path orelse {
std.debug.lockStdErr();
const stderr = std.io.getStdErr();
diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig
index 1dafcf3bb7..1eabdd54e6 100644
--- a/lib/std/Build/Cache.zig
+++ b/lib/std/Build/Cache.zig
@@ -896,8 +896,8 @@ pub const Manifest = struct {
}
}
- /// Returns a hex encoded hash of the inputs.
- pub fn final(self: *Manifest) HexDigest {
+ /// Returns a binary hash of the inputs.
+ pub fn finalBin(self: *Manifest) BinDigest {
assert(self.manifest_file != null);
// We don't close the manifest file yet, because we want to
@@ -908,7 +908,12 @@ pub const Manifest = struct {
var bin_digest: BinDigest = undefined;
self.hash.hasher.final(&bin_digest);
+ return bin_digest;
+ }
+ /// Returns a hex encoded hash of the inputs.
+ pub fn final(self: *Manifest) HexDigest {
+ const bin_digest = self.finalBin();
return binToHex(bin_digest);
}
diff --git a/lib/std/Build/Fuzz.zig b/lib/std/Build/Fuzz.zig
index 9857db5a1f..23f8a02692 100644
--- a/lib/std/Build/Fuzz.zig
+++ b/lib/std/Build/Fuzz.zig
@@ -100,6 +100,15 @@ pub fn start(
}
fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) void {
+ rebuildTestsWorkerRunFallible(run, ttyconf, parent_prog_node) catch |err| {
+ const compile = run.producer.?;
+ log.err("step '{s}': failed to rebuild in fuzz mode: {s}", .{
+ compile.step.name, @errorName(err),
+ });
+ };
+}
+
+fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {
const gpa = run.step.owner.allocator;
const stderr = std.io.getStdErr();
@@ -121,14 +130,9 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog
const rebuilt_bin_path = result catch |err| switch (err) {
error.MakeFailed => return,
- else => {
- log.err("step '{s}': failed to rebuild in fuzz mode: {s}", .{
- compile.step.name, @errorName(err),
- });
- return;
- },
+ else => |other| return other,
};
- run.rebuilt_executable = rebuilt_bin_path;
+ run.rebuilt_executable = try rebuilt_bin_path.join(gpa, compile.out_filename);
}
fn fuzzWorkerRun(
diff --git a/lib/std/Build/Fuzz/WebServer.zig b/lib/std/Build/Fuzz/WebServer.zig
index 8534d95d16..fbf6b8dbce 100644
--- a/lib/std/Build/Fuzz/WebServer.zig
+++ b/lib/std/Build/Fuzz/WebServer.zig
@@ -8,6 +8,8 @@ const Coverage = std.debug.Coverage;
const abi = std.Build.Fuzz.abi;
const log = std.log;
const assert = std.debug.assert;
+const Cache = std.Build.Cache;
+const Path = Cache.Path;
const WebServer = @This();
@@ -31,6 +33,10 @@ coverage_mutex: std.Thread.Mutex,
/// Signaled when `coverage_files` changes.
coverage_condition: std.Thread.Condition,
+const fuzzer_bin_name = "fuzzer";
+const fuzzer_arch_os_abi = "wasm32-freestanding";
+const fuzzer_cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext";
+
const CoverageMap = struct {
mapped_memory: []align(std.mem.page_size) const u8,
coverage: Coverage,
@@ -181,9 +187,18 @@ fn serveWasm(
// Do the compilation every request, so that the user can edit the files
// and see the changes without restarting the server.
- const wasm_binary_path = try buildWasmBinary(ws, arena, optimize_mode);
+ const wasm_base_path = try buildWasmBinary(ws, arena, optimize_mode);
+ const bin_name = try std.zig.binNameAlloc(arena, .{
+ .root_name = fuzzer_bin_name,
+ .target = std.zig.system.resolveTargetQuery(std.Build.parseTargetQuery(.{
+ .arch_os_abi = fuzzer_arch_os_abi,
+ .cpu_features = fuzzer_cpu_features,
+ }) catch unreachable) catch unreachable,
+ .output_mode = .Exe,
+ });
// std.http.Server does not have a sendfile API yet.
- const file_contents = try std.fs.cwd().readFileAlloc(gpa, wasm_binary_path, 10 * 1024 * 1024);
+ const bin_path = try wasm_base_path.join(arena, bin_name);
+ const file_contents = try bin_path.root_dir.handle.readFileAlloc(gpa, bin_path.sub_path, 10 * 1024 * 1024);
defer gpa.free(file_contents);
try request.respond(file_contents, .{
.extra_headers = &.{
@@ -197,7 +212,7 @@ fn buildWasmBinary(
ws: *WebServer,
arena: Allocator,
optimize_mode: std.builtin.OptimizeMode,
-) ![]const u8 {
+) !Path {
const gpa = ws.gpa;
const main_src_path: Build.Cache.Path = .{
@@ -219,11 +234,11 @@ fn buildWasmBinary(
ws.zig_exe_path, "build-exe", //
"-fno-entry", //
"-O", @tagName(optimize_mode), //
- "-target", "wasm32-freestanding", //
- "-mcpu", "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext", //
+ "-target", fuzzer_arch_os_abi, //
+ "-mcpu", fuzzer_cpu_features, //
"--cache-dir", ws.global_cache_directory.path orelse ".", //
"--global-cache-dir", ws.global_cache_directory.path orelse ".", //
- "--name", "fuzzer", //
+ "--name", fuzzer_bin_name, //
"-rdynamic", //
"-fsingle-threaded", //
"--dep", "Walk", //
@@ -251,7 +266,7 @@ fn buildWasmBinary(
try sendMessage(child.stdin.?, .exit);
const Header = std.zig.Server.Message.Header;
- var result: ?[]const u8 = null;
+ var result: ?Path = null;
var result_error_bundle = std.zig.ErrorBundle.empty;
const stdout = poller.fifo(.stdout);
@@ -288,13 +303,17 @@ fn buildWasmBinary(
.extra = extra_array,
};
},
- .emit_bin_path => {
- const EbpHdr = std.zig.Server.Message.EmitBinPath;
+ .emit_digest => {
+ const EbpHdr = std.zig.Server.Message.EmitDigest;
const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
if (!ebp_hdr.flags.cache_hit) {
log.info("source changes detected; rebuilt wasm component", .{});
}
- result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);
+ const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
+ result = Path{
+ .root_dir = ws.global_cache_directory,
+ .sub_path = try arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*)),
+ };
},
else => {}, // ignore other messages
}
@@ -568,10 +587,7 @@ fn prepareTables(
};
errdefer gop.value_ptr.coverage.deinit(gpa);
- const rebuilt_exe_path: Build.Cache.Path = .{
- .root_dir = Build.Cache.Directory.cwd(),
- .sub_path = run_step.rebuilt_executable.?,
- };
+ const rebuilt_exe_path = run_step.rebuilt_executable.?;
var debug_info = std.debug.Info.load(gpa, rebuilt_exe_path, &gop.value_ptr.coverage) catch |err| {
log.err("step '{s}': failed to load debug information for '{}': {s}", .{
run_step.step.name, rebuilt_exe_path, @errorName(err),
diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig
index 47a6e49a82..346ab2c9b3 100644
--- a/lib/std/Build/Step.zig
+++ b/lib/std/Build/Step.zig
@@ -317,6 +317,8 @@ const Build = std.Build;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const builtin = @import("builtin");
+const Cache = Build.Cache;
+const Path = Cache.Path;
pub fn evalChildProcess(s: *Step, argv: []const []const u8) ![]u8 {
const run_result = try captureChildProcess(s, std.Progress.Node.none, argv);
@@ -373,7 +375,7 @@ pub fn evalZigProcess(
argv: []const []const u8,
prog_node: std.Progress.Node,
watch: bool,
-) !?[]const u8 {
+) !?Path {
if (s.getZigProcess()) |zp| update: {
assert(watch);
if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
@@ -477,7 +479,7 @@ pub fn evalZigProcess(
return result;
}
-fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {
+fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
const b = s.owner;
const arena = b.allocator;
@@ -487,7 +489,7 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {
if (!watch) try sendMessage(zp.child.stdin.?, .exit);
const Header = std.zig.Server.Message.Header;
- var result: ?[]const u8 = null;
+ var result: ?Path = null;
const stdout = zp.poller.fifo(.stdout);
@@ -531,16 +533,15 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {
break;
}
},
- .emit_bin_path => {
- const EbpHdr = std.zig.Server.Message.EmitBinPath;
+ .emit_digest => {
+ const EbpHdr = std.zig.Server.Message.EmitDigest;
const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
s.result_cached = ebp_hdr.flags.cache_hit;
- result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);
- if (watch) {
- // This message indicates the end of the update.
- stdout.discard(body.len);
- break;
- }
+ const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
+ result = Path{
+ .root_dir = b.cache_root,
+ .sub_path = try arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*)),
+ };
},
.file_system_inputs => {
s.clearWatchInputs();
diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig
index 054dda9e90..1aeebbb55b 100644
--- a/lib/std/Build/Step/Compile.zig
+++ b/lib/std/Build/Step/Compile.zig
@@ -17,6 +17,7 @@ const Module = std.Build.Module;
const InstallDir = std.Build.InstallDir;
const GeneratedFile = std.Build.GeneratedFile;
const Compile = @This();
+const Path = std.Build.Cache.Path;
pub const base_id: Step.Id = .compile;
@@ -1765,7 +1766,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const zig_args = try getZigArgs(compile, false);
- const maybe_output_bin_path = step.evalZigProcess(
+ const maybe_output_dir = step.evalZigProcess(
zig_args,
options.progress_node,
(b.graph.incremental == true) and options.watch,
@@ -1779,53 +1780,51 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
};
// Update generated files
- if (maybe_output_bin_path) |output_bin_path| {
- const output_dir = fs.path.dirname(output_bin_path).?;
-
+ if (maybe_output_dir) |output_dir| {
if (compile.emit_directory) |lp| {
- lp.path = output_dir;
+ lp.path = b.fmt("{}", .{output_dir});
}
// -femit-bin[=path] (default) Output machine code
if (compile.generated_bin) |bin| {
- bin.path = b.pathJoin(&.{ output_dir, compile.out_filename });
+ bin.path = output_dir.joinString(b.allocator, compile.out_filename) catch @panic("OOM");
}
- const sep = std.fs.path.sep;
+ const sep = std.fs.path.sep_str;
// output PDB if someone requested it
if (compile.generated_pdb) |pdb| {
- pdb.path = b.fmt("{s}{c}{s}.pdb", .{ output_dir, sep, compile.name });
+ pdb.path = b.fmt("{}" ++ sep ++ "{s}.pdb", .{ output_dir, compile.name });
}
// -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
if (compile.generated_implib) |implib| {
- implib.path = b.fmt("{s}{c}{s}.lib", .{ output_dir, sep, compile.name });
+ implib.path = b.fmt("{}" ++ sep ++ "{s}.lib", .{ output_dir, compile.name });
}
// -femit-h[=path] Generate a C header file (.h)
if (compile.generated_h) |lp| {
- lp.path = b.fmt("{s}{c}{s}.h", .{ output_dir, sep, compile.name });
+ lp.path = b.fmt("{}" ++ sep ++ "{s}.h", .{ output_dir, compile.name });
}
// -femit-docs[=path] Create a docs/ dir with html documentation
if (compile.generated_docs) |generated_docs| {
- generated_docs.path = b.pathJoin(&.{ output_dir, "docs" });
+ generated_docs.path = output_dir.joinString(b.allocator, "docs") catch @panic("OOM");
}
// -femit-asm[=path] Output .s (assembly code)
if (compile.generated_asm) |lp| {
- lp.path = b.fmt("{s}{c}{s}.s", .{ output_dir, sep, compile.name });
+ lp.path = b.fmt("{}" ++ sep ++ "{s}.s", .{ output_dir, compile.name });
}
// -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions)
if (compile.generated_llvm_ir) |lp| {
- lp.path = b.fmt("{s}{c}{s}.ll", .{ output_dir, sep, compile.name });
+ lp.path = b.fmt("{}" ++ sep ++ "{s}.ll", .{ output_dir, compile.name });
}
// -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions)
if (compile.generated_llvm_bc) |lp| {
- lp.path = b.fmt("{s}{c}{s}.bc", .{ output_dir, sep, compile.name });
+ lp.path = b.fmt("{}" ++ sep ++ "{s}.bc", .{ output_dir, compile.name });
}
}
@@ -1841,7 +1840,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
}
}
-pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) ![]const u8 {
+pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) !Path {
const gpa = c.step.owner.allocator;
c.step.result_error_msgs.clearRetainingCapacity();
diff --git a/lib/std/Build/Step/InstallArtifact.zig b/lib/std/Build/Step/InstallArtifact.zig
index 4e778d897c..3d404eb8ca 100644
--- a/lib/std/Build/Step/InstallArtifact.zig
+++ b/lib/std/Build/Step/InstallArtifact.zig
@@ -125,10 +125,10 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
if (install_artifact.dest_dir) |dest_dir| {
const full_dest_path = b.getInstallPath(dest_dir, install_artifact.dest_sub_path);
- const full_src_path = install_artifact.emitted_bin.?.getPath2(b, step);
- const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_dest_path, .{}) catch |err| {
+ const src_path = install_artifact.emitted_bin.?.getPath3(b, step);
+ const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_dest_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
- full_src_path, full_dest_path, @errorName(err),
+ src_path.sub_path, full_dest_path, @errorName(err),
});
};
all_cached = all_cached and p == .fresh;
@@ -141,22 +141,22 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
}
if (install_artifact.implib_dir) |implib_dir| {
- const full_src_path = install_artifact.emitted_implib.?.getPath2(b, step);
- const full_implib_path = b.getInstallPath(implib_dir, fs.path.basename(full_src_path));
- const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_implib_path, .{}) catch |err| {
+ const src_path = install_artifact.emitted_implib.?.getPath3(b, step);
+ const full_implib_path = b.getInstallPath(implib_dir, fs.path.basename(src_path.sub_path));
+ const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_implib_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
- full_src_path, full_implib_path, @errorName(err),
+ src_path.sub_path, full_implib_path, @errorName(err),
});
};
all_cached = all_cached and p == .fresh;
}
if (install_artifact.pdb_dir) |pdb_dir| {
- const full_src_path = install_artifact.emitted_pdb.?.getPath2(b, step);
- const full_pdb_path = b.getInstallPath(pdb_dir, fs.path.basename(full_src_path));
- const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_pdb_path, .{}) catch |err| {
+ const src_path = install_artifact.emitted_pdb.?.getPath3(b, step);
+ const full_pdb_path = b.getInstallPath(pdb_dir, fs.path.basename(src_path.sub_path));
+ const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_pdb_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
- full_src_path, full_pdb_path, @errorName(err),
+ src_path.sub_path, full_pdb_path, @errorName(err),
});
};
all_cached = all_cached and p == .fresh;
@@ -164,11 +164,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
if (install_artifact.h_dir) |h_dir| {
if (install_artifact.emitted_h) |emitted_h| {
- const full_src_path = emitted_h.getPath2(b, step);
- const full_h_path = b.getInstallPath(h_dir, fs.path.basename(full_src_path));
- const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| {
+ const src_path = emitted_h.getPath3(b, step);
+ const full_h_path = b.getInstallPath(h_dir, fs.path.basename(src_path.sub_path));
+ const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_h_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
- full_src_path, full_h_path, @errorName(err),
+ src_path.sub_path, full_h_path, @errorName(err),
});
};
all_cached = all_cached and p == .fresh;
@@ -176,22 +176,22 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
for (install_artifact.artifact.installed_headers.items) |installation| switch (installation) {
.file => |file| {
- const full_src_path = file.source.getPath2(b, step);
+ const src_path = file.source.getPath3(b, step);
const full_h_path = b.getInstallPath(h_dir, file.dest_rel_path);
- const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| {
+ const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_h_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
- full_src_path, full_h_path, @errorName(err),
+ src_path.sub_path, full_h_path, @errorName(err),
});
};
all_cached = all_cached and p == .fresh;
},
.directory => |dir| {
- const full_src_dir_path = dir.source.getPath2(b, step);
+ const src_dir_path = dir.source.getPath3(b, step);
const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path);
- var src_dir = b.build_root.handle.openDir(full_src_dir_path, .{ .iterate = true }) catch |err| {
+ var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.sub_path, .{ .iterate = true }) catch |err| {
return step.fail("unable to open source directory '{s}': {s}", .{
- full_src_dir_path, @errorName(err),
+ src_dir_path.sub_path, @errorName(err),
});
};
defer src_dir.close();
@@ -208,14 +208,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
continue :next_entry;
}
}
- const full_src_entry_path = b.pathJoin(&.{ full_src_dir_path, entry.path });
+
+ const src_entry_path = src_dir_path.join(b.allocator, entry.path) catch @panic("OOM");
const full_dest_path = b.pathJoin(&.{ full_h_prefix, entry.path });
switch (entry.kind) {
.directory => try cwd.makePath(full_dest_path),
.file => {
- const p = fs.Dir.updateFile(cwd, full_src_entry_path, cwd, full_dest_path, .{}) catch |err| {
+ const p = fs.Dir.updateFile(src_entry_path.root_dir.handle, src_entry_path.sub_path, cwd, full_dest_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
- full_src_entry_path, full_dest_path, @errorName(err),
+ src_entry_path.sub_path, full_dest_path, @errorName(err),
});
};
all_cached = all_cached and p == .fresh;
diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig
index 5d9ebce9aa..0c011e25ed 100644
--- a/lib/std/Build/Step/Run.zig
+++ b/lib/std/Build/Step/Run.zig
@@ -7,6 +7,7 @@ const mem = std.mem;
const process = std.process;
const EnvMap = process.EnvMap;
const assert = std.debug.assert;
+const Path = Build.Cache.Path;
const Run = @This();
@@ -93,7 +94,7 @@ cached_test_metadata: ?CachedTestMetadata = null,
/// Populated during the fuzz phase if this run step corresponds to a unit test
/// executable that contains fuzz tests.
-rebuilt_executable: ?[]const u8,
+rebuilt_executable: ?Path,
/// If this Run step was produced by a Compile step, it is tracked here.
producer: ?*Step.Compile,
@@ -872,7 +873,7 @@ pub fn rerunInFuzzMode(
.artifact => |pa| {
const artifact = pa.artifact;
const file_path = if (artifact == run.producer.?)
- run.rebuilt_executable.?
+ b.fmt("{}", .{run.rebuilt_executable.?})
else
(artifact.installed_path orelse artifact.generated_bin.?.path.?);
try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));
diff --git a/lib/std/Build/Step/TranslateC.zig b/lib/std/Build/Step/TranslateC.zig
index ac4729abd0..9ef5f7acdf 100644
--- a/lib/std/Build/Step/TranslateC.zig
+++ b/lib/std/Build/Step/TranslateC.zig
@@ -29,7 +29,7 @@ pub const Options = struct {
pub fn create(owner: *std.Build, options: Options) *TranslateC {
const translate_c = owner.allocator.create(TranslateC) catch @panic("OOM");
const source = options.root_source_file.dupe(owner);
- translate_c.* = TranslateC{
+ translate_c.* = .{
.step = Step.init(.{
.id = base_id,
.name = "translate-c",
@@ -42,7 +42,7 @@ pub fn create(owner: *std.Build, options: Options) *TranslateC {
.out_basename = undefined,
.target = options.target,
.optimize = options.optimize,
- .output_file = std.Build.GeneratedFile{ .step = &translate_c.step },
+ .output_file = .{ .step = &translate_c.step },
.link_libc = options.link_libc,
.use_clang = options.use_clang,
};
@@ -89,6 +89,9 @@ pub fn addModule(translate_c: *TranslateC, name: []const u8) *std.Build.Module {
pub fn createModule(translate_c: *TranslateC) *std.Build.Module {
return translate_c.step.owner.createModule(.{
.root_source_file = translate_c.getOutput(),
+ .target = translate_c.target,
+ .optimize = translate_c.optimize,
+ .link_libc = translate_c.link_libc,
});
}
@@ -153,12 +156,12 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
try argv_list.append(c_macro);
}
- try argv_list.append(translate_c.source.getPath2(b, step));
+ const c_source_path = translate_c.source.getPath2(b, step);
+ try argv_list.append(c_source_path);
- const output_path = try step.evalZigProcess(argv_list.items, prog_node, false);
+ const output_dir = try step.evalZigProcess(argv_list.items, prog_node, false);
- translate_c.out_basename = fs.path.basename(output_path.?);
- const output_dir = fs.path.dirname(output_path.?).?;
-
- translate_c.output_file.path = b.pathJoin(&.{ output_dir, translate_c.out_basename });
+ const basename = std.fs.path.stem(std.fs.path.basename(c_source_path));
+ translate_c.out_basename = b.fmt("{s}.zig", .{basename});
+ translate_c.output_file.path = output_dir.?.joinString(b.allocator, translate_c.out_basename) catch @panic("OOM");
}
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 92d36dd135..d430cf6a83 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -2722,7 +2722,39 @@ pub const SYS = switch (native_os) {
};
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
pub const Sigaction = switch (native_os) {
- .linux => linux.Sigaction,
+ .linux => switch (native_arch) {
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ => if (builtin.target.isMusl())
+ linux.Sigaction
+ else if (builtin.target.ptrBitWidth() == 64) extern struct {
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+
+ flags: c_uint,
+ handler: extern union {
+ handler: ?handler_fn,
+ sigaction: ?sigaction_fn,
+ },
+ mask: sigset_t,
+ restorer: ?*const fn () callconv(.C) void = null,
+ } else extern struct {
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+
+ flags: c_uint,
+ handler: extern union {
+ handler: ?handler_fn,
+ sigaction: ?sigaction_fn,
+ },
+ mask: sigset_t,
+ restorer: ?*const fn () callconv(.C) void = null,
+ __resv: [1]c_int = .{0},
+ },
+ else => linux.Sigaction,
+ },
.emscripten => emscripten.Sigaction,
.netbsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {
pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
@@ -6326,16 +6358,46 @@ pub const Stat = switch (native_os) {
return self.ctim;
}
},
- .mips, .mipsel => extern struct {
+ .mips, .mipsel => if (builtin.target.isMusl()) extern struct {
dev: dev_t,
- __pad0: [2]u32,
+ __pad0: [2]i32,
ino: ino_t,
mode: mode_t,
nlink: nlink_t,
uid: uid_t,
gid: gid_t,
rdev: dev_t,
- __pad1: [2]u32,
+ __pad1: [2]i32,
+ size: off_t,
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ blksize: blksize_t,
+ __pad3: i32,
+ blocks: blkcnt_t,
+ __pad4: [14]i32,
+
+ pub fn atime(self: @This()) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: @This()) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: @This()) timespec {
+ return self.ctim;
+ }
+ } else extern struct {
+ dev: dev_t,
+ __pad0: [3]u32,
+ ino: ino_t,
+ mode: mode_t,
+ nlink: nlink_t,
+ uid: uid_t,
+ gid: gid_t,
+ rdev: dev_t,
+ __pad1: [3]u32,
size: off_t,
atim: timespec,
mtim: timespec,
@@ -6357,6 +6419,68 @@ pub const Stat = switch (native_os) {
return self.ctim;
}
},
+ .mips64, .mips64el => if (builtin.target.isMusl()) extern struct {
+ dev: dev_t,
+ __pad0: [3]i32,
+ ino: ino_t,
+ mode: mode_t,
+ nlink: nlink_t,
+ uid: uid_t,
+ gid: gid_t,
+ rdev: dev_t,
+ __pad1: [2]u32,
+ size: off_t,
+ __pad2: i32,
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ blksize: blksize_t,
+ __pad3: u32,
+ blocks: blkcnt_t,
+ __pad4: [14]i32,
+
+ pub fn atime(self: @This()) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: @This()) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: @This()) timespec {
+ return self.ctim;
+ }
+ } else extern struct {
+ dev: dev_t,
+ __pad0: [3]u32,
+ ino: ino_t,
+ mode: mode_t,
+ nlink: nlink_t,
+ uid: uid_t,
+ gid: gid_t,
+ rdev: dev_t,
+ __pad1: [3]u32,
+ size: off_t,
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ blksize: blksize_t,
+ __pad3: u32,
+ blocks: blkcnt_t,
+ __pad4: [14]i32,
+
+ pub fn atime(self: @This()) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: @This()) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: @This()) timespec {
+ return self.ctim;
+ }
+ },
else => std.os.linux.Stat, // libc stat is the same as kernel stat.
},
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index 1e184e4e8e..3e2cf53b60 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -1156,6 +1156,11 @@ pub const CPUFAMILY = enum(u32) {
ARM_FIRESTORM_ICESTORM = 0x1b588bb3,
ARM_BLIZZARD_AVALANCHE = 0xda33d83d,
ARM_EVEREST_SAWTOOTH = 0x8765edea,
+ ARM_COLL = 0x2876f5b5,
+ ARM_IBIZA = 0xfa33415e,
+ ARM_LOBOS = 0x5f4dea93,
+ ARM_PALMA = 0x72015832,
+ ARM_DONAN = 0x6f5129ac,
_,
};
diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig
index 186f287fdd..aa524fa2c2 100644
--- a/lib/std/crypto.zig
+++ b/lib/std/crypto.zig
@@ -74,8 +74,9 @@ pub const dh = struct {
/// Key Encapsulation Mechanisms.
pub const kem = struct {
- pub const kyber_d00 = @import("crypto/ml_kem.zig").kyber_d00;
- pub const ml_kem_01 = @import("crypto/ml_kem.zig").ml_kem_01;
+ pub const kyber_d00 = @import("crypto/ml_kem.zig").d00;
+ pub const ml_kem = @import("crypto/ml_kem.zig").nist;
+ pub const ml_kem_01 = @compileError("deprecated: final version of the specification has been published, use ml_kem instead");
};
/// Elliptic-curve arithmetic.
diff --git a/lib/std/crypto/aes/soft.zig b/lib/std/crypto/aes/soft.zig
index 9e7af0606d..fd0dfaf001 100644
--- a/lib/std/crypto/aes/soft.zig
+++ b/lib/std/crypto/aes/soft.zig
@@ -629,6 +629,8 @@ fn generateSbox(invert: bool) [256]u8 {
// Generate lookup tables.
fn generateTable(invert: bool) [4][256]u32 {
+ @setEvalBranchQuota(50000);
+
var table: [4][256]u32 = undefined;
for (generateSbox(invert), 0..) |value, index| {
diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig
index 255011de87..1a285080b5 100644
--- a/lib/std/crypto/blake2.zig
+++ b/lib/std/crypto/blake2.zig
@@ -786,7 +786,7 @@ test "blake2b384 streaming" {
test "comptime blake2b384" {
comptime {
- @setEvalBranchQuota(10000);
+ @setEvalBranchQuota(20000);
var block = [_]u8{0} ** Blake2b384.block_length;
var out: [Blake2b384.digest_length]u8 = undefined;
@@ -878,7 +878,7 @@ test "blake2b512 keyed" {
test "comptime blake2b512" {
comptime {
- @setEvalBranchQuota(10000);
+ @setEvalBranchQuota(12000);
var block = [_]u8{0} ** Blake2b512.block_length;
var out: [Blake2b512.digest_length]u8 = undefined;
diff --git a/lib/std/crypto/ml_kem.zig b/lib/std/crypto/ml_kem.zig
index 00eade1c71..9a3a35492c 100644
--- a/lib/std/crypto/ml_kem.zig
+++ b/lib/std/crypto/ml_kem.zig
@@ -1,15 +1,8 @@
//! Implementation of the IND-CCA2 post-quantum secure key encapsulation mechanism (KEM)
//! ML-KEM (NIST FIPS-203 publication) and CRYSTALS-Kyber (v3.02/"draft00" CFRG draft).
//!
-//! The schemes are not finalized yet, and are still subject to breaking changes.
-//!
-//! The Kyber namespace suffix (currently `_d00`) refers to the version currently
-//! implemented, in accordance with the draft.
-//! The ML-KEM namespace suffix (currently `_01`) refers to the NIST FIPS-203 draft
-//! published on August 24, 2023, with the unintentional transposition of  having been reverted.
-//!
-//! Suffixes may not be updated if new versions of the documents only include editorial changes.
-//! The suffixes will be removed once the schemes are finalized.
+//! The namespace `d00` refers to the version currently implemented, in accordance with the CFRG draft.
+//! The `nist` namespace refers to the FIPS-203 publication.
//!
//! Quoting from the CFRG I-D:
//!
@@ -148,7 +141,7 @@ const Params = struct {
dv: u8,
};
-pub const kyber_d00 = struct {
+pub const d00 = struct {
pub const Kyber512 = Kyber(.{
.name = "Kyber512",
.k = 2,
@@ -174,7 +167,7 @@ pub const kyber_d00 = struct {
});
};
-pub const ml_kem_01 = struct {
+pub const nist = struct {
pub const MLKem512 = Kyber(.{
.name = "ML-KEM-512",
.ml_kem = true,
@@ -204,12 +197,12 @@ pub const ml_kem_01 = struct {
};
const modes = [_]type{
- kyber_d00.Kyber512,
- kyber_d00.Kyber768,
- kyber_d00.Kyber1024,
- ml_kem_01.MLKem512,
- ml_kem_01.MLKem768,
- ml_kem_01.MLKem1024,
+ d00.Kyber512,
+ d00.Kyber768,
+ d00.Kyber1024,
+ nist.MLKem512,
+ nist.MLKem768,
+ nist.MLKem1024,
};
const h_length: usize = 32;
const inner_seed_length: usize = 32;
@@ -505,7 +498,10 @@ fn Kyber(comptime p: Params) type {
// Derives inner PKE keypair from given seed.
fn innerKeyFromSeed(seed: [inner_seed_length]u8, pk: *InnerPk, sk: *InnerSk) void {
var expanded_seed: [64]u8 = undefined;
- sha3.Sha3_512.hash(&seed, &expanded_seed, .{});
+ var h = sha3.Sha3_512.init(.{});
+ if (p.ml_kem) h.update(&[1]u8{p.k});
+ h.update(&seed);
+ h.final(&expanded_seed);
pk.rho = expanded_seed[0..32].*;
const sigma = expanded_seed[32..64];
pk.aT = M.uniform(pk.rho, false); // Expand ρ to A; we'll transpose later on
@@ -1722,9 +1718,9 @@ const sha2 = crypto.hash.sha2;
test "NIST KAT test" {
inline for (.{
- .{ kyber_d00.Kyber512, "e9c2bd37133fcb40772f81559f14b1f58dccd1c816701be9ba6214d43baf4547" },
- .{ kyber_d00.Kyber1024, "89248f2f33f7f4f7051729111f3049c409a933ec904aedadf035f30fa5646cd5" },
- .{ kyber_d00.Kyber768, "a1e122cad3c24bc51622e4c242d8b8acbcd3f618fee4220400605ca8f9ea02c2" },
+ .{ d00.Kyber512, "e9c2bd37133fcb40772f81559f14b1f58dccd1c816701be9ba6214d43baf4547" },
+ .{ d00.Kyber1024, "89248f2f33f7f4f7051729111f3049c409a933ec904aedadf035f30fa5646cd5" },
+ .{ d00.Kyber768, "a1e122cad3c24bc51622e4c242d8b8acbcd3f618fee4220400605ca8f9ea02c2" },
}) |modeHash| {
const mode = modeHash[0];
var seed: [48]u8 = undefined;
diff --git a/lib/std/crypto/pcurves/p384.zig b/lib/std/crypto/pcurves/p384.zig
index f8c5713209..3ab95da5e8 100644
--- a/lib/std/crypto/pcurves/p384.zig
+++ b/lib/std/crypto/pcurves/p384.zig
@@ -393,7 +393,7 @@ pub const P384 = struct {
}
const basePointPc = pc: {
- @setEvalBranchQuota(50000);
+ @setEvalBranchQuota(70000);
break :pc precompute(P384.basePoint, 15);
};
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 08ee3b7cde..826978abe4 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -56,6 +56,8 @@ pub const sys_can_stack_trace = switch (builtin.cpu.arch) {
// TODO: Make this work.
.mips,
.mipsel,
+ .mips64,
+ .mips64el,
=> false,
// `@returnAddress()` in LLVM 10 gives
diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig
index fb72316675..7cce30df38 100644
--- a/lib/std/debug/Dwarf.zig
+++ b/lib/std/debug/Dwarf.zig
@@ -2275,9 +2275,11 @@ pub const ElfModule = struct {
break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk;
}
if (std.posix.getenv("XDG_CACHE_HOME")) |cache_path| {
- const path = std.fs.path.join(gpa, &[_][]const u8{ cache_path, "debuginfod_client" }) catch break :blk;
- defer gpa.free(path);
- break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk;
+ if (cache_path.len > 0) {
+ const path = std.fs.path.join(gpa, &[_][]const u8{ cache_path, "debuginfod_client" }) catch break :blk;
+ defer gpa.free(path);
+ break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk;
+ }
}
if (std.posix.getenv("HOME")) |home_path| {
const path = std.fs.path.join(gpa, &[_][]const u8{ home_path, ".cache", "debuginfod_client" }) catch break :blk;
diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig
index f836d75ae0..b17533ebf8 100644
--- a/lib/std/dwarf.zig
+++ b/lib/std/dwarf.zig
@@ -89,6 +89,7 @@ pub const LNS = struct {
};
pub const LNE = struct {
+ pub const padding = 0x00;
pub const end_sequence = 0x01;
pub const set_address = 0x02;
pub const define_file = 0x03;
diff --git a/lib/std/enums.zig b/lib/std/enums.zig
index aea194683d..1cc7bde8d2 100644
--- a/lib/std/enums.zig
+++ b/lib/std/enums.zig
@@ -6,7 +6,7 @@ const testing = std.testing;
const EnumField = std.builtin.Type.EnumField;
/// Increment this value when adding APIs that add single backwards branches.
-const eval_branch_quota_cushion = 5;
+const eval_branch_quota_cushion = 10;
/// Returns a struct with a field matching each unique named enum element.
/// If the enum is extern and has multiple names for the same value, only
diff --git a/lib/std/fs/get_app_data_dir.zig b/lib/std/fs/get_app_data_dir.zig
index a05a431648..cce99ea8cc 100644
--- a/lib/std/fs/get_app_data_dir.zig
+++ b/lib/std/fs/get_app_data_dir.zig
@@ -32,7 +32,9 @@ pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDi
},
.linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris, .illumos => {
if (posix.getenv("XDG_DATA_HOME")) |xdg| {
- return fs.path.join(allocator, &[_][]const u8{ xdg, appname });
+ if (xdg.len > 0) {
+ return fs.path.join(allocator, &[_][]const u8{ xdg, appname });
+ }
}
const home_dir = posix.getenv("HOME") orelse {
diff --git a/lib/std/hash/xxhash.zig b/lib/std/hash/xxhash.zig
index 88ec3ba372..1d7c8399fc 100644
--- a/lib/std/hash/xxhash.zig
+++ b/lib/std/hash/xxhash.zig
@@ -890,7 +890,7 @@ test "xxhash32 smhasher" {
}
};
try Test.do();
- @setEvalBranchQuota(75000);
+ @setEvalBranchQuota(85000);
comptime try Test.do();
}
diff --git a/lib/std/json/stringify.zig b/lib/std/json/stringify.zig
index 6a8efb7e0e..965b7c3113 100644
--- a/lib/std/json/stringify.zig
+++ b/lib/std/json/stringify.zig
@@ -156,36 +156,23 @@ pub fn writeStreamArbitraryDepth(
/// | <array>
/// | write
/// | print
+/// | <writeRawStream>
/// <object> = beginObject ( <field> <value> )* endObject
-/// <field> = objectField | objectFieldRaw
+/// <field> = objectField | objectFieldRaw | <objectFieldRawStream>
/// <array> = beginArray ( <value> )* endArray
+/// <writeRawStream> = beginWriteRaw ( stream.writeAll )* endWriteRaw
+/// <objectFieldRawStream> = beginObjectFieldRaw ( stream.writeAll )* endObjectFieldRaw
/// ```
///
-/// Supported types:
-/// * Zig `bool` -> JSON `true` or `false`.
-/// * Zig `?T` -> `null` or the rendering of `T`.
-/// * Zig `i32`, `u64`, etc. -> JSON number or string.
-/// * When option `emit_nonportable_numbers_as_strings` is true, if the value is outside the range `+-1<<53` (the precise integer range of f64), it is rendered as a JSON string in base 10. Otherwise, it is rendered as JSON number.
-/// * Zig floats -> JSON number or string.
-/// * If the value cannot be precisely represented by an f64, it is rendered as a JSON string. Otherwise, it is rendered as JSON number.
-/// * TODO: Float rendering will likely change in the future, e.g. to remove the unnecessary "e+00".
-/// * Zig `[]const u8`, `[]u8`, `*[N]u8`, `@Vector(N, u8)`, and similar -> JSON string.
-/// * See `StringifyOptions.emit_strings_as_arrays`.
-/// * If the content is not valid UTF-8, rendered as an array of numbers instead.
-/// * Zig `[]T`, `[N]T`, `*[N]T`, `@Vector(N, T)`, and similar -> JSON array of the rendering of each item.
-/// * Zig tuple -> JSON array of the rendering of each item.
-/// * Zig `struct` -> JSON object with each field in declaration order.
-/// * If the struct declares a method `pub fn jsonStringify(self: *@This(), jw: anytype) !void`, it is called to do the serialization instead of the default behavior. The given `jw` is a pointer to this `WriteStream`. See `std.json.Value` for an example.
-/// * See `StringifyOptions.emit_null_optional_fields`.
-/// * Zig `union(enum)` -> JSON object with one field named for the active tag and a value representing the payload.
-/// * If the payload is `void`, then the emitted value is `{}`.
-/// * If the union declares a method `pub fn jsonStringify(self: *@This(), jw: anytype) !void`, it is called to do the serialization instead of the default behavior. The given `jw` is a pointer to this `WriteStream`.
-/// * Zig `enum` -> JSON string naming the active tag.
-/// * If the enum declares a method `pub fn jsonStringify(self: *@This(), jw: anytype) !void`, it is called to do the serialization instead of the default behavior. The given `jw` is a pointer to this `WriteStream`.
-/// * Zig untyped enum literal -> JSON string naming the active tag.
-/// * Zig error -> JSON string naming the error.
-/// * Zig `*T` -> the rendering of `T`. Note there is no guard against circular-reference infinite recursion.
-///
+/// The `safety_checks_hint` parameter determines how much memory is used to enable assertions that the above grammar is being followed,
+/// e.g. tripping an assertion rather than allowing `endObject` to emit the final `}` in `[[[]]}`.
+/// "Depth" in this context means the depth of nested `[]` or `{}` expressions
+/// (or equivalently the amount of recursion on the `<value>` grammar expression above).
+/// For example, emitting the JSON `[[[]]]` requires a depth of 3.
+/// If `.checked_to_fixed_depth` is used, there is additionally an assertion that the nesting depth never exceeds the given limit.
+/// `.checked_to_arbitrary_depth` requires a runtime allocator for the memory.
+/// `.checked_to_fixed_depth` embeds the storage required in the `WriteStream` struct.
+/// `.assumed_correct` requires no space and performs none of these assertions.
/// In `ReleaseFast` and `ReleaseSmall` mode, the given `safety_checks_hint` is ignored and is always treated as `.assumed_correct`.
pub fn WriteStream(
comptime OutStream: type,
@@ -197,10 +184,14 @@ pub fn WriteStream(
) type {
return struct {
const Self = @This();
- const safety_checks: @TypeOf(safety_checks_hint) = switch (@import("builtin").mode) {
- .Debug, .ReleaseSafe => safety_checks_hint,
- .ReleaseFast, .ReleaseSmall => .assumed_correct,
+ const build_mode_has_safety = switch (@import("builtin").mode) {
+ .Debug, .ReleaseSafe => true,
+ .ReleaseFast, .ReleaseSmall => false,
};
+ const safety_checks: @TypeOf(safety_checks_hint) = if (build_mode_has_safety)
+ safety_checks_hint
+ else
+ .assumed_correct;
pub const Stream = OutStream;
pub const Error = switch (safety_checks) {
@@ -225,6 +216,11 @@ pub fn WriteStream(
.assumed_correct => void,
},
+ raw_streaming_mode: if (build_mode_has_safety)
+ enum { none, value, objectField }
+ else
+ void = if (build_mode_has_safety) .none else {},
+
pub fn init(safety_allocator: Allocator, stream: OutStream, options: StringifyOptions) Self {
return .{
.options = options,
@@ -237,6 +233,7 @@ pub fn WriteStream(
};
}
+ /// Only necessary with .checked_to_arbitrary_depth.
pub fn deinit(self: *Self) void {
switch (safety_checks) {
.checked_to_arbitrary_depth => self.nesting_stack.deinit(),
@@ -246,6 +243,7 @@ pub fn WriteStream(
}
pub fn beginArray(self: *Self) Error!void {
+ if (build_mode_has_safety) assert(self.raw_streaming_mode == .none);
try self.valueStart();
try self.stream.writeByte('[');
try self.pushIndentation(ARRAY_MODE);
@@ -253,6 +251,7 @@ pub fn WriteStream(
}
pub fn beginObject(self: *Self) Error!void {
+ if (build_mode_has_safety) assert(self.raw_streaming_mode == .none);
try self.valueStart();
try self.stream.writeByte('{');
try self.pushIndentation(OBJECT_MODE);
@@ -260,6 +259,7 @@ pub fn WriteStream(
}
pub fn endArray(self: *Self) Error!void {
+ if (build_mode_has_safety) assert(self.raw_streaming_mode == .none);
self.popIndentation(ARRAY_MODE);
switch (self.next_punctuation) {
.none => {},
@@ -273,6 +273,7 @@ pub fn WriteStream(
}
pub fn endObject(self: *Self) Error!void {
+ if (build_mode_has_safety) assert(self.raw_streaming_mode == .none);
self.popIndentation(OBJECT_MODE);
switch (self.next_punctuation) {
.none => {},
@@ -389,16 +390,39 @@ pub fn WriteStream(
/// e.g. `"1"`, `"[]"`, `"[1,2]"`, not `"1,2"`.
/// This function may be useful for doing your own number formatting.
pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) Error!void {
+ if (build_mode_has_safety) assert(self.raw_streaming_mode == .none);
try self.valueStart();
try self.stream.print(fmt, args);
self.valueDone();
}
+ /// An alternative to calling `write` that allows you to write directly to the `.stream` field, e.g. with `.stream.writeAll()`.
+ /// Call `beginWriteRaw()`, then write a complete value (including any quotes if necessary) directly to the `.stream` field,
+ /// then call `endWriteRaw()`.
+ /// This can be useful for streaming very long strings into the output without needing it all buffered in memory.
+ pub fn beginWriteRaw(self: *Self) !void {
+ if (build_mode_has_safety) {
+ assert(self.raw_streaming_mode == .none);
+ self.raw_streaming_mode = .value;
+ }
+ try self.valueStart();
+ }
+
+ /// See `beginWriteRaw`.
+ pub fn endWriteRaw(self: *Self) void {
+ if (build_mode_has_safety) {
+ assert(self.raw_streaming_mode == .value);
+ self.raw_streaming_mode = .none;
+ }
+ self.valueDone();
+ }
+
/// See `WriteStream` for when to call this method.
/// `key` is the string content of the property name.
/// Surrounding quotes will be added and any special characters will be escaped.
/// See also `objectFieldRaw`.
pub fn objectField(self: *Self, key: []const u8) Error!void {
+ if (build_mode_has_safety) assert(self.raw_streaming_mode == .none);
try self.objectFieldStart();
try encodeJsonString(key, self.options, self.stream);
self.next_punctuation = .colon;
@@ -408,14 +432,65 @@ pub fn WriteStream(
/// A few assertions are performed on the given value to ensure that the caller of this function understands the API contract.
/// See also `objectField`.
pub fn objectFieldRaw(self: *Self, quoted_key: []const u8) Error!void {
+ if (build_mode_has_safety) assert(self.raw_streaming_mode == .none);
assert(quoted_key.len >= 2 and quoted_key[0] == '"' and quoted_key[quoted_key.len - 1] == '"'); // quoted_key should be "quoted".
try self.objectFieldStart();
try self.stream.writeAll(quoted_key);
self.next_punctuation = .colon;
}
- /// See `WriteStream`.
+ /// In the rare case that you need to write very long object field names,
+ /// this is an alternative to `objectField` and `objectFieldRaw` that allows you to write directly to the `.stream` field
+ /// similar to `beginWriteRaw`.
+ /// Call `endObjectFieldRaw()` when you're done.
+ pub fn beginObjectFieldRaw(self: *Self) !void {
+ if (build_mode_has_safety) {
+ assert(self.raw_streaming_mode == .none);
+ self.raw_streaming_mode = .objectField;
+ }
+ try self.objectFieldStart();
+ }
+
+ /// See `beginObjectFieldRaw`.
+ pub fn endObjectFieldRaw(self: *Self) void {
+ if (build_mode_has_safety) {
+ assert(self.raw_streaming_mode == .objectField);
+ self.raw_streaming_mode = .none;
+ }
+ self.next_punctuation = .colon;
+ }
+
+ /// Renders the given Zig value as JSON.
+ ///
+ /// Supported types:
+ /// * Zig `bool` -> JSON `true` or `false`.
+ /// * Zig `?T` -> `null` or the rendering of `T`.
+ /// * Zig `i32`, `u64`, etc. -> JSON number or string.
+ /// * When option `emit_nonportable_numbers_as_strings` is true, if the value is outside the range `+-1<<53` (the precise integer range of f64), it is rendered as a JSON string in base 10. Otherwise, it is rendered as JSON number.
+ /// * Zig floats -> JSON number or string.
+ /// * If the value cannot be precisely represented by an f64, it is rendered as a JSON string. Otherwise, it is rendered as JSON number.
+ /// * TODO: Float rendering will likely change in the future, e.g. to remove the unnecessary "e+00".
+ /// * Zig `[]const u8`, `[]u8`, `*[N]u8`, `@Vector(N, u8)`, and similar -> JSON string.
+ /// * See `StringifyOptions.emit_strings_as_arrays`.
+ /// * If the content is not valid UTF-8, rendered as an array of numbers instead.
+ /// * Zig `[]T`, `[N]T`, `*[N]T`, `@Vector(N, T)`, and similar -> JSON array of the rendering of each item.
+ /// * Zig tuple -> JSON array of the rendering of each item.
+ /// * Zig `struct` -> JSON object with each field in declaration order.
+ /// * If the struct declares a method `pub fn jsonStringify(self: *@This(), jw: anytype) !void`, it is called to do the serialization instead of the default behavior. The given `jw` is a pointer to this `WriteStream`. See `std.json.Value` for an example.
+ /// * See `StringifyOptions.emit_null_optional_fields`.
+ /// * Zig `union(enum)` -> JSON object with one field named for the active tag and a value representing the payload.
+ /// * If the payload is `void`, then the emitted value is `{}`.
+ /// * If the union declares a method `pub fn jsonStringify(self: *@This(), jw: anytype) !void`, it is called to do the serialization instead of the default behavior. The given `jw` is a pointer to this `WriteStream`.
+ /// * Zig `enum` -> JSON string naming the active tag.
+ /// * If the enum declares a method `pub fn jsonStringify(self: *@This(), jw: anytype) !void`, it is called to do the serialization instead of the default behavior. The given `jw` is a pointer to this `WriteStream`.
+ /// * Zig untyped enum literal -> JSON string naming the active tag.
+ /// * Zig error -> JSON string naming the error.
+ /// * Zig `*T` -> the rendering of `T`. Note there is no guard against circular-reference infinite recursion.
+ ///
+ /// See also alternative functions `print` and `beginWriteRaw`.
+ /// For writing object field names, use `objectField` instead.
pub fn write(self: *Self, value: anytype) Error!void {
+ if (build_mode_has_safety) assert(self.raw_streaming_mode == .none);
const T = @TypeOf(value);
switch (@typeInfo(T)) {
.Int => {
diff --git a/lib/std/json/stringify_test.zig b/lib/std/json/stringify_test.zig
index 1722868d2a..c0003b87dc 100644
--- a/lib/std/json/stringify_test.zig
+++ b/lib/std/json/stringify_test.zig
@@ -443,3 +443,53 @@ test "nonportable numbers" {
try testStringify("9999999999999999", 9999999999999999, .{});
try testStringify("\"9999999999999999\"", 9999999999999999, .{ .emit_nonportable_numbers_as_strings = true });
}
+
+test "stringify raw streaming" {
+ var out_buf: [1024]u8 = undefined;
+ var slice_stream = std.io.fixedBufferStream(&out_buf);
+ const out = slice_stream.writer();
+
+ {
+ var w = writeStream(out, .{ .whitespace = .indent_2 });
+ try testRawStreaming(&w, &slice_stream);
+ }
+
+ {
+ var w = writeStreamMaxDepth(out, .{ .whitespace = .indent_2 }, 8);
+ try testRawStreaming(&w, &slice_stream);
+ }
+
+ {
+ var w = writeStreamMaxDepth(out, .{ .whitespace = .indent_2 }, null);
+ try testRawStreaming(&w, &slice_stream);
+ }
+
+ {
+ var w = writeStreamArbitraryDepth(testing.allocator, out, .{ .whitespace = .indent_2 });
+ defer w.deinit();
+ try testRawStreaming(&w, &slice_stream);
+ }
+}
+
+fn testRawStreaming(w: anytype, slice_stream: anytype) !void {
+ slice_stream.reset();
+
+ try w.beginObject();
+ try w.beginObjectFieldRaw();
+ try w.stream.writeAll("\"long");
+ try w.stream.writeAll(" key\"");
+ w.endObjectFieldRaw();
+ try w.beginWriteRaw();
+ try w.stream.writeAll("\"long");
+ try w.stream.writeAll(" value\"");
+ w.endWriteRaw();
+ try w.endObject();
+
+ const result = slice_stream.getWritten();
+ const expected =
+ \\{
+ \\ "long key": "long value"
+ \\}
+ ;
+ try std.testing.expectEqualStrings(expected, result);
+}
diff --git a/lib/std/math.zig b/lib/std/math.zig
index 0c00818a1e..f18739095c 100644
--- a/lib/std/math.zig
+++ b/lib/std/math.zig
@@ -749,31 +749,23 @@ test rotl {
try testing.expect(rotl(@Vector(1, u32), @Vector(1, u32){1 << 31}, @as(isize, -1))[0] == @as(u32, 1) << 30);
}
-/// Returns an unsigned int type that can hold the number of bits in T
-/// - 1. Suitable for 0-based bit indices of T.
+/// Returns an unsigned int type that can hold the number of bits in T - 1.
+/// Suitable for 0-based bit indices of T.
pub fn Log2Int(comptime T: type) type {
// comptime ceil log2
if (T == comptime_int) return comptime_int;
- comptime var count = 0;
- comptime var s = @typeInfo(T).Int.bits - 1;
- inline while (s != 0) : (s >>= 1) {
- count += 1;
- }
-
- return std.meta.Int(.unsigned, count);
+ const bits: u16 = @typeInfo(T).Int.bits;
+ const log2_bits = 16 - @clz(bits - 1);
+ return std.meta.Int(.unsigned, log2_bits);
}
/// Returns an unsigned int type that can hold the number of bits in T.
pub fn Log2IntCeil(comptime T: type) type {
// comptime ceil log2
if (T == comptime_int) return comptime_int;
- comptime var count = 0;
- comptime var s = @typeInfo(T).Int.bits;
- inline while (s != 0) : (s >>= 1) {
- count += 1;
- }
-
- return std.meta.Int(.unsigned, count);
+ const bits: u16 = @typeInfo(T).Int.bits;
+ const log2_bits = 16 - @clz(bits);
+ return std.meta.Int(.unsigned, log2_bits);
}
/// Returns the smallest integer type that can hold both from and to.
diff --git a/lib/std/math/hypot.zig b/lib/std/math/hypot.zig
index cc0dc17ab1..ddc9408aba 100644
--- a/lib/std/math/hypot.zig
+++ b/lib/std/math/hypot.zig
@@ -114,6 +114,7 @@ test "hypot.precise" {
}
test "hypot.special" {
+ @setEvalBranchQuota(2000);
inline for (.{ f16, f32, f64, f128 }) |T| {
try expect(math.isNan(hypot(nan(T), 0.0)));
try expect(math.isNan(hypot(0.0, nan(T))));
diff --git a/lib/std/math/nextafter.zig b/lib/std/math/nextafter.zig
index 717cbf4700..b88648229b 100644
--- a/lib/std/math/nextafter.zig
+++ b/lib/std/math/nextafter.zig
@@ -144,7 +144,7 @@ test "int" {
}
test "float" {
- @setEvalBranchQuota(3000);
+ @setEvalBranchQuota(4000);
// normal -> normal
try expect(nextAfter(f16, 0x1.234p0, 2.0) == 0x1.238p0);
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index 54ad53fe06..20f1370bfc 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -2272,7 +2272,7 @@ pub fn fadvise(fd: fd_t, offset: i64, len: i64, advice: usize) usize {
length_halves[0],
length_halves[1],
);
- } else if (comptime native_arch == .mips or native_arch == .mipsel) {
+ } else if (native_arch.isMIPS32()) {
// MIPS O32 does not deal with the register alignment issue, so pass a dummy value.
const offset_halves = splitValue64(offset);
@@ -2382,7 +2382,7 @@ pub fn map_shadow_stack(addr: u64, size: u64, flags: u32) usize {
}
pub const E = switch (native_arch) {
- .mips, .mipsel => enum(u16) {
+ .mips, .mipsel, .mips64, .mips64el => enum(u16) {
/// No error occurred.
SUCCESS = 0,
@@ -6784,7 +6784,258 @@ pub const termios2 = if (is_mips) extern struct {
ospeed: speed_t,
};
+/// Linux-specific socket ioctls
+pub const SIOCINQ = T.FIONREAD;
+
+/// Linux-specific socket ioctls
+/// output queue size (not sent + not acked)
+pub const SIOCOUTQ = T.IOCOUTQ;
+
+pub const SOCK_IOC_TYPE = 0x89;
+
+pub const SIOCGSTAMP_NEW = IOCTL.IOR(SOCK_IOC_TYPE, 0x06, i64[2]);
+pub const SIOCGSTAMP_OLD = IOCTL.IOR('s', 100, timeval);
+
+/// Get stamp (timeval)
+pub const SIOCGSTAMP = if (native_arch == .x86_64 or @sizeOf(timeval) == 8) SIOCGSTAMP_OLD else SIOCGSTAMP_NEW;
+
+pub const SIOCGSTAMPNS_NEW = IOCTL.IOR(SOCK_IOC_TYPE, 0x07, i64[2]);
+pub const SIOCGSTAMPNS_OLD = IOCTL.IOR('s', 101, kernel_timespec);
+
+/// Get stamp (timespec)
+pub const SIOCGSTAMPNS = if (native_arch == .x86_64 or @sizeOf(timespec) == 8) SIOCGSTAMPNS_OLD else SIOCGSTAMPNS_NEW;
+
+// Routing table calls.
+/// Add routing table entry
+pub const SIOCADDRT = 0x890B;
+
+/// Delete routing table entry
+pub const SIOCDELRT = 0x890C;
+
+/// Unused
+pub const SIOCRTMSG = 0x890D;
+
+// Socket configuration controls.
+/// Get iface name
+pub const SIOCGIFNAME = 0x8910;
+
+/// Set iface channel
+pub const SIOCSIFLINK = 0x8911;
+
+/// Get iface list
+pub const SIOCGIFCONF = 0x8912;
+
+/// Get flags
+pub const SIOCGIFFLAGS = 0x8913;
+
+/// Set flags
+pub const SIOCSIFFLAGS = 0x8914;
+
+/// Get PA address
+pub const SIOCGIFADDR = 0x8915;
+
+/// Set PA address
+pub const SIOCSIFADDR = 0x8916;
+
+/// Get remote PA address
+pub const SIOCGIFDSTADDR = 0x8917;
+
+/// Set remote PA address
+pub const SIOCSIFDSTADDR = 0x8918;
+
+/// Get broadcast PA address
+pub const SIOCGIFBRDADDR = 0x8919;
+
+/// Set broadcast PA address
+pub const SIOCSIFBRDADDR = 0x891a;
+
+/// Get network PA mask
+pub const SIOCGIFNETMASK = 0x891b;
+
+/// Set network PA mask
+pub const SIOCSIFNETMASK = 0x891c;
+
+/// Get metric
+pub const SIOCGIFMETRIC = 0x891d;
+
+/// Set metric
+pub const SIOCSIFMETRIC = 0x891e;
+
+/// Get memory address (BSD)
+pub const SIOCGIFMEM = 0x891f;
+
+/// Set memory address (BSD)
+pub const SIOCSIFMEM = 0x8920;
+
+/// Get MTU size
+pub const SIOCGIFMTU = 0x8921;
+
+/// Set MTU size
+pub const SIOCSIFMTU = 0x8922;
+
+/// Set interface name
+pub const SIOCSIFNAME = 0x8923;
+
+/// Set hardware address
+pub const SIOCSIFHWADDR = 0x8924;
+
+/// Get encapsulations
+pub const SIOCGIFENCAP = 0x8925;
+
+/// Set encapsulations
+pub const SIOCSIFENCAP = 0x8926;
+
+/// Get hardware address
+pub const SIOCGIFHWADDR = 0x8927;
+
+/// Driver slaving support
+pub const SIOCGIFSLAVE = 0x8929;
+
+/// Driver slaving support
+pub const SIOCSIFSLAVE = 0x8930;
+
+/// Add to Multicast address lists
+pub const SIOCADDMULTI = 0x8931;
+
+/// Delete from Multicast address lists
+pub const SIOCDELMULTI = 0x8932;
+
+/// name -> if_index mapping
pub const SIOCGIFINDEX = 0x8933;
+
+/// Set extended flags set
+pub const SIOCSIFPFLAGS = 0x8934;
+
+/// Get extended flags set
+pub const SIOCGIFPFLAGS = 0x8935;
+
+/// Delete PA address
+pub const SIOCDIFADDR = 0x8936;
+
+/// Set hardware broadcast addr
+pub const SIOCSIFHWBROADCAST = 0x8937;
+
+/// Get number of devices
+pub const SIOCGIFCOUNT = 0x8938;
+
+/// Bridging support
+pub const SIOCGIFBR = 0x8940;
+
+/// Set bridging options
+pub const SIOCSIFBR = 0x8941;
+
+/// Get the tx queue length
+pub const SIOCGIFTXQLEN = 0x8942;
+
+/// Set the tx queue length
+pub const SIOCSIFTXQLEN = 0x8943;
+
+/// Ethtool interface
+pub const SIOCETHTOOL = 0x8946;
+
+/// Get address of MII PHY in use.
+pub const SIOCGMIIPHY = 0x8947;
+
+/// Read MII PHY register.
+pub const SIOCGMIIREG = 0x8948;
+
+/// Write MII PHY register.
+pub const SIOCSMIIREG = 0x8949;
+
+/// Get / Set netdev parameters
+pub const SIOCWANDEV = 0x894A;
+
+/// Output queue size (not sent only)
+pub const SIOCOUTQNSD = 0x894B;
+
+/// Get socket network namespace
+pub const SIOCGSKNS = 0x894C;
+
+// ARP cache control calls.
+// 0x8950 - 0x8952 obsolete calls.
+/// Delete ARP table entry
+pub const SIOCDARP = 0x8953;
+
+/// Get ARP table entry
+pub const SIOCGARP = 0x8954;
+
+/// Set ARP table entry
+pub const SIOCSARP = 0x8955;
+
+// RARP cache control calls.
+/// Delete RARP table entry
+pub const SIOCDRARP = 0x8960;
+
+/// Get RARP table entry
+pub const SIOCGRARP = 0x8961;
+
+/// Set RARP table entry
+pub const SIOCSRARP = 0x8962;
+
+// Driver configuration calls
+/// Get device parameters
+pub const SIOCGIFMAP = 0x8970;
+
+/// Set device parameters
+pub const SIOCSIFMAP = 0x8971;
+
+// DLCI configuration calls
+/// Create new DLCI device
+pub const SIOCADDDLCI = 0x8980;
+
+/// Delete DLCI device
+pub const SIOCDELDLCI = 0x8981;
+
+/// 802.1Q VLAN support
+pub const SIOCGIFVLAN = 0x8982;
+
+/// Set 802.1Q VLAN options
+pub const SIOCSIFVLAN = 0x8983;
+
+// bonding calls
+/// Enslave a device to the bond
+pub const SIOCBONDENSLAVE = 0x8990;
+
+/// Release a slave from the bond
+pub const SIOCBONDRELEASE = 0x8991;
+
+/// Set the hw addr of the bond
+pub const SIOCBONDSETHWADDR = 0x8992;
+
+/// rtn info about slave state
+pub const SIOCBONDSLAVEINFOQUERY = 0x8993;
+
+/// rtn info about bond state
+pub const SIOCBONDINFOQUERY = 0x8994;
+
+/// Update to a new active slave
+pub const SIOCBONDCHANGEACTIVE = 0x8995;
+
+// Bridge calls
+/// Create new bridge device
+pub const SIOCBRADDBR = 0x89a0;
+
+/// Remove bridge device
+pub const SIOCBRDELBR = 0x89a1;
+
+/// Add interface to bridge
+pub const SIOCBRADDIF = 0x89a2;
+
+/// Remove interface from bridge
+pub const SIOCBRDELIF = 0x89a3;
+
+/// Get hardware time stamp config
+pub const SIOCSHWTSTAMP = 0x89b0;
+
+/// Set hardware time stamp config
+pub const SIOCGHWTSTAMP = 0x89b1;
+
+/// Device private ioctl calls
+pub const SIOCDEVPRIVATE = 0x89F0;
+
+/// These 16 ioctl calls are protocol private
+pub const SIOCPROTOPRIVATE = 0x89E0;
+
pub const IFNAMESIZE = 16;
pub const ifmap = extern struct {
@@ -6817,53 +7068,166 @@ pub const ifreq = extern struct {
};
// doc comments copied from musl
-pub const rlimit_resource = if (native_arch.isMIPS() or native_arch.isSPARC())
- arch_bits.rlimit_resource
-else
- enum(c_int) {
- /// Per-process CPU limit, in seconds.
- CPU,
- /// Largest file that can be created, in bytes.
- FSIZE,
- /// Maximum size of data segment, in bytes.
- DATA,
- /// Maximum size of stack segment, in bytes.
- STACK,
- /// Largest core file that can be created, in bytes.
- CORE,
- /// Largest resident set size, in bytes.
- /// This affects swapping; processes that are exceeding their
- /// resident set size will be more likely to have physical memory
- /// taken from them.
- RSS,
- /// Number of processes.
- NPROC,
- /// Number of open files.
- NOFILE,
- /// Locked-in-memory address space.
- MEMLOCK,
- /// Address space limit.
- AS,
- /// Maximum number of file locks.
- LOCKS,
- /// Maximum number of pending signals.
- SIGPENDING,
- /// Maximum bytes in POSIX message queues.
- MSGQUEUE,
- /// Maximum nice priority allowed to raise to.
- /// Nice levels 19 .. -20 correspond to 0 .. 39
- /// values of this resource limit.
- NICE,
- /// Maximum realtime priority allowed for non-privileged
- /// processes.
- RTPRIO,
- /// Maximum CPU time in µs that a process scheduled under a real-time
- /// scheduling policy may consume without making a blocking system
- /// call before being forcibly descheduled.
- RTTIME,
+pub const rlimit_resource = if (native_arch.isMIPS()) enum(c_int) {
+ /// Per-process CPU limit, in seconds.
+ CPU = 0,
- _,
- };
+ /// Largest file that can be created, in bytes.
+ FSIZE = 1,
+
+ /// Maximum size of data segment, in bytes.
+ DATA = 2,
+
+ /// Maximum size of stack segment, in bytes.
+ STACK = 3,
+
+ /// Largest core file that can be created, in bytes.
+ CORE = 4,
+
+ /// Number of open files.
+ NOFILE = 5,
+
+ /// Address space limit.
+ AS = 6,
+
+ /// Largest resident set size, in bytes.
+ /// This affects swapping; processes that are exceeding their
+ /// resident set size will be more likely to have physical memory
+ /// taken from them.
+ RSS = 7,
+
+ /// Number of processes.
+ NPROC = 8,
+
+ /// Locked-in-memory address space.
+ MEMLOCK = 9,
+
+ /// Maximum number of file locks.
+ LOCKS = 10,
+
+ /// Maximum number of pending signals.
+ SIGPENDING = 11,
+
+ /// Maximum bytes in POSIX message queues.
+ MSGQUEUE = 12,
+
+ /// Maximum nice priority allowed to raise to.
+ /// Nice levels 19 .. -20 correspond to 0 .. 39
+ /// values of this resource limit.
+ NICE = 13,
+
+ /// Maximum realtime priority allowed for non-privileged
+ /// processes.
+ RTPRIO = 14,
+
+ /// Maximum CPU time in µs that a process scheduled under a real-time
+ /// scheduling policy may consume without making a blocking system
+ /// call before being forcibly descheduled.
+ RTTIME = 15,
+
+ _,
+} else if (native_arch.isSPARC()) enum(c_int) {
+ /// Per-process CPU limit, in seconds.
+ CPU = 0,
+
+ /// Largest file that can be created, in bytes.
+ FSIZE = 1,
+
+ /// Maximum size of data segment, in bytes.
+ DATA = 2,
+
+ /// Maximum size of stack segment, in bytes.
+ STACK = 3,
+
+ /// Largest core file that can be created, in bytes.
+ CORE = 4,
+
+ /// Largest resident set size, in bytes.
+ /// This affects swapping; processes that are exceeding their
+ /// resident set size will be more likely to have physical memory
+ /// taken from them.
+ RSS = 5,
+
+ /// Number of open files.
+ NOFILE = 6,
+
+ /// Number of processes.
+ NPROC = 7,
+
+ /// Locked-in-memory address space.
+ MEMLOCK = 8,
+
+ /// Address space limit.
+ AS = 9,
+
+ /// Maximum number of file locks.
+ LOCKS = 10,
+
+ /// Maximum number of pending signals.
+ SIGPENDING = 11,
+
+ /// Maximum bytes in POSIX message queues.
+ MSGQUEUE = 12,
+
+ /// Maximum nice priority allowed to raise to.
+ /// Nice levels 19 .. -20 correspond to 0 .. 39
+ /// values of this resource limit.
+ NICE = 13,
+
+ /// Maximum realtime priority allowed for non-privileged
+ /// processes.
+ RTPRIO = 14,
+
+ /// Maximum CPU time in µs that a process scheduled under a real-time
+ /// scheduling policy may consume without making a blocking system
+ /// call before being forcibly descheduled.
+ RTTIME = 15,
+
+ _,
+} else enum(c_int) {
+ /// Per-process CPU limit, in seconds.
+ CPU = 0,
+ /// Largest file that can be created, in bytes.
+ FSIZE = 1,
+ /// Maximum size of data segment, in bytes.
+ DATA = 2,
+ /// Maximum size of stack segment, in bytes.
+ STACK = 3,
+ /// Largest core file that can be created, in bytes.
+ CORE = 4,
+ /// Largest resident set size, in bytes.
+ /// This affects swapping; processes that are exceeding their
+ /// resident set size will be more likely to have physical memory
+ /// taken from them.
+ RSS = 5,
+ /// Number of processes.
+ NPROC = 6,
+ /// Number of open files.
+ NOFILE = 7,
+ /// Locked-in-memory address space.
+ MEMLOCK = 8,
+ /// Address space limit.
+ AS = 9,
+ /// Maximum number of file locks.
+ LOCKS = 10,
+ /// Maximum number of pending signals.
+ SIGPENDING = 11,
+ /// Maximum bytes in POSIX message queues.
+ MSGQUEUE = 12,
+ /// Maximum nice priority allowed to raise to.
+ /// Nice levels 19 .. -20 correspond to 0 .. 39
+ /// values of this resource limit.
+ NICE = 13,
+ /// Maximum realtime priority allowed for non-privileged
+ /// processes.
+ RTPRIO = 14,
+ /// Maximum CPU time in µs that a process scheduled under a real-time
+ /// scheduling policy may consume without making a blocking system
+ /// call before being forcibly descheduled.
+ RTTIME = 15,
+
+ _,
+};
pub const rlim_t = u64;
diff --git a/lib/std/os/linux/mips.zig b/lib/std/os/linux/mips.zig
index aa02841926..e6cb5f7900 100644
--- a/lib/std/os/linux/mips.zig
+++ b/lib/std/os/linux/mips.zig
@@ -14,7 +14,8 @@ const timespec = linux.timespec;
pub fn syscall0(number: SYS) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ subu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -28,7 +29,7 @@ pub fn syscall_pipe(fd: *[2]i32) usize {
\\ .set noat
\\ .set noreorder
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
\\ nop
\\ b 2f
\\ subu $2, $0, $2
@@ -46,7 +47,8 @@ pub fn syscall_pipe(fd: *[2]i32) usize {
pub fn syscall1(number: SYS, arg1: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ subu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -59,7 +61,8 @@ pub fn syscall1(number: SYS, arg1: usize) usize {
pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ subu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -73,7 +76,8 @@ pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ subu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -88,7 +92,8 @@ pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ subu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -108,7 +113,8 @@ pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
\\ sw %[arg5], 16($sp)
\\ syscall
\\ addu $sp, $sp, 24
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ subu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -141,7 +147,8 @@ pub fn syscall6(
\\ sw %[arg6], 20($sp)
\\ syscall
\\ addu $sp, $sp, 24
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ subu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -174,7 +181,8 @@ pub fn syscall7(
\\ sw %[arg7], 24($sp)
\\ syscall
\\ addu $sp, $sp, 32
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ subu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -314,7 +322,7 @@ pub const msghdr_const = extern struct {
flags: i32,
};
-pub const blksize_t = i32;
+pub const blksize_t = u32;
pub const nlink_t = u32;
pub const time_t = i32;
pub const mode_t = u32;
@@ -323,36 +331,47 @@ pub const ino_t = u64;
pub const dev_t = u64;
pub const blkcnt_t = i64;
-// The `stat` definition used by the Linux kernel.
+// The `stat64` definition used by the Linux kernel.
pub const Stat = extern struct {
- dev: u32,
- __pad0: [3]u32, // Reserved for st_dev expansion
+ dev: dev_t,
+ __pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
ino: ino_t,
mode: mode_t,
nlink: nlink_t,
uid: uid_t,
gid: gid_t,
- rdev: u32,
- __pad1: [3]u32,
+ rdev: dev_t,
+ __pad1: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
size: off_t,
- atim: timespec,
- mtim: timespec,
- ctim: timespec,
+ atim: i32,
+ atim_nsec: u32,
+ mtim: i32,
+ mtim_nsec: u32,
+ ctim: i32,
+ ctim_nsec: u32,
blksize: blksize_t,
__pad3: u32,
blocks: blkcnt_t,
- __pad4: [14]usize,
pub fn atime(self: @This()) timespec {
- return self.atim;
+ return .{
+ .sec = self.atim,
+ .nsec = self.atim_nsec,
+ };
}
pub fn mtime(self: @This()) timespec {
- return self.mtim;
+ return .{
+ .sec = self.mtim,
+ .nsec = self.mtim_nsec,
+ };
}
pub fn ctime(self: @This()) timespec {
- return self.ctim;
+ return .{
+ .sec = self.ctim,
+ .nsec = self.ctim_nsec,
+ };
}
};
@@ -368,66 +387,6 @@ pub const timezone = extern struct {
pub const Elf_Symndx = u32;
-pub const rlimit_resource = enum(c_int) {
- /// Per-process CPU limit, in seconds.
- CPU,
-
- /// Largest file that can be created, in bytes.
- FSIZE,
-
- /// Maximum size of data segment, in bytes.
- DATA,
-
- /// Maximum size of stack segment, in bytes.
- STACK,
-
- /// Largest core file that can be created, in bytes.
- CORE,
-
- /// Number of open files.
- NOFILE,
-
- /// Address space limit.
- AS,
-
- /// Largest resident set size, in bytes.
- /// This affects swapping; processes that are exceeding their
- /// resident set size will be more likely to have physical memory
- /// taken from them.
- RSS,
-
- /// Number of processes.
- NPROC,
-
- /// Locked-in-memory address space.
- MEMLOCK,
-
- /// Maximum number of file locks.
- LOCKS,
-
- /// Maximum number of pending signals.
- SIGPENDING,
-
- /// Maximum bytes in POSIX message queues.
- MSGQUEUE,
-
- /// Maximum nice priority allowed to raise to.
- /// Nice levels 19 .. -20 correspond to 0 .. 39
- /// values of this resource limit.
- NICE,
-
- /// Maximum realtime priority allowed for non-privileged
- /// processes.
- RTPRIO,
-
- /// Maximum CPU time in µs that a process scheduled under a real-time
- /// scheduling policy may consume without making a blocking system
- /// call before being forcibly descheduled.
- RTTIME,
-
- _,
-};
-
/// TODO
pub const ucontext_t = void;
diff --git a/lib/std/os/linux/mips64.zig b/lib/std/os/linux/mips64.zig
index 579d41ca75..5e6661eae5 100644
--- a/lib/std/os/linux/mips64.zig
+++ b/lib/std/os/linux/mips64.zig
@@ -14,7 +14,8 @@ const timespec = linux.timespec;
pub fn syscall0(number: SYS) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ dsubu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -28,7 +29,7 @@ pub fn syscall_pipe(fd: *[2]i32) usize {
\\ .set noat
\\ .set noreorder
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
\\ nop
\\ b 2f
\\ subu $2, $0, $2
@@ -46,7 +47,9 @@ pub fn syscall_pipe(fd: *[2]i32) usize {
pub fn syscall1(number: SYS, arg1: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
+ \\ nop
\\ dsubu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -59,7 +62,8 @@ pub fn syscall1(number: SYS, arg1: usize) usize {
pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ dsubu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -73,7 +77,8 @@ pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ dsubu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -88,7 +93,8 @@ pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ dsubu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -104,7 +110,8 @@ pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize)
pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ dsubu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -129,7 +136,8 @@ pub fn syscall6(
) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ dsubu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -156,7 +164,8 @@ pub fn syscall7(
) usize {
return asm volatile (
\\ syscall
- \\ blez $7, 1f
+ \\ beq $7, $zero, 1f
+ \\ blez $2, 1f
\\ dsubu $2, $0, $2
\\ 1:
: [ret] "={$2}" (-> usize),
@@ -292,7 +301,7 @@ pub const msghdr_const = extern struct {
flags: i32,
};
-pub const blksize_t = i32;
+pub const blksize_t = u32;
pub const nlink_t = u32;
pub const time_t = i32;
pub const mode_t = u32;
@@ -303,34 +312,45 @@ pub const blkcnt_t = i64;
// The `stat` definition used by the Linux kernel.
pub const Stat = extern struct {
- dev: u32,
- __pad0: [3]u32, // Reserved for st_dev expansion
+ dev: dev_t,
+ __pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
ino: ino_t,
mode: mode_t,
nlink: nlink_t,
uid: uid_t,
gid: gid_t,
- rdev: u32,
- __pad1: [3]u32,
+ rdev: dev_t,
+ __pad1: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
size: off_t,
- atim: timespec,
- mtim: timespec,
- ctim: timespec,
+ atim: u32,
+ atim_nsec: u32,
+ mtim: u32,
+ mtim_nsec: u32,
+ ctim: u32,
+ ctim_nsec: u32,
blksize: blksize_t,
__pad3: u32,
blocks: blkcnt_t,
- __pad4: [14]usize,
pub fn atime(self: @This()) timespec {
- return self.atim;
+ return .{
+ .sec = self.atim,
+ .nsec = self.atim_nsec,
+ };
}
pub fn mtime(self: @This()) timespec {
- return self.mtim;
+ return .{
+ .sec = self.mtim,
+ .nsec = self.mtim_nsec,
+ };
}
pub fn ctime(self: @This()) timespec {
- return self.ctim;
+ return .{
+ .sec = self.ctim,
+ .nsec = self.ctim_nsec,
+ };
}
};
@@ -346,66 +366,6 @@ pub const timezone = extern struct {
pub const Elf_Symndx = u32;
-pub const rlimit_resource = enum(c_int) {
- /// Per-process CPU limit, in seconds.
- CPU,
-
- /// Largest file that can be created, in bytes.
- FSIZE,
-
- /// Maximum size of data segment, in bytes.
- DATA,
-
- /// Maximum size of stack segment, in bytes.
- STACK,
-
- /// Largest core file that can be created, in bytes.
- CORE,
-
- /// Number of open files.
- NOFILE,
-
- /// Address space limit.
- AS,
-
- /// Largest resident set size, in bytes.
- /// This affects swapping; processes that are exceeding their
- /// resident set size will be more likely to have physical memory
- /// taken from them.
- RSS,
-
- /// Number of processes.
- NPROC,
-
- /// Locked-in-memory address space.
- MEMLOCK,
-
- /// Maximum number of file locks.
- LOCKS,
-
- /// Maximum number of pending signals.
- SIGPENDING,
-
- /// Maximum bytes in POSIX message queues.
- MSGQUEUE,
-
- /// Maximum nice priority allowed to raise to.
- /// Nice levels 19 .. -20 correspond to 0 .. 39
- /// values of this resource limit.
- NICE,
-
- /// Maximum realtime priority allowed for non-privileged
- /// processes.
- RTPRIO,
-
- /// Maximum CPU time in µs that a process scheduled under a real-time
- /// scheduling policy may consume without making a blocking system
- /// call before being forcibly descheduled.
- RTTIME,
-
- _,
-};
-
/// TODO
pub const ucontext_t = void;
diff --git a/lib/std/os/linux/sparc64.zig b/lib/std/os/linux/sparc64.zig
index a705b58fb6..b30f001000 100644
--- a/lib/std/os/linux/sparc64.zig
+++ b/lib/std/os/linux/sparc64.zig
@@ -448,63 +448,3 @@ pub const ucontext_t = extern struct {
/// TODO
pub const getcontext = {};
-
-pub const rlimit_resource = enum(c_int) {
- /// Per-process CPU limit, in seconds.
- CPU,
-
- /// Largest file that can be created, in bytes.
- FSIZE,
-
- /// Maximum size of data segment, in bytes.
- DATA,
-
- /// Maximum size of stack segment, in bytes.
- STACK,
-
- /// Largest core file that can be created, in bytes.
- CORE,
-
- /// Largest resident set size, in bytes.
- /// This affects swapping; processes that are exceeding their
- /// resident set size will be more likely to have physical memory
- /// taken from them.
- RSS,
-
- /// Number of open files.
- NOFILE,
-
- /// Number of processes.
- NPROC,
-
- /// Locked-in-memory address space.
- MEMLOCK,
-
- /// Address space limit.
- AS,
-
- /// Maximum number of file locks.
- LOCKS,
-
- /// Maximum number of pending signals.
- SIGPENDING,
-
- /// Maximum bytes in POSIX message queues.
- MSGQUEUE,
-
- /// Maximum nice priority allowed to raise to.
- /// Nice levels 19 .. -20 correspond to 0 .. 39
- /// values of this resource limit.
- NICE,
-
- /// Maximum realtime priority allowed for non-privileged
- /// processes.
- RTPRIO,
-
- /// Maximum CPU time in µs that a process scheduled under a real-time
- /// scheduling policy may consume without making a blocking system
- /// call before being forcibly descheduled.
- RTTIME,
-
- _,
-};
diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig
index a8fa1454a5..4c6ec1294b 100644
--- a/lib/std/unicode.zig
+++ b/lib/std/unicode.zig
@@ -535,6 +535,7 @@ fn testUtf16CountCodepoints() !void {
}
test "utf16 count codepoints" {
+ @setEvalBranchQuota(2000);
try testUtf16CountCodepoints();
try comptime testUtf16CountCodepoints();
}
diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig
index d0f1c73fc8..3450e39cc6 100644
--- a/lib/std/zig/AstGen.zig
+++ b/lib/std/zig/AstGen.zig
@@ -66,6 +66,10 @@ scratch: std.ArrayListUnmanaged(u32) = .{},
/// of ZIR.
/// The key is the ref operand; the value is the ref instruction.
ref_table: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
+/// Any information which should trigger invalidation of incremental compilation
+/// data should be used to update this hasher. The result is the final source
+/// hash of the enclosing declaration/etc.
+src_hasher: std.zig.SrcHasher,
const InnerError = error{ OutOfMemory, AnalysisFail };
@@ -137,6 +141,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
.arena = arena.allocator(),
.tree = &tree,
.nodes_need_rl = &nodes_need_rl,
+ .src_hasher = undefined, // `structDeclInner` for the root struct will set this
};
defer astgen.deinit(gpa);
@@ -1422,6 +1427,8 @@ fn fnProtoExpr(
.is_extern = false,
.is_noinline = false,
.noalias_bits = noalias_bits,
+
+ .proto_hash = undefined, // ignored for `body_gz == null`
});
_ = try block_scope.addBreak(.break_inline, block_inst, result);
@@ -4007,6 +4014,13 @@ fn fnDecl(
const tree = astgen.tree;
const token_tags = tree.tokens.items(.tag);
+ const old_hasher = astgen.src_hasher;
+ defer astgen.src_hasher = old_hasher;
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
+ // We don't add the full source yet, because we also need the prototype hash!
+ // The source slice is added towards the *end* of this function.
+ astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
+
// missing function name already happened in scanDecls()
const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;
@@ -4300,11 +4314,21 @@ fn fnDecl(
.is_extern = true,
.is_noinline = is_noinline,
.noalias_bits = noalias_bits,
+ .proto_hash = undefined, // ignored for `body_gz == null`
});
} else func: {
// as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz
fn_gz.instructions_top = ret_gz.instructions.items.len;
+ // Construct the prototype hash.
+ // Leave `astgen.src_hasher` unmodified; this will be used for hashing
+ // the *whole* function declaration, including its body.
+ var proto_hasher = astgen.src_hasher;
+ const proto_node = tree.nodes.items(.data)[decl_node].lhs;
+ proto_hasher.update(tree.getNodeSource(proto_node));
+ var proto_hash: std.zig.SrcHash = undefined;
+ proto_hasher.final(&proto_hash);
+
const prev_fn_block = astgen.fn_block;
const prev_fn_ret_ty = astgen.fn_ret_ty;
defer {
@@ -4362,16 +4386,22 @@ fn fnDecl(
.is_extern = false,
.is_noinline = is_noinline,
.noalias_bits = noalias_bits,
+ .proto_hash = proto_hash,
});
};
+ // *Now* we can incorporate the full source code into the hasher.
+ astgen.src_hasher.update(tree.getNodeSource(decl_node));
+
// We add this at the end so that its instruction index marks the end range
// of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
_ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
+ var hash: std.zig.SrcHash = undefined;
+ astgen.src_hasher.final(&hash);
try setDeclaration(
decl_inst,
- std.zig.hashSrc(tree.getNodeSource(decl_node)),
+ hash,
.{ .named = fn_name_token },
decl_gz.decl_line,
is_pub,
@@ -4395,6 +4425,12 @@ fn globalVarDecl(
const tree = astgen.tree;
const token_tags = tree.tokens.items(.tag);
+ const old_hasher = astgen.src_hasher;
+ defer astgen.src_hasher = old_hasher;
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
+ astgen.src_hasher.update(tree.getNodeSource(node));
+ astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
+
const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
// We do this at the beginning so that the instruction index marks the range start
// of the top level declaration.
@@ -4534,9 +4570,11 @@ fn globalVarDecl(
_ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
}
+ var hash: std.zig.SrcHash = undefined;
+ astgen.src_hasher.final(&hash);
try setDeclaration(
decl_inst,
- std.zig.hashSrc(tree.getNodeSource(node)),
+ hash,
.{ .named = name_token },
block_scope.decl_line,
is_pub,
@@ -4562,6 +4600,12 @@ fn comptimeDecl(
const node_datas = tree.nodes.items(.data);
const body_node = node_datas[node].lhs;
+ const old_hasher = astgen.src_hasher;
+ defer astgen.src_hasher = old_hasher;
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
+ astgen.src_hasher.update(tree.getNodeSource(node));
+ astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
+
// Up top so the ZIR instruction index marks the start range of this
// top-level declaration.
const decl_inst = try gz.makeDeclaration(node);
@@ -4584,9 +4628,11 @@ fn comptimeDecl(
_ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
}
+ var hash: std.zig.SrcHash = undefined;
+ astgen.src_hasher.final(&hash);
try setDeclaration(
decl_inst,
- std.zig.hashSrc(tree.getNodeSource(node)),
+ hash,
.@"comptime",
decl_block.decl_line,
false,
@@ -4607,6 +4653,12 @@ fn usingnamespaceDecl(
const tree = astgen.tree;
const node_datas = tree.nodes.items(.data);
+ const old_hasher = astgen.src_hasher;
+ defer astgen.src_hasher = old_hasher;
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
+ astgen.src_hasher.update(tree.getNodeSource(node));
+ astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
+
const type_expr = node_datas[node].lhs;
const is_pub = blk: {
const main_tokens = tree.nodes.items(.main_token);
@@ -4634,9 +4686,11 @@ fn usingnamespaceDecl(
const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
_ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
+ var hash: std.zig.SrcHash = undefined;
+ astgen.src_hasher.final(&hash);
try setDeclaration(
decl_inst,
- std.zig.hashSrc(tree.getNodeSource(node)),
+ hash,
.@"usingnamespace",
decl_block.decl_line,
is_pub,
@@ -4658,6 +4712,12 @@ fn testDecl(
const node_datas = tree.nodes.items(.data);
const body_node = node_datas[node].rhs;
+ const old_hasher = astgen.src_hasher;
+ defer astgen.src_hasher = old_hasher;
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
+ astgen.src_hasher.update(tree.getNodeSource(node));
+ astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
+
// Up top so the ZIR instruction index marks the start range of this
// top-level declaration.
const decl_inst = try gz.makeDeclaration(node);
@@ -4819,13 +4879,18 @@ fn testDecl(
.is_extern = false,
.is_noinline = false,
.noalias_bits = 0,
+
+ // Tests don't have a prototype that needs hashing
+ .proto_hash = .{0} ** 16,
});
_ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);
+ var hash: std.zig.SrcHash = undefined;
+ astgen.src_hasher.final(&hash);
try setDeclaration(
decl_inst,
- std.zig.hashSrc(tree.getNodeSource(node)),
+ hash,
test_name,
decl_block.decl_line,
false,
@@ -4983,10 +5048,12 @@ fn structDeclInner(
}
};
- var fields_hasher = std.zig.SrcHasher.init(.{});
- fields_hasher.update(@tagName(layout));
+ const old_hasher = astgen.src_hasher;
+ defer astgen.src_hasher = old_hasher;
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
+ astgen.src_hasher.update(@tagName(layout));
if (backing_int_node != 0) {
- fields_hasher.update(tree.getNodeSource(backing_int_node));
+ astgen.src_hasher.update(tree.getNodeSource(backing_int_node));
}
var sfba = std.heap.stackFallback(256, astgen.arena);
@@ -5009,7 +5076,7 @@ fn structDeclInner(
.field => |field| field,
};
- fields_hasher.update(tree.getNodeSource(member_node));
+ astgen.src_hasher.update(tree.getNodeSource(member_node));
if (!is_tuple) {
const field_name = try astgen.identAsString(member.ast.main_token);
@@ -5139,7 +5206,7 @@ fn structDeclInner(
}
var fields_hash: std.zig.SrcHash = undefined;
- fields_hasher.final(&fields_hash);
+ astgen.src_hasher.final(&fields_hash);
try gz.setStruct(decl_inst, .{
.src_node = node,
@@ -5240,11 +5307,13 @@ fn unionDeclInner(
var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
defer wip_members.deinit();
- var fields_hasher = std.zig.SrcHasher.init(.{});
- fields_hasher.update(@tagName(layout));
- fields_hasher.update(&.{@intFromBool(auto_enum_tok != null)});
+ const old_hasher = astgen.src_hasher;
+ defer astgen.src_hasher = old_hasher;
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
+ astgen.src_hasher.update(@tagName(layout));
+ astgen.src_hasher.update(&.{@intFromBool(auto_enum_tok != null)});
if (arg_node != 0) {
- fields_hasher.update(astgen.tree.getNodeSource(arg_node));
+ astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node));
}
var sfba = std.heap.stackFallback(256, astgen.arena);
@@ -5261,7 +5330,7 @@ fn unionDeclInner(
.decl => continue,
.field => |field| field,
};
- fields_hasher.update(astgen.tree.getNodeSource(member_node));
+ astgen.src_hasher.update(astgen.tree.getNodeSource(member_node));
member.convertToNonTupleLike(astgen.tree.nodes);
if (member.ast.tuple_like) {
return astgen.failTok(member.ast.main_token, "union field missing name", .{});
@@ -5364,7 +5433,7 @@ fn unionDeclInner(
}
var fields_hash: std.zig.SrcHash = undefined;
- fields_hasher.final(&fields_hash);
+ astgen.src_hasher.final(&fields_hash);
if (!block_scope.isEmpty()) {
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
@@ -5578,11 +5647,13 @@ fn containerDecl(
var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);
defer wip_members.deinit();
- var fields_hasher = std.zig.SrcHasher.init(.{});
+ const old_hasher = astgen.src_hasher;
+ defer astgen.src_hasher = old_hasher;
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
if (container_decl.ast.arg != 0) {
- fields_hasher.update(tree.getNodeSource(container_decl.ast.arg));
+ astgen.src_hasher.update(tree.getNodeSource(container_decl.ast.arg));
}
- fields_hasher.update(&.{@intFromBool(nonexhaustive)});
+ astgen.src_hasher.update(&.{@intFromBool(nonexhaustive)});
var sfba = std.heap.stackFallback(256, astgen.arena);
const sfba_allocator = sfba.get();
@@ -5596,7 +5667,7 @@ fn containerDecl(
for (container_decl.ast.members) |member_node| {
if (member_node == counts.nonexhaustive_node)
continue;
- fields_hasher.update(tree.getNodeSource(member_node));
+ astgen.src_hasher.update(tree.getNodeSource(member_node));
var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
.decl => continue,
.field => |field| field,
@@ -5676,7 +5747,7 @@ fn containerDecl(
}
var fields_hash: std.zig.SrcHash = undefined;
- fields_hasher.final(&fields_hash);
+ astgen.src_hasher.final(&fields_hash);
const body = block_scope.instructionsSlice();
const body_len = astgen.countBodyLenAfterFixups(body);
@@ -8478,6 +8549,10 @@ fn tunnelThroughClosure(
});
}
+ // Incorporate the capture index into the source hash, so that changes in
+ // the order of captures cause suitable re-analysis.
+ astgen.src_hasher.update(std.mem.asBytes(&cur_capture_index));
+
// Add an instruction to get the value from the closure.
return gz.addExtendedNodeSmall(.closure_get, inner_ref_node, cur_capture_index);
}
@@ -9306,6 +9381,13 @@ fn builtinCall(
},
.src => {
+ // Incorporate the source location into the source hash, so that
+ // changes in the source location of `@src()` result in re-analysis.
+ astgen.src_hasher.update(
+ std.mem.asBytes(&astgen.source_line) ++
+ std.mem.asBytes(&astgen.source_column),
+ );
+
const token_starts = tree.tokens.items(.start);
const node_start = token_starts[tree.firstToken(node)];
astgen.advanceSourceCursor(node_start);
@@ -12122,6 +12204,9 @@ const GenZir = struct {
is_test: bool,
is_extern: bool,
is_noinline: bool,
+
+ /// Ignored if `body_gz == null`.
+ proto_hash: std.zig.SrcHash,
}) !Zir.Inst.Ref {
assert(args.src_node != 0);
const astgen = gz.astgen;
@@ -12150,15 +12235,7 @@ const GenZir = struct {
const columns = args.lbrace_column | (rbrace_column << 16);
- const proto_hash: std.zig.SrcHash = switch (node_tags[fn_decl]) {
- .fn_decl => sig_hash: {
- const proto_node = node_datas[fn_decl].lhs;
- break :sig_hash std.zig.hashSrc(tree.getNodeSource(proto_node));
- },
- .test_decl => std.zig.hashSrc(""), // tests don't have a prototype
- else => unreachable,
- };
- const proto_hash_arr: [4]u32 = @bitCast(proto_hash);
+ const proto_hash_arr: [4]u32 = @bitCast(args.proto_hash);
src_locs_and_hash_buffer = .{
args.lbrace_line,
diff --git a/lib/std/zig/Server.zig b/lib/std/zig/Server.zig
index 7ce017045d..0ed9cfcd0b 100644
--- a/lib/std/zig/Server.zig
+++ b/lib/std/zig/Server.zig
@@ -14,8 +14,8 @@ pub const Message = struct {
zig_version,
/// Body is an ErrorBundle.
error_bundle,
- /// Body is a EmitBinPath.
- emit_bin_path,
+ /// Body is a EmitDigest.
+ emit_digest,
/// Body is a TestMetadata
test_metadata,
/// Body is a TestResults
@@ -82,8 +82,8 @@ pub const Message = struct {
};
/// Trailing:
- /// * file system path where the emitted binary can be found
- pub const EmitBinPath = extern struct {
+ /// * the hex digest of the cache directory within the /o/ subdirectory.
+ pub const EmitDigest = extern struct {
flags: Flags,
pub const Flags = packed struct(u8) {
@@ -196,17 +196,17 @@ pub fn serveU64Message(s: *Server, tag: OutMessage.Tag, int: u64) !void {
}, &.{std.mem.asBytes(&msg_le)});
}
-pub fn serveEmitBinPath(
+pub fn serveEmitDigest(
s: *Server,
- fs_path: []const u8,
- header: OutMessage.EmitBinPath,
+ digest: *const [Cache.bin_digest_len]u8,
+ header: OutMessage.EmitDigest,
) !void {
try s.serveMessage(.{
- .tag = .emit_bin_path,
- .bytes_len = @intCast(fs_path.len + @sizeOf(OutMessage.EmitBinPath)),
+ .tag = .emit_digest,
+ .bytes_len = @intCast(digest.len + @sizeOf(OutMessage.EmitDigest)),
}, &.{
std.mem.asBytes(&header),
- fs_path,
+ digest,
});
}
@@ -328,3 +328,4 @@ const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const native_endian = builtin.target.cpu.arch.endian();
const need_bswap = native_endian != .little;
+const Cache = std.Build.Cache;
diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig
index 8318a5a345..26f4c4780f 100644
--- a/lib/std/zig/Zir.zig
+++ b/lib/std/zig/Zir.zig
@@ -3548,7 +3548,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
const datas = zir.instructions.items(.data);
switch (tags[@intFromEnum(decl_inst)]) {
// Functions are allowed and yield no iterations.
- // There is one case matching this in the extended instruction set below.
+ // This is because they are returned by `findDecls`.
.func, .func_inferred, .func_fancy => return .{
.extra_index = undefined,
.decls_remaining = 0,
@@ -3558,6 +3558,13 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
.extended => {
const extended = datas[@intFromEnum(decl_inst)].extended;
switch (extended.opcode) {
+ // Reifications are allowed and yield no iterations.
+ // This is because they are returned by `findDecls`.
+ .reify => return .{
+ .extra_index = undefined,
+ .decls_remaining = 0,
+ .zir = zir,
+ },
.struct_decl => {
const small: Inst.StructDecl.Small = @bitCast(extended.small);
var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).Struct.fields.len);
@@ -3690,6 +3697,17 @@ pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.In
if (bodies.addrspace_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
}
+/// Like `findDecls`, but only considers the `main_struct_inst` instruction. This may return more than
+/// just that instruction because it will also traverse fields.
+pub fn findDeclsRoot(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index)) !void {
+ list.clearRetainingCapacity();
+
+ var found_defers: std.AutoHashMapUnmanaged(u32, void) = .{};
+ defer found_defers.deinit(gpa);
+
+ try zir.findDeclsInner(gpa, list, &found_defers, .main_struct_inst);
+}
+
fn findDeclsInner(
zir: Zir,
gpa: Allocator,
diff --git a/lib/std/zig/system/darwin/macos.zig b/lib/std/zig/system/darwin/macos.zig
index 0bc08b319c..c0a9aa47d7 100644
--- a/lib/std/zig/system/darwin/macos.zig
+++ b/lib/std/zig/system/darwin/macos.zig
@@ -419,6 +419,11 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
.ARM_TYPHOON => &Target.aarch64.cpu.apple_a8,
.ARM_CYCLONE => &Target.aarch64.cpu.cyclone,
else => return null,
+ .ARM_COLL => &Target.aarch64.cpu.apple_a17,
+ .ARM_IBIZA => &Target.aarch64.cpu.apple_m3, // base
+ .ARM_LOBOS => &Target.aarch64.cpu.apple_m3, // pro
+ .ARM_PALMA => &Target.aarch64.cpu.apple_m3, // max
+ // .ARM_DONAN => &Target.aarch64.cpu.apple_m4, // decl not available until llvm 19
};
return Target.Cpu{
diff --git a/src/Air.zig b/src/Air.zig
index aa821dc420..5c559a4088 100644
--- a/src/Air.zig
+++ b/src/Air.zig
@@ -456,6 +456,8 @@ pub const Inst = struct {
/// Same as `dbg_var_ptr` except the local is a const, not a var, and the
/// operand is the local's value.
dbg_var_val,
+ /// Same as `dbg_var_val` except the local is an inline function argument.
+ dbg_arg_inline,
/// ?T => bool
/// Result type is always bool.
/// Uses the `un_op` field.
@@ -1022,10 +1024,7 @@ pub const Inst = struct {
ty: Ref,
/// Index into `extra` of a null-terminated string representing the parameter name.
/// This is `.none` if debug info is stripped.
- name: enum(u32) {
- none = std.math.maxInt(u32),
- _,
- },
+ name: NullTerminatedString,
},
ty_op: struct {
ty: Ref,
@@ -1440,6 +1439,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
.dbg_stmt,
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
.store,
.store_safe,
.fence,
@@ -1562,14 +1562,16 @@ pub fn value(air: Air, inst: Inst.Ref, pt: Zcu.PerThread) !?Value {
return air.typeOfIndex(index, &pt.zcu.intern_pool).onePossibleValue(pt);
}
-pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 {
- const bytes = std.mem.sliceAsBytes(air.extra[index..]);
- var end: usize = 0;
- while (bytes[end] != 0) {
- end += 1;
+pub const NullTerminatedString = enum(u32) {
+ none = std.math.maxInt(u32),
+ _,
+
+ pub fn toSlice(nts: NullTerminatedString, air: Air) [:0]const u8 {
+ if (nts == .none) return "";
+ const bytes = std.mem.sliceAsBytes(air.extra[@intFromEnum(nts)..]);
+ return bytes[0..std.mem.indexOfScalar(u8, bytes, 0).? :0];
}
- return bytes[0..end :0];
-}
+};
/// Returns whether the given instruction must always be lowered, for instance
/// because it can cause side effects. If an instruction does not need to be
@@ -1596,6 +1598,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
.dbg_inline_block,
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
.ret,
.ret_safe,
.ret_load,
diff --git a/src/Air/types_resolved.zig b/src/Air/types_resolved.zig
index 77c8344a86..4b92a3a94f 100644
--- a/src/Air/types_resolved.zig
+++ b/src/Air/types_resolved.zig
@@ -339,6 +339,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> {
if (!checkRef(data.pl_op.operand, zcu)) return false;
},
diff --git a/src/Compilation.zig b/src/Compilation.zig
index fab0496b22..dc7d0ba925 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -39,6 +39,8 @@ const Air = @import("Air.zig");
const Builtin = @import("Builtin.zig");
const LlvmObject = @import("codegen/llvm.zig").Object;
const dev = @import("dev.zig");
+pub const Directory = Cache.Directory;
+const Path = Cache.Path;
pub const Config = @import("Compilation/Config.zig");
@@ -70,9 +72,9 @@ bin_file: ?*link.File,
/// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin)
sysroot: ?[]const u8,
/// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used.
-implib_emit: ?Emit,
+implib_emit: ?Path,
/// This is non-null when `-femit-docs` is provided.
-docs_emit: ?Emit,
+docs_emit: ?Path,
root_name: [:0]const u8,
include_compiler_rt: bool,
objects: []Compilation.LinkObject,
@@ -269,27 +271,9 @@ llvm_opt_bisect_limit: c_int,
file_system_inputs: ?*std.ArrayListUnmanaged(u8),
-pub const Emit = struct {
- /// Where the output will go.
- directory: Directory,
- /// Path to the output file, relative to `directory`.
- sub_path: []const u8,
-
- /// Returns the full path to `basename` if it were in the same directory as the
- /// `Emit` sub_path.
- pub fn basenamePath(emit: Emit, arena: Allocator, basename: []const u8) ![:0]const u8 {
- const full_path = if (emit.directory.path) |p|
- try std.fs.path.join(arena, &[_][]const u8{ p, emit.sub_path })
- else
- emit.sub_path;
-
- if (std.fs.path.dirname(full_path)) |dirname| {
- return try std.fs.path.joinZ(arena, &.{ dirname, basename });
- } else {
- return try arena.dupeZ(u8, basename);
- }
- }
-};
+/// This is the digest of the cache for the current compilation.
+/// This digest will be known after update() is called.
+digest: ?[Cache.bin_digest_len]u8 = null,
pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
pub const SemaError = Zcu.SemaError;
@@ -868,8 +852,6 @@ pub const LldError = struct {
}
};
-pub const Directory = Cache.Directory;
-
pub const EmitLoc = struct {
/// If this is `null` it means the file will be output to the cache directory.
/// When provided, both the open file handle and the path name must outlive the `Compilation`.
@@ -1672,7 +1654,9 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
// In the case of incremental cache mode, this `artifact_directory`
// is computed based on a hash of non-linker inputs, and it is where all
// build artifacts are stored (even while in-progress).
+ comp.digest = hash.peekBin();
const digest = hash.final();
+
const artifact_sub_dir = "o" ++ std.fs.path.sep_str ++ digest;
var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
errdefer artifact_dir.close();
@@ -1688,8 +1672,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
comp.cache_use = .{ .incremental = incremental };
if (options.emit_bin) |emit_bin| {
- const emit: Emit = .{
- .directory = emit_bin.directory orelse artifact_directory,
+ const emit: Path = .{
+ .root_dir = emit_bin.directory orelse artifact_directory,
.sub_path = emit_bin.basename,
};
comp.bin_file = try link.File.open(arena, comp, emit, lf_open_opts);
@@ -1697,14 +1681,14 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
if (options.emit_implib) |emit_implib| {
comp.implib_emit = .{
- .directory = emit_implib.directory orelse artifact_directory,
+ .root_dir = emit_implib.directory orelse artifact_directory,
.sub_path = emit_implib.basename,
};
}
if (options.emit_docs) |emit_docs| {
comp.docs_emit = .{
- .directory = emit_docs.directory orelse artifact_directory,
+ .root_dir = emit_docs.directory orelse artifact_directory,
.sub_path = emit_docs.basename,
};
}
@@ -2121,9 +2105,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
comp.last_update_was_cache_hit = true;
log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});
- const digest = man.final();
+ const bin_digest = man.finalBin();
+ const hex_digest = Cache.binToHex(bin_digest);
- comp.wholeCacheModeSetBinFilePath(whole, &digest);
+ comp.digest = bin_digest;
+ comp.wholeCacheModeSetBinFilePath(whole, &hex_digest);
assert(whole.lock == null);
whole.lock = man.toOwnedLock();
@@ -2155,21 +2141,21 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
if (whole.implib_sub_path) |sub_path| {
comp.implib_emit = .{
- .directory = tmp_artifact_directory,
+ .root_dir = tmp_artifact_directory,
.sub_path = std.fs.path.basename(sub_path),
};
}
if (whole.docs_sub_path) |sub_path| {
comp.docs_emit = .{
- .directory = tmp_artifact_directory,
+ .root_dir = tmp_artifact_directory,
.sub_path = std.fs.path.basename(sub_path),
};
}
if (whole.bin_sub_path) |sub_path| {
- const emit: Emit = .{
- .directory = tmp_artifact_directory,
+ const emit: Path = .{
+ .root_dir = tmp_artifact_directory,
.sub_path = std.fs.path.basename(sub_path),
};
comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts);
@@ -2329,7 +2315,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
try man.populateOtherManifest(pwc.manifest, pwc.prefix_map);
}
- const digest = man.final();
+ const bin_digest = man.finalBin();
+ const hex_digest = Cache.binToHex(bin_digest);
// Rename the temporary directory into place.
// Close tmp dir and link.File to avoid open handle during rename.
@@ -2341,7 +2328,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
const s = std.fs.path.sep_str;
const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
- const o_sub_path = "o" ++ s ++ digest;
+ const o_sub_path = "o" ++ s ++ hex_digest;
// Work around windows `AccessDenied` if any files within this
// directory are open by closing and reopening the file handles.
@@ -2376,14 +2363,15 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
},
);
};
- comp.wholeCacheModeSetBinFilePath(whole, &digest);
+ comp.digest = bin_digest;
+ comp.wholeCacheModeSetBinFilePath(whole, &hex_digest);
// The linker flush functions need to know the final output path
// for debug info purposes because executable debug info contains
// references object file paths.
if (comp.bin_file) |lf| {
lf.emit = .{
- .directory = comp.local_cache_directory,
+ .root_dir = comp.local_cache_directory,
.sub_path = whole.bin_sub_path.?,
};
@@ -2393,9 +2381,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
}
}
- try flush(comp, arena, .main, main_progress_node);
-
- if (try comp.totalErrorCount() != 0) return;
+ try flush(comp, arena, .{
+ .root_dir = comp.local_cache_directory,
+ .sub_path = o_sub_path,
+ }, .main, main_progress_node);
// Failure here only means an unnecessary cache miss.
man.writeManifest() catch |err| {
@@ -2410,8 +2399,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
assert(whole.lock == null);
whole.lock = man.toOwnedLock();
},
- .incremental => {
- try flush(comp, arena, .main, main_progress_node);
+ .incremental => |incremental| {
+ try flush(comp, arena, .{
+ .root_dir = incremental.artifact_directory,
+ }, .main, main_progress_node);
},
}
}
@@ -2440,7 +2431,13 @@ pub fn appendFileSystemInput(
std.debug.panic("missing prefix directory: {}, {s}", .{ root, sub_file_path });
}
-fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
+fn flush(
+ comp: *Compilation,
+ arena: Allocator,
+ default_artifact_directory: Path,
+ tid: Zcu.PerThread.Id,
+ prog_node: std.Progress.Node,
+) !void {
if (comp.bin_file) |lf| {
// This is needed before reading the error flags.
lf.flush(arena, tid, prog_node) catch |err| switch (err) {
@@ -2454,17 +2451,7 @@ fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
try link.File.C.flushEmitH(zcu);
if (zcu.llvm_object) |llvm_object| {
- const default_emit = switch (comp.cache_use) {
- .whole => |whole| .{
- .directory = whole.tmp_artifact_directory.?,
- .sub_path = "dummy",
- },
- .incremental => |incremental| .{
- .directory = incremental.artifact_directory,
- .sub_path = "dummy",
- },
- };
- try emitLlvmObject(comp, arena, default_emit, null, llvm_object, prog_node);
+ try emitLlvmObject(comp, arena, default_artifact_directory, null, llvm_object, prog_node);
}
}
}
@@ -2533,7 +2520,7 @@ fn wholeCacheModeSetBinFilePath(
@memcpy(sub_path[digest_start..][0..digest.len], digest);
comp.implib_emit = .{
- .directory = comp.local_cache_directory,
+ .root_dir = comp.local_cache_directory,
.sub_path = sub_path,
};
}
@@ -2542,7 +2529,7 @@ fn wholeCacheModeSetBinFilePath(
@memcpy(sub_path[digest_start..][0..digest.len], digest);
comp.docs_emit = .{
- .directory = comp.local_cache_directory,
+ .root_dir = comp.local_cache_directory,
.sub_path = sub_path,
};
}
@@ -2745,7 +2732,7 @@ fn emitOthers(comp: *Compilation) void {
pub fn emitLlvmObject(
comp: *Compilation,
arena: Allocator,
- default_emit: Emit,
+ default_artifact_directory: Path,
bin_emit_loc: ?EmitLoc,
llvm_object: LlvmObject.Ptr,
prog_node: std.Progress.Node,
@@ -2756,10 +2743,10 @@ pub fn emitLlvmObject(
try llvm_object.emit(.{
.pre_ir_path = comp.verbose_llvm_ir,
.pre_bc_path = comp.verbose_llvm_bc,
- .bin_path = try resolveEmitLoc(arena, default_emit, bin_emit_loc),
- .asm_path = try resolveEmitLoc(arena, default_emit, comp.emit_asm),
- .post_ir_path = try resolveEmitLoc(arena, default_emit, comp.emit_llvm_ir),
- .post_bc_path = try resolveEmitLoc(arena, default_emit, comp.emit_llvm_bc),
+ .bin_path = try resolveEmitLoc(arena, default_artifact_directory, bin_emit_loc),
+ .asm_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_asm),
+ .post_ir_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_ir),
+ .post_bc_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_bc),
.is_debug = comp.root_mod.optimize_mode == .Debug,
.is_small = comp.root_mod.optimize_mode == .ReleaseSmall,
@@ -2772,14 +2759,14 @@ pub fn emitLlvmObject(
fn resolveEmitLoc(
arena: Allocator,
- default_emit: Emit,
+ default_artifact_directory: Path,
opt_loc: ?EmitLoc,
) Allocator.Error!?[*:0]const u8 {
const loc = opt_loc orelse return null;
const slice = if (loc.directory) |directory|
try directory.joinZ(arena, &.{loc.basename})
else
- try default_emit.basenamePath(arena, loc.basename);
+ try default_artifact_directory.joinStringZ(arena, loc.basename);
return slice.ptr;
}
@@ -3010,14 +2997,26 @@ pub fn saveState(comp: *Compilation) !void {
addBuf(&bufs, mem.sliceAsBytes(ip.free_dep_entries.items));
for (ip.locals, pt_headers.items) |*local, pt_header| {
- addBuf(&bufs, mem.sliceAsBytes(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len]));
- addBuf(&bufs, mem.sliceAsBytes(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len]));
- addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len]));
- addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len]));
- 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_type)[0..pt_header.intern_pool.files_len]));
+ if (pt_header.intern_pool.limbs_len > 0) {
+ addBuf(&bufs, mem.sliceAsBytes(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len]));
+ }
+ if (pt_header.intern_pool.extra_len > 0) {
+ addBuf(&bufs, mem.sliceAsBytes(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len]));
+ }
+ if (pt_header.intern_pool.items_len > 0) {
+ addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len]));
+ addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len]));
+ }
+ if (pt_header.intern_pool.string_bytes_len > 0) {
+ addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]);
+ }
+ if (pt_header.intern_pool.tracked_insts_len > 0) {
+ addBuf(&bufs, mem.sliceAsBytes(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len]));
+ }
+ if (pt_header.intern_pool.files_len > 0) {
+ 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_type)[0..pt_header.intern_pool.files_len]));
+ }
}
//// TODO: compilation errors
@@ -3035,7 +3034,7 @@ pub fn saveState(comp: *Compilation) !void {
// Using an atomic file prevents a crash or power failure from corrupting
// the previous incremental compilation state.
- var af = try lf.emit.directory.handle.atomicFile(basename, .{});
+ var af = try lf.emit.root_dir.handle.atomicFile(basename, .{});
defer af.deinit();
try af.file.pwritevAll(bufs.items, 0);
try af.finish();
@@ -4000,11 +3999,11 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{});
const emit = comp.docs_emit.?;
- var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
+ var out_dir = emit.root_dir.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
return comp.lockAndSetMiscFailure(
.docs_copy,
"unable to create output directory '{}{s}': {s}",
- .{ emit.directory, emit.sub_path, @errorName(err) },
+ .{ emit.root_dir, emit.sub_path, @errorName(err) },
);
};
defer out_dir.close();
@@ -4024,7 +4023,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
return comp.lockAndSetMiscFailure(
.docs_copy,
"unable to create '{}{s}/sources.tar': {s}",
- .{ emit.directory, emit.sub_path, @errorName(err) },
+ .{ emit.root_dir, emit.sub_path, @errorName(err) },
);
};
defer tar_file.close();
@@ -4223,11 +4222,11 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node);
const emit = comp.docs_emit.?;
- var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
+ var out_dir = emit.root_dir.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
return comp.lockAndSetMiscFailure(
.docs_copy,
"unable to create output directory '{}{s}': {s}",
- .{ emit.directory, emit.sub_path, @errorName(err) },
+ .{ emit.root_dir, emit.sub_path, @errorName(err) },
);
};
defer out_dir.close();
@@ -4241,7 +4240,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}{s}' to '{}{s}': {s}", .{
sub_compilation.local_cache_directory,
sub_compilation.cache_use.whole.bin_sub_path.?,
- emit.directory,
+ emit.root_dir,
emit.sub_path,
@errorName(err),
});
@@ -4403,7 +4402,7 @@ pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest
}
pub const CImportResult = struct {
- out_zig_path: []u8,
+ digest: [Cache.bin_digest_len]u8,
cache_hit: bool,
errors: std.zig.ErrorBundle,
@@ -4413,8 +4412,6 @@ pub const CImportResult = struct {
};
/// Caller owns returned memory.
-/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
-/// a bit when we want to start using it from self-hosted.
pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult {
dev.check(.translate_c_command);
@@ -4503,7 +4500,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
error.OutOfMemory => return error.OutOfMemory,
error.SemanticAnalyzeFail => {
return CImportResult{
- .out_zig_path = "",
+ .digest = undefined,
.cache_hit = actual_hit,
.errors = errors,
};
@@ -4528,8 +4525,9 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
.incremental => {},
}
- const digest = man.final();
- const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
+ const bin_digest = man.finalBin();
+ const hex_digest = Cache.binToHex(bin_digest);
+ const o_sub_path = "o" ++ std.fs.path.sep_str ++ hex_digest;
var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close();
@@ -4541,8 +4539,8 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
try out_zig_file.writeAll(formatted);
- break :digest digest;
- } else man.final();
+ break :digest bin_digest;
+ } else man.finalBin();
if (man.have_exclusive_lock) {
// Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is
@@ -4554,14 +4552,8 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
};
}
- const out_zig_path = try comp.local_cache_directory.join(comp.arena, &.{
- "o", &digest, cimport_zig_basename,
- });
- if (comp.verbose_cimport) {
- log.info("C import output: {s}", .{out_zig_path});
- }
return CImportResult{
- .out_zig_path = out_zig_path,
+ .digest = digest,
.cache_hit = actual_hit,
.errors = std.zig.ErrorBundle.empty,
};
@@ -4800,7 +4792,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
try argv.appendSlice(c_object.src.cache_exempt_flags);
const out_obj_path = if (comp.bin_file) |lf|
- try lf.emit.directory.join(arena, &.{lf.emit.sub_path})
+ try lf.emit.root_dir.join(arena, &.{lf.emit.sub_path})
else
"/dev/null";
diff --git a/src/InternPool.zig b/src/InternPool.zig
index d953755987..83732a29f6 100644
--- a/src/InternPool.zig
+++ b/src/InternPool.zig
@@ -2391,6 +2391,7 @@ pub const Key = union(enum) {
func: Index,
arg_values: []const Index,
result: Index,
+ branch_count: u32,
};
pub fn hash32(key: Key, ip: *const InternPool) u32 {
@@ -6157,6 +6158,7 @@ pub const MemoizedCall = struct {
func: Index,
args_len: u32,
result: Index,
+ branch_count: u32,
};
pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
@@ -6785,6 +6787,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.func = extra.data.func,
.arg_values = @ptrCast(extra_list.view().items(.@"0")[extra.end..][0..extra.data.args_len]),
.result = extra.data.result,
+ .branch_count = extra.data.branch_count,
} };
},
};
@@ -7955,6 +7958,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
.func = memoized_call.func,
.args_len = @intCast(memoized_call.arg_values.len),
.result = memoized_call.result,
+ .branch_count = memoized_call.branch_count,
}),
});
extra.appendSliceAssumeCapacity(.{@ptrCast(memoized_call.arg_values)});
diff --git a/src/Liveness.zig b/src/Liveness.zig
index 4ca28758e2..b75fc402dd 100644
--- a/src/Liveness.zig
+++ b/src/Liveness.zig
@@ -464,6 +464,7 @@ pub fn categorizeOperand(
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> {
const o = air_datas[@intFromEnum(inst)].pl_op.operand;
if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
@@ -1097,6 +1098,7 @@ fn analyzeInst(
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> {
const operand = inst_datas[@intFromEnum(inst)].pl_op.operand;
return analyzeOperands(a, pass, data, inst, .{ operand, .none, .none });
diff --git a/src/Liveness/Verify.zig b/src/Liveness/Verify.zig
index 4392f25e10..7a9959481a 100644
--- a/src/Liveness/Verify.zig
+++ b/src/Liveness/Verify.zig
@@ -157,6 +157,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
},
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
.wasm_memory_grow,
=> {
const pl_op = data[@intFromEnum(inst)].pl_op;
diff --git a/src/Sema.zig b/src/Sema.zig
index c8e2f2ae15..3752cefe3f 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -113,6 +113,11 @@ type_references: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
/// `AnalUnit` multiple times.
dependencies: std.AutoArrayHashMapUnmanaged(InternPool.Dependee, void) = .{},
+/// Whether memoization of this call is permitted. Operations with side effects global
+/// to the `Sema`, such as `@setEvalBranchQuota`, set this to `false`. It is observed
+/// by `analyzeCall`.
+allow_memoize: bool = true,
+
const MaybeComptimeAlloc = struct {
/// The runtime index of the `alloc` instruction.
runtime_index: Value.RuntimeIndex,
@@ -183,6 +188,7 @@ const InternPool = @import("InternPool.zig");
const Alignment = InternPool.Alignment;
const AnalUnit = InternPool.AnalUnit;
const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
+const Cache = std.Build.Cache;
pub const default_branch_quota = 1000;
pub const default_reference_trace_len = 2;
@@ -375,7 +381,7 @@ pub const Block = struct {
c_import_buf: ?*std.ArrayList(u8) = null,
- /// If not `null`, this boolean is set when a `dbg_var_ptr` or `dbg_var_val`
+ /// If not `null`, this boolean is set when a `dbg_var_ptr`, `dbg_var_val`, or `dbg_arg_inline`.
/// instruction is emitted. It signals that the innermost lexically
/// enclosing `block`/`block_inline` should be translated into a real AIR
/// `block` in order for codegen to match lexical scoping for debug vars.
@@ -5523,6 +5529,7 @@ fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
.needed_comptime_reason = "eval branch quota must be comptime-known",
}));
sema.branch_quota = @max(sema.branch_quota, quota);
+ sema.allow_memoize = false;
}
fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
@@ -5871,16 +5878,18 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
return sema.failWithOwnedErrorMsg(&child_block, msg);
}
const parent_mod = parent_block.ownerModule();
+ const digest = Cache.binToHex(c_import_res.digest);
+ const c_import_zig_path = try comp.arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ digest);
const c_import_mod = Package.Module.create(comp.arena, .{
.global_cache_directory = comp.global_cache_directory,
.paths = .{
.root = .{
- .root_dir = Compilation.Directory.cwd(),
- .sub_path = std.fs.path.dirname(c_import_res.out_zig_path) orelse "",
+ .root_dir = comp.local_cache_directory,
+ .sub_path = c_import_zig_path,
},
- .root_src_path = std.fs.path.basename(c_import_res.out_zig_path),
+ .root_src_path = "cimport.zig",
},
- .fully_qualified_name = c_import_res.out_zig_path,
+ .fully_qualified_name = c_import_zig_path,
.cc_argv = parent_mod.cc_argv,
.inherited = .{},
.global = comp.config,
@@ -6413,6 +6422,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
}
zcu.intern_pool.funcMaxStackAlignment(sema.func_index, alignment);
+ sema.allow_memoize = false;
}
fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
@@ -6431,6 +6441,7 @@ fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData)
.cau => return, // does nothing outside a function
};
ip.funcSetCold(func, is_cold);
+ sema.allow_memoize = false;
}
fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
@@ -6442,6 +6453,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
.cau => return, // does nothing outside a function
};
ip.funcSetDisableInstrumentation(func);
+ sema.allow_memoize = false;
}
fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
@@ -6564,7 +6576,7 @@ fn addDbgVar(
const operand_ty = sema.typeOf(operand);
const val_ty = switch (air_tag) {
.dbg_var_ptr => operand_ty.childType(mod),
- .dbg_var_val => operand_ty,
+ .dbg_var_val, .dbg_arg_inline => operand_ty,
else => unreachable,
};
if (try sema.typeRequiresComptime(val_ty)) return;
@@ -6583,25 +6595,26 @@ fn addDbgVar(
if (block.need_debug_scope) |ptr| ptr.* = true;
// Add the name to the AIR.
- const name_extra_index = try sema.appendAirString(name);
+ const name_nts = try sema.appendAirString(name);
_ = try block.addInst(.{
.tag = air_tag,
.data = .{ .pl_op = .{
- .payload = name_extra_index,
+ .payload = @intFromEnum(name_nts),
.operand = operand,
} },
});
}
-pub fn appendAirString(sema: *Sema, str: []const u8) Allocator.Error!u32 {
- const str_extra_index: u32 = @intCast(sema.air_extra.items.len);
+pub fn appendAirString(sema: *Sema, str: []const u8) Allocator.Error!Air.NullTerminatedString {
+ if (str.len == 0) return .none;
+ const nts: Air.NullTerminatedString = @enumFromInt(sema.air_extra.items.len);
const elements_used = str.len / 4 + 1;
const elements = try sema.air_extra.addManyAsSlice(sema.gpa, elements_used);
const buffer = mem.sliceAsBytes(elements);
@memcpy(buffer[0..str.len], str);
buffer[str.len] = 0;
- return str_extra_index;
+ return nts;
}
fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -7585,6 +7598,9 @@ fn analyzeCall(
const module_fn = zcu.funcInfo(module_fn_index);
+ // The call site definitely depends on the function's signature.
+ try sema.declareDependency(.{ .src_hash = module_fn.zir_body_inst });
+
// This is not a function instance, so the function's `Nav` has a
// `Cau` -- we don't need to check `generic_owner`.
const fn_nav = ip.getNav(module_fn.owner_nav);
@@ -7721,101 +7737,121 @@ fn analyzeCall(
} }));
}
- // This `res2` is here instead of directly breaking from `res` due to a stage1
- // bug generating invalid LLVM IR.
- const res2: Air.Inst.Ref = res2: {
- if (should_memoize and is_comptime_call) {
- if (zcu.intern_pool.getIfExists(.{ .memoized_call = .{
+ memoize: {
+ if (!should_memoize) break :memoize;
+ if (!is_comptime_call) break :memoize;
+ const memoized_call_index = ip.getIfExists(.{
+ .memoized_call = .{
.func = module_fn_index,
.arg_values = memoized_arg_values,
- .result = .none,
- } })) |memoized_call_index| {
- const memoized_call = zcu.intern_pool.indexToKey(memoized_call_index).memoized_call;
- break :res2 Air.internedToRef(memoized_call.result);
- }
+ .result = undefined, // ignored by hash+eql
+ .branch_count = undefined, // ignored by hash+eql
+ },
+ }) orelse break :memoize;
+ const memoized_call = ip.indexToKey(memoized_call_index).memoized_call;
+ if (sema.branch_count + memoized_call.branch_count > sema.branch_quota) {
+ // Let the call play out se we get the correct source location for the
+ // "evaluation exceeded X backwards branches" error.
+ break :memoize;
}
+ sema.branch_count += memoized_call.branch_count;
+ break :res Air.internedToRef(memoized_call.result);
+ }
- new_fn_info.return_type = sema.fn_ret_ty.toIntern();
- if (!is_comptime_call and !block.is_typeof) {
- const zir_tags = sema.code.instructions.items(.tag);
- for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) {
- .param, .param_comptime => {
- const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].pl_tok;
- const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
- const param_name = sema.code.nullTerminatedString(extra.data.name);
- const inst = sema.inst_map.get(param).?;
+ // Since we're doing an inline call, we depend on the source code of the whole
+ // function declaration.
+ try sema.declareDependency(.{ .src_hash = fn_cau.zir_index });
- try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
- },
- .param_anytype, .param_anytype_comptime => {
- const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok;
- const param_name = inst_data.get(sema.code);
- const inst = sema.inst_map.get(param).?;
+ new_fn_info.return_type = sema.fn_ret_ty.toIntern();
+ if (!is_comptime_call and !block.is_typeof) {
+ const zir_tags = sema.code.instructions.items(.tag);
+ for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) {
+ .param, .param_comptime => {
+ const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].pl_tok;
+ const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
+ const param_name = sema.code.nullTerminatedString(extra.data.name);
+ const inst = sema.inst_map.get(param).?;
+
+ try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);
+ },
+ .param_anytype, .param_anytype_comptime => {
+ const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok;
+ const param_name = inst_data.get(sema.code);
+ const inst = sema.inst_map.get(param).?;
- try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
- },
- else => continue,
- };
- }
+ try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);
+ },
+ else => continue,
+ };
+ }
- if (is_comptime_call and ensure_result_used) {
- try sema.ensureResultUsed(block, sema.fn_ret_ty, call_src);
- }
+ if (is_comptime_call and ensure_result_used) {
+ try sema.ensureResultUsed(block, sema.fn_ret_ty, call_src);
+ }
- if (is_comptime_call or block.is_typeof) {
- // Save the error trace as our first action in the function
- // to match the behavior of runtime function calls.
- const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);
- sema.error_return_trace_index_on_fn_entry = error_return_trace_index;
- child_block.error_return_trace_index = error_return_trace_index;
- }
+ if (is_comptime_call or block.is_typeof) {
+ // Save the error trace as our first action in the function
+ // to match the behavior of runtime function calls.
+ const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);
+ sema.error_return_trace_index_on_fn_entry = error_return_trace_index;
+ child_block.error_return_trace_index = error_return_trace_index;
+ }
- const result = result: {
- sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) {
- error.ComptimeReturn => break :result inlining.comptime_result,
- else => |e| return e,
- };
- break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);
+ // We temporarily set `allow_memoize` to `true` to track this comptime call.
+ // It is restored after this call finishes analysis, so that a caller may
+ // know whether an in-progress call (containing this call) may be memoized.
+ const old_allow_memoize = sema.allow_memoize;
+ defer sema.allow_memoize = old_allow_memoize and sema.allow_memoize;
+ sema.allow_memoize = true;
+
+ // Store the current eval branch count so we can find out how many eval branches
+ // the comptime call caused.
+ const old_branch_count = sema.branch_count;
+
+ const result = result: {
+ sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) {
+ error.ComptimeReturn => break :result inlining.comptime_result,
+ else => |e| return e,
};
+ break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);
+ };
- if (is_comptime_call) {
- const result_val = try sema.resolveConstValue(block, LazySrcLoc.unneeded, result, undefined);
- const result_interned = result_val.toIntern();
-
- // Transform ad-hoc inferred error set types into concrete error sets.
- const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);
-
- // If the result can mutate comptime vars, we must not memoize it, as it contains
- // a reference to `comptime_allocs` so is not stable across instances of `Sema`.
- // TODO: check whether any external comptime memory was mutated by the
- // comptime function call. If so, then do not memoize the call here.
- if (should_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) {
- _ = try pt.intern(.{ .memoized_call = .{
- .func = module_fn_index,
- .arg_values = memoized_arg_values,
- .result = result_transformed,
- } });
- }
+ if (is_comptime_call) {
+ const result_val = try sema.resolveConstValue(block, LazySrcLoc.unneeded, result, undefined);
+ const result_interned = result_val.toIntern();
- break :res2 Air.internedToRef(result_transformed);
- }
+ // Transform ad-hoc inferred error set types into concrete error sets.
+ const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);
- if (try sema.resolveValue(result)) |result_val| {
- const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());
- break :res2 Air.internedToRef(result_transformed);
+ // If the result can mutate comptime vars, we must not memoize it, as it contains
+ // a reference to `comptime_allocs` so is not stable across instances of `Sema`.
+ // TODO: check whether any external comptime memory was mutated by the
+ // comptime function call. If so, then do not memoize the call here.
+ if (should_memoize and sema.allow_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) {
+ _ = try pt.intern(.{ .memoized_call = .{
+ .func = module_fn_index,
+ .arg_values = memoized_arg_values,
+ .result = result_transformed,
+ .branch_count = sema.branch_count - old_branch_count,
+ } });
}
- const new_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result).toIntern());
- if (new_ty != .none) {
- // TODO: mutate in place the previous instruction if possible
- // rather than adding a bitcast instruction.
- break :res2 try block.addBitCast(Type.fromInterned(new_ty), result);
- }
+ break :res Air.internedToRef(result_transformed);
+ }
- break :res2 result;
- };
+ if (try sema.resolveValue(result)) |result_val| {
+ const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());
+ break :res Air.internedToRef(result_transformed);
+ }
+
+ const new_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result).toIntern());
+ if (new_ty != .none) {
+ // TODO: mutate in place the previous instruction if possible
+ // rather than adding a bitcast instruction.
+ break :res try block.addBitCast(Type.fromInterned(new_ty), result);
+ }
- break :res res2;
+ break :res result;
} else res: {
assert(!func_ty_info.is_generic);
@@ -8263,7 +8299,7 @@ fn instantiateGenericCall(
.name = if (child_block.ownerModule().strip)
.none
else
- @enumFromInt(try sema.appendAirString(fn_zir.nullTerminatedString(param_name))),
+ try sema.appendAirString(fn_zir.nullTerminatedString(param_name)),
} },
}));
try child_block.params.append(sema.arena, .{
diff --git a/src/Type.zig b/src/Type.zig
index 0a37e5a6f5..4437722f7d 100644
--- a/src/Type.zig
+++ b/src/Type.zig
@@ -202,6 +202,7 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
.C => try writer.writeAll("[*c]"),
.Slice => try writer.writeAll("[]"),
}
+ if (info.flags.is_allowzero and info.flags.size != .C) try writer.writeAll("allowzero ");
if (info.flags.alignment != .none or
info.packed_offset.host_size != 0 or
info.flags.vector_index != .none)
@@ -229,7 +230,6 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
}
if (info.flags.is_const) try writer.writeAll("const ");
if (info.flags.is_volatile) try writer.writeAll("volatile ");
- if (info.flags.is_allowzero and info.flags.size != .C) try writer.writeAll("allowzero ");
try print(Type.fromInterned(info.child), writer, pt);
return;
diff --git a/src/Zcu.zig b/src/Zcu.zig
index 53ad80444e..9754740833 100644
--- a/src/Zcu.zig
+++ b/src/Zcu.zig
@@ -2554,18 +2554,29 @@ pub fn mapOldZirToNew(
var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{};
defer match_stack.deinit(gpa);
- // Main struct inst is always matched
- try match_stack.append(gpa, .{
- .old_inst = .main_struct_inst,
- .new_inst = .main_struct_inst,
- });
-
// Used as temporary buffers for namespace declaration instructions
var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
defer old_decls.deinit(gpa);
var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
defer new_decls.deinit(gpa);
+ // Map the main struct inst (and anything in its fields)
+ {
+ try old_zir.findDeclsRoot(gpa, &old_decls);
+ try new_zir.findDeclsRoot(gpa, &new_decls);
+
+ assert(old_decls.items[0] == .main_struct_inst);
+ assert(new_decls.items[0] == .main_struct_inst);
+
+ // We don't have any smart way of matching up these type declarations, so we always
+ // correlate them based on source order.
+ const n = @min(old_decls.items.len, new_decls.items.len);
+ try match_stack.ensureUnusedCapacity(gpa, n);
+ for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
+ match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
+ }
+ }
+
while (match_stack.popOrNull()) |match_item| {
// Match the namespace declaration itself
try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig
index 0db30bfdbd..291518f5f0 100644
--- a/src/Zcu/PerThread.zig
+++ b/src/Zcu/PerThread.zig
@@ -1240,11 +1240,11 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
};
}
- const nav_already_populated, const queue_linker_work = switch (ip.indexToKey(decl_val.toIntern())) {
- .func => |f| .{ f.owner_nav == nav_index, false },
- .variable => |v| .{ false, v.owner_nav == nav_index },
- .@"extern" => .{ false, false },
- else => .{ false, true },
+ const nav_already_populated, const queue_linker_work, const resolve_type = switch (ip.indexToKey(decl_val.toIntern())) {
+ .func => |f| .{ f.owner_nav == nav_index, true, false },
+ .variable => |v| .{ false, v.owner_nav == nav_index, true },
+ .@"extern" => .{ false, false, false },
+ else => .{ false, true, true },
};
if (nav_already_populated) {
@@ -1317,14 +1317,16 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
queue_codegen: {
if (!queue_linker_work) break :queue_codegen;
- // Needed for codegen_nav which will call updateDecl and then the
- // codegen backend wants full access to the Decl Type.
- // We also need this for the `isFnOrHasRuntimeBits` check below.
- // TODO: we could make the language more lenient by deferring this work
- // to the `codegen_nav` job.
- try decl_ty.resolveFully(pt);
+ if (resolve_type) {
+ // Needed for codegen_nav which will call updateDecl and then the
+ // codegen backend wants full access to the Decl Type.
+ // We also need this for the `isFnOrHasRuntimeBits` check below.
+ // TODO: we could make the language more lenient by deferring this work
+ // to the `codegen_nav` job.
+ try decl_ty.resolveFully(pt);
+ }
- if (!decl_ty.isFnOrHasRuntimeBits(pt)) {
+ if (!resolve_type or !decl_ty.hasRuntimeBits(pt)) {
if (zcu.comp.config.use_llvm) break :queue_codegen;
if (file.mod.strip) break :queue_codegen;
}
@@ -2158,7 +2160,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
.name = if (inner_block.ownerModule().strip)
.none
else
- @enumFromInt(try sema.appendAirString(sema.code.nullTerminatedString(param_name))),
+ try sema.appendAirString(sema.code.nullTerminatedString(param_name)),
} },
});
}
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
index cb16dba688..882f3e98e3 100644
--- a/src/arch/aarch64/CodeGen.zig
+++ b/src/arch/aarch64/CodeGen.zig
@@ -170,7 +170,9 @@ const DbgInfoReloc = struct {
fn genDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
switch (reloc.tag) {
- .arg => try reloc.genArgDbgInfo(function),
+ .arg,
+ .dbg_arg_inline,
+ => try reloc.genArgDbgInfo(function),
.dbg_var_ptr,
.dbg_var_val,
@@ -201,7 +203,7 @@ const DbgInfoReloc = struct {
else => unreachable, // not a possible argument
};
- try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
+ try dw.genLocalDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
},
.plan9 => {},
.none => {},
@@ -237,7 +239,7 @@ const DbgInfoReloc = struct {
break :blk .empty;
},
};
- try dwarf.genVarDebugInfo(.local_var, reloc.name, reloc.ty, loc);
+ try dwarf.genLocalDebugInfo(.local_var, reloc.name, reloc.ty, loc);
},
.plan9 => {},
.none => {},
@@ -799,6 +801,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> try self.airDbgVar(inst),
.call => try self.airCall(inst, .auto),
@@ -4220,17 +4223,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const ty = self.typeOfIndex(inst);
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
-
- const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
- if (name_nts != .none) {
- const name = self.air.nullTerminatedString(@intFromEnum(name_nts));
- try self.dbg_info_relocs.append(self.gpa, .{
- .tag = tag,
- .ty = ty,
- .name = name,
- .mcv = self.args[arg_index],
- });
- }
+ const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
+ if (name != .none) try self.dbg_info_relocs.append(self.gpa, .{
+ .tag = tag,
+ .ty = ty,
+ .name = name.toSlice(self.air),
+ .mcv = self.args[arg_index],
+ });
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index];
return self.finishAir(inst, result, .{ .none, .none, .none });
@@ -4644,14 +4643,14 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
const ty = self.typeOf(operand);
const mcv = try self.resolveInst(operand);
- const name = self.air.nullTerminatedString(pl_op.payload);
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv });
try self.dbg_info_relocs.append(self.gpa, .{
.tag = tag,
.ty = ty,
- .name = name,
+ .name = name.toSlice(self.air),
.mcv = mcv,
});
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig
index 6e33b9b51f..796d3e34dc 100644
--- a/src/arch/arm/CodeGen.zig
+++ b/src/arch/arm/CodeGen.zig
@@ -248,7 +248,9 @@ const DbgInfoReloc = struct {
fn genDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
switch (reloc.tag) {
- .arg => try reloc.genArgDbgInfo(function),
+ .arg,
+ .dbg_arg_inline,
+ => try reloc.genArgDbgInfo(function),
.dbg_var_ptr,
.dbg_var_val,
@@ -279,7 +281,7 @@ const DbgInfoReloc = struct {
else => unreachable, // not a possible argument
};
- try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
+ try dw.genLocalDebugInfo(.local_arg, reloc.name, reloc.ty, loc);
},
.plan9 => {},
.none => {},
@@ -315,7 +317,7 @@ const DbgInfoReloc = struct {
break :blk .empty;
},
};
- try dw.genVarDebugInfo(.local_var, reloc.name, reloc.ty, loc);
+ try dw.genLocalDebugInfo(.local_var, reloc.name, reloc.ty, loc);
},
.plan9 => {},
.none => {},
@@ -786,6 +788,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> try self.airDbgVar(inst),
.call => try self.airCall(inst, .auto),
@@ -4199,16 +4202,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const ty = self.typeOfIndex(inst);
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
- const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
- if (name_nts != .none) {
- const name = self.air.nullTerminatedString(@intFromEnum(name_nts));
- try self.dbg_info_relocs.append(self.gpa, .{
- .tag = tag,
- .ty = ty,
- .name = name,
- .mcv = self.args[arg_index],
- });
- }
+ const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
+ if (name != .none) try self.dbg_info_relocs.append(self.gpa, .{
+ .tag = tag,
+ .ty = ty,
+ .name = name.toSlice(self.air),
+ .mcv = self.args[arg_index],
+ });
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index];
return self.finishAir(inst, result, .{ .none, .none, .none });
@@ -4612,14 +4612,14 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
const ty = self.typeOf(operand);
const mcv = try self.resolveInst(operand);
- const name = self.air.nullTerminatedString(pl_op.payload);
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv });
try self.dbg_info_relocs.append(self.gpa, .{
.tag = tag,
.ty = ty,
- .name = name,
+ .name = name.toSlice(self.air),
.mcv = mcv,
});
diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig
index bfbd91ba21..deeb0dc4da 100644
--- a/src/arch/riscv64/CodeGen.zig
+++ b/src/arch/riscv64/CodeGen.zig
@@ -1644,6 +1644,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> try func.airDbgVar(inst),
.dbg_inline_block => try func.airDbgInlineBlock(inst),
@@ -4673,11 +4674,15 @@ fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void {
const arg = func.air.instructions.items(.data)[@intFromEnum(inst)].arg;
const ty = arg.ty.toType();
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.genVarDebugInfo(.local_arg, name, ty, .{ .reg = reg.dwarfNum() }),
+ .register => |reg| try dw.genLocalDebugInfo(
+ .local_arg,
+ arg.name.toSlice(func.air),
+ ty,
+ .{ .reg = reg.dwarfNum() },
+ ),
.load_frame => {},
else => {},
},
@@ -5179,16 +5184,17 @@ fn airDbgVar(func: *Func, inst: Air.Inst.Index) !void {
const operand = pl_op.operand;
const ty = func.typeOf(operand);
const mcv = try func.resolveInst(operand);
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
- const name = func.air.nullTerminatedString(pl_op.payload);
-
- try func.genVarDbgInfo(ty, mcv, name);
+ const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
+ try func.genVarDbgInfo(tag, ty, mcv, name.toSlice(func.air));
return func.finishAir(inst, .unreach, .{ operand, .none, .none });
}
fn genVarDbgInfo(
func: Func,
+ tag: Air.Inst.Tag,
ty: Type,
mcv: MCValue,
name: []const u8,
@@ -5205,7 +5211,11 @@ fn genVarDbgInfo(
break :blk .empty;
},
};
- try dwarf.genVarDebugInfo(.local_var, name, ty, loc);
+ try dwarf.genLocalDebugInfo(switch (tag) {
+ else => unreachable,
+ .dbg_var_ptr, .dbg_var_val => .local_var,
+ .dbg_arg_inline => .local_arg,
+ }, name, ty, loc);
},
.plan9 => {},
.none => {},
diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig
index a4fadad526..258941f19d 100644
--- a/src/arch/riscv64/Emit.zig
+++ b/src/arch/riscv64/Emit.zig
@@ -56,17 +56,17 @@ pub fn emitMir(emit: *Emit) Error!void {
const hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
const lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
- try atom_ptr.addReloc(elf_file, .{
+ try atom_ptr.addReloc(elf_file.base.comp.gpa, .{
.r_offset = start_offset,
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,
.r_addend = 0,
- });
+ }, zo);
- try atom_ptr.addReloc(elf_file, .{
+ try atom_ptr.addReloc(elf_file.base.comp.gpa, .{
.r_offset = start_offset + 4,
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,
.r_addend = 0,
- });
+ }, zo);
},
.load_tlv_reloc => |symbol| {
const elf_file = emit.bin_file.cast(.elf).?;
@@ -76,23 +76,23 @@ pub fn emitMir(emit: *Emit) Error!void {
const R_RISCV = std.elf.R_RISCV;
- try atom_ptr.addReloc(elf_file, .{
+ try atom_ptr.addReloc(elf_file.base.comp.gpa, .{
.r_offset = start_offset,
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_HI20),
.r_addend = 0,
- });
+ }, zo);
- try atom_ptr.addReloc(elf_file, .{
+ try atom_ptr.addReloc(elf_file.base.comp.gpa, .{
.r_offset = start_offset + 4,
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_ADD),
.r_addend = 0,
- });
+ }, zo);
- try atom_ptr.addReloc(elf_file, .{
+ try atom_ptr.addReloc(elf_file.base.comp.gpa, .{
.r_offset = start_offset + 8,
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_LO12_I),
.r_addend = 0,
- });
+ }, zo);
},
.call_extern_fn_reloc => |symbol| {
const elf_file = emit.bin_file.cast(.elf).?;
@@ -101,11 +101,11 @@ pub fn emitMir(emit: *Emit) Error!void {
const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
- try atom_ptr.addReloc(elf_file, .{
+ try atom_ptr.addReloc(elf_file.base.comp.gpa, .{
.r_offset = start_offset,
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
.r_addend = 0,
- });
+ }, zo);
},
};
}
diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig
index a3d3f107a2..99192aa554 100644
--- a/src/arch/sparc64/CodeGen.zig
+++ b/src/arch/sparc64/CodeGen.zig
@@ -643,6 +643,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> try self.airDbgVar(inst),
.call => try self.airCall(inst, .auto),
@@ -1662,7 +1663,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
- const name = self.air.nullTerminatedString(pl_op.payload);
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
const operand = pl_op.operand;
// TODO emit debug info for this variable
_ = name;
@@ -3582,13 +3583,15 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg;
const ty = arg.ty.toType();
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.genVarDebugInfo(.local_arg, name, ty, .{
- .reg = reg.dwarfNum(),
- }),
+ .register => |reg| try dw.genLocalDebugInfo(
+ .local_arg,
+ arg.name.toSlice(self.air),
+ ty,
+ .{ .reg = reg.dwarfNum() },
+ ),
else => {},
},
else => {},
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 33b1fd31c2..d2e9db8062 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1917,8 +1917,9 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.dbg_stmt => func.airDbgStmt(inst),
.dbg_inline_block => func.airDbgInlineBlock(inst),
- .dbg_var_ptr => func.airDbgVar(inst, true),
- .dbg_var_val => func.airDbgVar(inst, false),
+ .dbg_var_ptr => func.airDbgVar(inst, .local_var, true),
+ .dbg_var_val => func.airDbgVar(inst, .local_var, false),
+ .dbg_arg_inline => func.airDbgVar(inst, .local_arg, false),
.call => func.airCall(inst, .auto),
.call_always_tail => func.airCall(inst, .always_tail),
@@ -2585,13 +2586,13 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
switch (func.debug_output) {
.dwarf => |dwarf| {
- const name_nts = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
- if (name_nts != .none) {
- const name = func.air.nullTerminatedString(@intFromEnum(name_nts));
- try dwarf.genVarDebugInfo(.local_arg, name, arg_ty, .{
- .wasm_ext = .{ .local = arg.local.value },
- });
- }
+ const name = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
+ if (name != .none) try dwarf.genLocalDebugInfo(
+ .local_arg,
+ name.toSlice(func.air),
+ arg_ty,
+ .{ .wasm_ext = .{ .local = arg.local.value } },
+ );
},
else => {},
}
@@ -6454,7 +6455,12 @@ fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
try func.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]));
}
-fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void {
+fn airDbgVar(
+ func: *CodeGen,
+ inst: Air.Inst.Index,
+ local_tag: link.File.Dwarf.WipNav.LocalTag,
+ is_ptr: bool,
+) InnerError!void {
_ = is_ptr;
if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{});
@@ -6464,8 +6470,8 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void
log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand });
- const name = func.air.nullTerminatedString(pl_op.payload);
- log.debug(" var name = ({s})", .{name});
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
+ log.debug(" var name = ({s})", .{name.toSlice(func.air)});
const loc: link.File.Dwarf.Loc = switch (operand) {
.local => |local| .{ .wasm_ext = .{ .local = local.value } },
@@ -6474,7 +6480,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void
break :blk .empty;
},
};
- try func.debug_output.dwarf.genVarDebugInfo(.local_var, name, ty, loc);
+ try func.debug_output.dwarf.genLocalDebugInfo(local_tag, name.toSlice(func.air), ty, loc);
return func.finishAir(inst, .none, &.{});
}
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 86fb2bf3e9..316389a7c2 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -59,19 +59,19 @@ owner: Owner,
inline_func: InternPool.Index,
mod: *Package.Module,
err_msg: ?*ErrorMsg,
+arg_index: u32,
args: []MCValue,
va_info: union {
sysv: struct {
gp_count: u32,
fp_count: u32,
- overflow_arg_area: FrameAddr,
- reg_save_area: FrameAddr,
+ overflow_arg_area: bits.FrameAddr,
+ reg_save_area: bits.FrameAddr,
},
win64: struct {},
},
ret_mcv: InstTracking,
fn_type: Type,
-arg_index: u32,
src_loc: Zcu.LazySrcLoc,
eflags_inst: ?Air.Inst.Index = null,
@@ -81,9 +81,6 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
/// MIR extra data
mir_extra: std.ArrayListUnmanaged(u32) = .{},
-stack_args: std.ArrayListUnmanaged(StackVar) = .{},
-stack_vars: std.ArrayListUnmanaged(StackVar) = .{},
-
/// Byte offset within the source file of the ending curly.
end_di_line: u32,
end_di_column: u32,
@@ -113,10 +110,6 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
-const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
-const RegisterOffset = struct { reg: Register, off: i32 = 0 };
-const SymbolOffset = struct { sym: u32, off: i32 = 0 };
-
const Owner = union(enum) {
nav_index: InternPool.Nav.Index,
lazy_sym: link.File.LazySymbol,
@@ -174,7 +167,7 @@ pub const MCValue = union(enum) {
/// The value is split across two registers.
register_pair: [2]Register,
/// The value is a constant offset from the value in a register.
- register_offset: RegisterOffset,
+ register_offset: bits.RegisterOffset,
/// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
register_overflow: struct { reg: Register, eflags: Condition },
/// The value is in memory at a hard-coded address.
@@ -182,11 +175,11 @@ pub const MCValue = union(enum) {
memory: u64,
/// The value is in memory at an address not-yet-allocated by the linker.
/// This traditionally corresponds to a relocation emitted in a relocatable object file.
- load_symbol: SymbolOffset,
+ load_symbol: bits.SymbolOffset,
/// The address of the memory location not-yet-allocated by the linker.
- lea_symbol: SymbolOffset,
+ lea_symbol: bits.SymbolOffset,
/// The value is in memory at a constant offset from the address in a register.
- indirect: RegisterOffset,
+ indirect: bits.RegisterOffset,
/// The value is in memory.
/// Payload is a symbol index.
load_direct: u32,
@@ -207,10 +200,10 @@ pub const MCValue = union(enum) {
lea_tlv: u32,
/// The value stored at an offset from a frame index
/// Payload is a frame address.
- load_frame: FrameAddr,
+ load_frame: bits.FrameAddr,
/// The address of an offset from a frame index
/// Payload is a frame address.
- lea_frame: FrameAddr,
+ lea_frame: bits.FrameAddr,
/// Supports integer_per_element abi
elementwise_regs_then_frame: packed struct { regs: u3 = 0, frame_off: i29 = 0, frame_index: FrameIndex },
/// This indicates that we have already allocated a frame index for this instruction,
@@ -426,10 +419,7 @@ pub const MCValue = union(enum) {
.load_symbol => |sym_off| {
assert(sym_off.off == 0);
return .{
- .base = .{ .reloc = .{
- .atom_index = try function.owner.getSymbolIndex(function),
- .sym_index = sym_off.sym,
- } },
+ .base = .{ .reloc = sym_off.sym_index },
.mod = .{ .rm = .{
.size = size,
.disp = sym_off.off,
@@ -456,8 +446,8 @@ pub const MCValue = union(enum) {
.register_overflow => |pl| try writer.print("{s}:{s}", .{
@tagName(pl.eflags), @tagName(pl.reg),
}),
- .load_symbol => |pl| try writer.print("[{} + 0x{x}]", .{ pl.sym, pl.off }),
- .lea_symbol => |pl| try writer.print("{} + 0x{x}", .{ pl.sym, pl.off }),
+ .load_symbol => |pl| try writer.print("[{} + 0x{x}]", .{ pl.sym_index, pl.off }),
+ .lea_symbol => |pl| try writer.print("{} + 0x{x}", .{ pl.sym_index, pl.off }),
.indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
.load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
.lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
@@ -728,12 +718,6 @@ const InstTracking = struct {
}
};
-const StackVar = struct {
- name: []const u8,
- type: Type,
- frame_addr: FrameAddr,
-};
-
const FrameAlloc = struct {
abi_size: u31,
spill_pad: u3,
@@ -818,11 +802,11 @@ pub fn generate(
.owner = .{ .nav_index = func.owner_nav },
.inline_func = func_index,
.err_msg = null,
+ .arg_index = undefined,
.args = undefined, // populated after `resolveCallingConventionValues`
.va_info = undefined, // populated after `resolveCallingConventionValues`
.ret_mcv = undefined, // populated after `resolveCallingConventionValues`
.fn_type = fn_type,
- .arg_index = 0,
.src_loc = src_loc,
.end_di_line = func.rbrace_line,
.end_di_column = func.rbrace_column,
@@ -839,8 +823,6 @@ pub fn generate(
function.exitlude_jump_relocs.deinit(gpa);
function.mir_instructions.deinit(gpa);
function.mir_extra.deinit(gpa);
- function.stack_args.deinit(gpa);
- function.stack_vars.deinit(gpa);
}
wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
@@ -895,6 +877,7 @@ pub fn generate(
}),
);
function.va_info = switch (cc) {
+ else => undefined,
.SysV => .{ .sysv = .{
.gp_count = call_info.gp_count,
.fp_count = call_info.fp_count,
@@ -902,7 +885,6 @@ pub fn generate(
.reg_save_area = undefined,
} },
.Win64 => .{ .win64 = .{} },
- else => undefined,
};
function.gen() catch |err| switch (err) {
@@ -913,9 +895,6 @@ pub fn generate(
else => |e| return e,
};
- try function.genStackVarDebugInfo(.local_arg, function.stack_args.items);
- try function.genStackVarDebugInfo(.local_var, function.stack_vars.items);
-
var mir: Mir = .{
.instructions = function.mir_instructions.toOwnedSlice(),
.extra = try function.mir_extra.toOwnedSlice(gpa),
@@ -924,6 +903,7 @@ pub fn generate(
defer mir.deinit(gpa);
var emit: Emit = .{
+ .air = function.air,
.lower = .{
.bin_file = bin_file,
.allocator = gpa,
@@ -934,6 +914,13 @@ pub fn generate(
.link_mode = comp.config.link_mode,
.pic = mod.pic,
},
+ .atom_index = function.owner.getSymbolIndex(&function) 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.", .{}),
+ },
+ else => |e| return e,
+ },
.debug_output = debug_output,
.code = code,
.prev_di_pc = 0,
@@ -991,11 +978,11 @@ pub fn generateLazy(
.owner = .{ .lazy_sym = lazy_sym },
.inline_func = undefined,
.err_msg = null,
+ .arg_index = undefined,
.args = undefined,
.va_info = undefined,
.ret_mcv = undefined,
.fn_type = undefined,
- .arg_index = undefined,
.src_loc = src_loc,
.end_di_line = undefined, // no debug info yet
.end_di_column = undefined, // no debug info yet
@@ -1013,14 +1000,15 @@ pub fn generateLazy(
else => |e| return e,
};
- var mir = Mir{
+ var mir: Mir = .{
.instructions = function.mir_instructions.toOwnedSlice(),
.extra = try function.mir_extra.toOwnedSlice(gpa),
.frame_locs = function.frame_locs.toOwnedSlice(),
};
defer mir.deinit(gpa);
- var emit = Emit{
+ var emit: Emit = .{
+ .air = function.air,
.lower = .{
.bin_file = bin_file,
.allocator = gpa,
@@ -1031,6 +1019,13 @@ pub fn generateLazy(
.link_mode = comp.config.link_mode,
.pic = mod.pic,
},
+ .atom_index = function.owner.getSymbolIndex(&function) 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.", .{}),
+ },
+ else => |e| return e,
+ },
.debug_output = debug_output,
.code = code,
.prev_di_pc = undefined, // no debug info yet
@@ -1116,7 +1111,7 @@ fn formatWipMir(
) @TypeOf(writer).Error!void {
const comp = data.self.bin_file.comp;
const mod = comp.root_mod;
- var lower = Lower{
+ var lower: Lower = .{
.bin_file = data.self.bin_file,
.allocator = data.self.gpa,
.mir = .{
@@ -1204,6 +1199,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
self.mir_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
i32, Mir.Memory.Info => @bitCast(@field(extra, field.name)),
+ bits.FrameIndex => @intFromEnum(@field(extra, field.name)),
else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
});
}
@@ -1357,6 +1353,124 @@ fn asmPlaceholder(self: *Self) !Mir.Inst.Index {
});
}
+const MirTagAir = enum { dbg_local };
+
+fn asmAir(self: *Self, tag: MirTagAir, inst: Air.Inst.Index) !void {
+ _ = try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_a,
+ },
+ .data = .{ .a = .{ .air_inst = inst } },
+ });
+}
+
+fn asmAirImmediate(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, imm: Immediate) !void {
+ switch (imm) {
+ .signed => |s| _ = try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_ai_s,
+ },
+ .data = .{ .ai = .{
+ .air_inst = inst,
+ .i = @bitCast(s),
+ } },
+ }),
+ .unsigned => |u| _ = if (math.cast(u32, u)) |small| try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_ai_u,
+ },
+ .data = .{ .ai = .{
+ .air_inst = inst,
+ .i = small,
+ } },
+ }) else try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_ai_64,
+ },
+ .data = .{ .ai = .{
+ .air_inst = inst,
+ .i = try self.addExtra(Mir.Imm64.encode(u)),
+ } },
+ }),
+ .reloc => |sym_off| _ = if (sym_off.off == 0) try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_as,
+ },
+ .data = .{ .as = .{
+ .air_inst = inst,
+ .sym_index = sym_off.sym_index,
+ } },
+ }) else try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_aso,
+ },
+ .data = .{ .ax = .{
+ .air_inst = inst,
+ .payload = try self.addExtra(sym_off),
+ } },
+ }),
+ }
+}
+
+fn asmAirRegisterImmediate(
+ self: *Self,
+ tag: MirTagAir,
+ inst: Air.Inst.Index,
+ reg: Register,
+ imm: Immediate,
+) !void {
+ _ = try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_aro,
+ },
+ .data = .{ .rx = .{
+ .r1 = reg,
+ .payload = try self.addExtra(Mir.AirOffset{
+ .air_inst = inst,
+ .off = imm.signed,
+ }),
+ } },
+ });
+}
+
+fn asmAirFrameAddress(
+ self: *Self,
+ tag: MirTagAir,
+ inst: Air.Inst.Index,
+ frame_addr: bits.FrameAddr,
+) !void {
+ _ = try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_af,
+ },
+ .data = .{ .ax = .{
+ .air_inst = inst,
+ .payload = try self.addExtra(frame_addr),
+ } },
+ });
+}
+
+fn asmAirMemory(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, m: Memory) !void {
+ _ = try self.addInst(.{
+ .tag = .pseudo,
+ .ops = switch (tag) {
+ .dbg_local => .pseudo_dbg_local_am,
+ },
+ .data = .{ .ax = .{
+ .air_inst = inst,
+ .payload = try self.addExtra(Mir.Memory.encode(m)),
+ } },
+ });
+}
+
fn asmOpOnly(self: *Self, tag: Mir.Inst.FixedTag) !void {
_ = try self.addInst(.{
.tag = tag[1],
@@ -1368,6 +1482,8 @@ fn asmOpOnly(self: *Self, tag: Mir.Inst.FixedTag) !void {
}
fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void {
+ assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
+ std.mem.endsWith(u8, @tagName(ops), "_none"));
_ = try self.addInst(.{
.tag = .pseudo,
.ops = ops,
@@ -1395,9 +1511,9 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void {
.reloc => .rel,
},
.data = switch (imm) {
- .reloc => |x| reloc: {
+ .reloc => |sym_off| reloc: {
assert(tag[0] == ._);
- break :reloc .{ .reloc = x };
+ break :reloc .{ .reloc = sym_off };
},
.signed, .unsigned => .{ .i = .{
.fixes = tag[0],
@@ -1424,31 +1540,22 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.FixedTag, reg1: Register, reg2
}
fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: Immediate) !void {
- const ops: Mir.Inst.Ops = switch (imm) {
- .signed => .ri_s,
- .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
+ const ops: Mir.Inst.Ops, const i: u32 = switch (imm) {
+ .signed => |s| .{ .ri_s, @bitCast(s) },
+ .unsigned => |u| if (math.cast(u32, u)) |small|
+ .{ .ri_u, small }
+ else
+ .{ .ri_64, try self.addExtra(Mir.Imm64.encode(imm.unsigned)) },
.reloc => unreachable,
};
_ = try self.addInst(.{
.tag = tag[1],
.ops = ops,
- .data = switch (ops) {
- .ri_s, .ri_u => .{ .ri = .{
- .fixes = tag[0],
- .r1 = reg,
- .i = switch (imm) {
- .signed => |s| @bitCast(s),
- .unsigned => |u| @intCast(u),
- .reloc => unreachable,
- },
- } },
- .ri64 => .{ .rx = .{
- .fixes = tag[0],
- .r1 = reg,
- .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
- } },
- else => unreachable,
- },
+ .data = .{ .ri = .{
+ .fixes = tag[0],
+ .r1 = reg,
+ .i = i,
+ } },
});
}
@@ -1996,6 +2103,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
const ip = &mod.intern_pool;
const air_tags = self.air.instructions.items(.tag);
+ self.arg_index = 0;
for (body) |inst| {
wip_mir_log.debug("{}", .{self.fmtAir(inst)});
verbose_tracking_log.debug("{}", .{self.fmtTracking()});
@@ -2009,6 +2117,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping);
}
+ if (self.arg_index == 0) try self.airDbgVarArgs();
+ self.arg_index = 0;
for (body) |inst| {
if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
wip_mir_log.debug("{}", .{self.fmtAir(inst)});
@@ -2158,6 +2268,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> try self.airDbgVar(inst),
.call => try self.airCall(inst, .auto),
@@ -2485,12 +2596,12 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo
};
}
-fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) Alignment {
+fn getFrameAddrAlignment(self: *Self, frame_addr: bits.FrameAddr) Alignment {
const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align;
return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off)));
}
-fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 {
+fn getFrameAddrSize(self: *Self, frame_addr: bits.FrameAddr) u32 {
return self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_size - @as(u31, @intCast(frame_addr.off));
}
@@ -11949,89 +12060,81 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
}
fn airDbgArg(self: *Self, inst: Air.Inst.Index) !void {
- defer self.finishAirBookkeeping();
- if (self.debug_output == .none) return;
- const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
- const name = self.air.nullTerminatedString(@intFromEnum(name_nts));
- if (name.len > 0) {
- const arg_ty = self.typeOfIndex(inst);
- const arg_mcv = self.getResolvedInstValue(inst).short;
- try self.genVarDebugInfo(.local_arg, .dbg_var_val, name, arg_ty, arg_mcv);
+ // skip zero-bit arguments as they don't have a corresponding arg instruction
+ var arg_index = self.arg_index;
+ while (self.args[arg_index] == .none) arg_index += 1;
+ self.arg_index = arg_index + 1;
+
+ if (self.debug_output != .none) {
+ const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
+ if (name != .none) try self.genLocalDebugInfo(inst, self.getResolvedInstValue(inst).short);
+ if (self.liveness.isUnused(inst)) try self.processDeath(inst);
}
- if (self.liveness.isUnused(inst)) try self.processDeath(inst);
+ for (self.args[self.arg_index..]) |arg| {
+ if (arg != .none) break;
+ } else try self.airDbgVarArgs();
+ self.finishAirBookkeeping();
+}
+
+fn airDbgVarArgs(self: *Self) !void {
+ if (self.pt.zcu.typeToFunc(self.fn_type).?.is_var_args)
+ try self.asmPseudo(.pseudo_dbg_var_args_none);
}
-fn genVarDebugInfo(
+fn genLocalDebugInfo(
self: *Self,
- var_tag: link.File.Dwarf.WipNav.VarTag,
- tag: Air.Inst.Tag,
- name: []const u8,
- ty: Type,
+ inst: Air.Inst.Index,
mcv: MCValue,
) !void {
- const stack_vars = switch (var_tag) {
- .local_arg => &self.stack_args,
- .local_var => &self.stack_vars,
- };
- switch (self.debug_output) {
- .dwarf => |dwarf| switch (tag) {
- else => unreachable,
- .dbg_var_ptr => {
- const var_ty = ty.childType(self.pt.zcu);
- switch (mcv) {
- else => {
- log.info("dbg_var_ptr({s}({}))", .{ @tagName(mcv), mcv });
- unreachable;
- },
- .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
- .lea_frame => |frame_addr| try stack_vars.append(self.gpa, .{
- .name = name,
- .type = var_ty,
- .frame_addr = frame_addr,
- }),
- .lea_symbol => |sym_off| try dwarf.genVarDebugInfo(var_tag, name, var_ty, .{ .plus = .{
- &.{ .addr = .{ .sym = sym_off.sym } },
- &.{ .consts = sym_off.off },
- } }),
- }
- },
- .dbg_var_val => switch (mcv) {
- .none => try dwarf.genVarDebugInfo(var_tag, name, ty, .empty),
+ if (self.debug_output == .none) return;
+ switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) {
+ else => unreachable,
+ .arg, .dbg_arg_inline, .dbg_var_val => |tag| {
+ switch (mcv) {
+ .none => try self.asmAir(.dbg_local, inst),
.unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
- .immediate => |immediate| try dwarf.genVarDebugInfo(var_tag, name, ty, .{ .stack_value = &.{
- .constu = immediate,
- } }),
+ .immediate => |imm| try self.asmAirImmediate(.dbg_local, inst, Immediate.u(imm)),
+ .lea_frame => |frame_addr| try self.asmAirFrameAddress(.dbg_local, inst, frame_addr),
+ .lea_symbol => |sym_off| try self.asmAirImmediate(.dbg_local, inst, Immediate.rel(sym_off)),
else => {
+ const ty = switch (tag) {
+ else => unreachable,
+ .arg => self.typeOfIndex(inst),
+ .dbg_arg_inline, .dbg_var_val => self.typeOf(
+ self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op.operand,
+ ),
+ };
const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ty, self.pt));
try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{});
- try stack_vars.append(self.gpa, .{
- .name = name,
- .type = ty,
- .frame_addr = .{ .index = frame_index },
+ try self.asmAirMemory(.dbg_local, inst, .{
+ .base = .{ .frame = frame_index },
+ .mod = .{ .rm = .{ .size = .qword } },
});
},
- },
+ }
},
- .plan9 => {},
- .none => {},
- }
-}
-
-fn genStackVarDebugInfo(
- self: Self,
- var_tag: link.File.Dwarf.WipNav.VarTag,
- stack_vars: []const StackVar,
-) !void {
- switch (self.debug_output) {
- .dwarf => |dwarf| for (stack_vars) |stack_var| {
- const frame_loc = self.frame_locs.get(@intFromEnum(stack_var.frame_addr.index));
- try dwarf.genVarDebugInfo(var_tag, stack_var.name, stack_var.type, .{ .plus = .{
- &.{ .breg = frame_loc.base.dwarfNum() },
- &.{ .consts = @as(i33, frame_loc.disp) + stack_var.frame_addr.off },
- } });
+ .dbg_var_ptr => switch (mcv) {
+ else => unreachable,
+ .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
+ .lea_frame => |frame_addr| try self.asmAirMemory(.dbg_local, inst, .{
+ .base = .{ .frame = frame_addr.index },
+ .mod = .{ .rm = .{
+ .size = .qword,
+ .disp = frame_addr.off,
+ } },
+ }),
+ .lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
+ .base = .{ .reloc = sym_off.sym_index },
+ .mod = .{ .rm = .{
+ .size = .qword,
+ .disp = sym_off.off,
+ } },
+ }),
+ .lea_direct, .lea_got, .lea_tlv => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{
+ .base = .{ .reloc = sym_index },
+ .mod = .{ .rm = .{ .size = .qword } },
+ }),
},
- .plan9 => {},
- .none => {},
}
}
@@ -12351,10 +12454,7 @@ fn genCall(self: *Self, info: union(enum) {
if (self.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
- try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = sym_index,
- }));
+ try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym_index }));
} 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().?;
@@ -12364,10 +12464,7 @@ fn genCall(self: *Self, info: union(enum) {
const zo = macho_file.getZigObject().?;
const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav);
const sym = zo.symbols.items[sym_index];
- try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = sym.nlist_idx,
- }));
+ try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym.nlist_idx }));
} else if (self.bin_file.cast(.plan9)) |p9| {
const atom_index = try p9.seeNav(pt, func.owner_nav);
const atom = p9.getAtom(atom_index);
@@ -12385,19 +12482,13 @@ fn genCall(self: *Self, info: union(enum) {
@"extern".name.toSlice(ip),
@"extern".lib_name.toSlice(ip),
);
- try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = target_sym_index,
- }));
+ try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index }));
} else if (self.bin_file.cast(.macho)) |macho_file| {
const target_sym_index = try macho_file.getGlobalSymbol(
@"extern".name.toSlice(ip),
@"extern".lib_name.toSlice(ip),
);
- try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = target_sym_index,
- }));
+ try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index }));
} else try self.genExternSymbolRef(
.call,
@"extern".lib_name.toSlice(ip),
@@ -12412,16 +12503,10 @@ fn genCall(self: *Self, info: union(enum) {
},
.lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| {
const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib);
- try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = target_sym_index,
- }));
+ try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index }));
} else if (self.bin_file.cast(.macho)) |macho_file| {
const target_sym_index = try macho_file.getGlobalSymbol(lib.callee, lib.lib);
- try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = target_sym_index,
- }));
+ try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index }));
} else try self.genExternSymbolRef(.call, lib.lib, lib.callee),
}
return call_info.return_value.short;
@@ -13060,29 +13145,21 @@ fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
self.inline_func = extra.data.func;
_ = try self.addInst(.{
.tag = .pseudo,
- .ops = .pseudo_dbg_inline_func,
+ .ops = .pseudo_dbg_enter_inline_func,
.data = .{ .func = extra.data.func },
});
try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
_ = try self.addInst(.{
.tag = .pseudo,
- .ops = .pseudo_dbg_inline_func,
+ .ops = .pseudo_dbg_leave_inline_func,
.data = .{ .func = old_inline_func },
});
}
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
- const operand = pl_op.operand;
- const ty = self.typeOf(operand);
- const mcv = try self.resolveInst(operand);
-
- const name = self.air.nullTerminatedString(pl_op.payload);
-
- const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
- try self.genVarDebugInfo(.local_var, tag, name, ty, mcv);
-
- return self.finishAir(inst, .unreach, .{ operand, .none, .none });
+ try self.genLocalDebugInfo(inst, try self.resolveInst(pl_op.operand));
+ return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });
}
fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index {
@@ -14970,10 +15047,7 @@ fn genSetReg(
.general_purpose => {
assert(sym_off.off == 0);
try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(dst_reg, abi_size), .{
- .base = .{ .reloc = .{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = sym_off.sym,
- } },
+ .base = .{ .reloc = sym_off.sym_index },
.mod = .{ .rm = .{
.size = self.memSize(ty),
.disp = sym_off.off,
@@ -14991,10 +15065,7 @@ fn genSetReg(
.ops = .direct_reloc,
.data = .{ .rx = .{
.r1 = registerAlias(dst_reg, abi_size),
- .payload = try self.addExtra(bits.Symbol{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = sym_index,
- }),
+ .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }),
} },
});
return;
@@ -15019,52 +15090,38 @@ fn genSetReg(
},
);
},
- .lea_symbol => |sym_index| {
- const atom_index = try self.owner.getSymbolIndex(self);
- switch (self.bin_file.tag) {
- .elf, .macho => {
- try self.asmRegisterMemory(
- .{ ._, .lea },
- dst_reg.to64(),
- .{
- .base = .{ .reloc = .{
- .atom_index = atom_index,
- .sym_index = sym_index.sym,
- } },
- .mod = .{ .rm = .{
- .size = .qword,
- .disp = sym_index.off,
- } },
- },
- );
- },
- else => return self.fail("TODO emit symbol sequence on {s}", .{
- @tagName(self.bin_file.tag),
- }),
- }
- },
- .lea_direct, .lea_got => |sym_index| {
- const atom_index = try self.owner.getSymbolIndex(self);
- _ = try self.addInst(.{
- .tag = switch (src_mcv) {
- .lea_direct => .lea,
- .lea_got => .mov,
- else => unreachable,
- },
- .ops = switch (src_mcv) {
- .lea_direct => .direct_reloc,
- .lea_got => .got_reloc,
- else => unreachable,
+ .lea_symbol => |sym_off| switch (self.bin_file.tag) {
+ .elf, .macho => try self.asmRegisterMemory(
+ .{ ._, .lea },
+ dst_reg.to64(),
+ .{
+ .base = .{ .reloc = sym_off.sym_index },
+ .mod = .{ .rm = .{
+ .size = .qword,
+ .disp = sym_off.off,
+ } },
},
- .data = .{ .rx = .{
- .r1 = dst_reg.to64(),
- .payload = try self.addExtra(bits.Symbol{
- .atom_index = atom_index,
- .sym_index = sym_index,
- }),
- } },
- });
+ ),
+ else => return self.fail("TODO emit symbol sequence on {s}", .{
+ @tagName(self.bin_file.tag),
+ }),
},
+ .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{
+ .tag = switch (src_mcv) {
+ .lea_direct => .lea,
+ .lea_got => .mov,
+ else => unreachable,
+ },
+ .ops = switch (src_mcv) {
+ .lea_direct => .direct_reloc,
+ .lea_got => .got_reloc,
+ else => unreachable,
+ },
+ .data = .{ .rx = .{
+ .r1 = dst_reg.to64(),
+ .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }),
+ } },
+ }),
.lea_tlv => unreachable, // TODO: remove this
.air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts),
}
@@ -15085,7 +15142,7 @@ fn genSetMem(
.none => .{ .immediate = @bitCast(@as(i64, disp)) },
.reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },
.frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
- .reloc => |base_symbol| .{ .lea_symbol = .{ .sym = base_symbol.sym_index, .off = disp } },
+ .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
};
switch (src_mcv) {
.none,
@@ -15328,7 +15385,6 @@ fn genExternSymbolRef(
lib: ?[]const u8,
callee: []const u8,
) InnerError!void {
- const atom_index = try self.owner.getSymbolIndex(self);
if (self.bin_file.cast(.coff)) |coff_file| {
const global_index = try coff_file.getGlobalSymbol(callee, lib);
_ = try self.addInst(.{
@@ -15336,8 +15392,7 @@ fn genExternSymbolRef(
.ops = .import_reloc,
.data = .{ .rx = .{
.r1 = .rax,
- .payload = try self.addExtra(bits.Symbol{
- .atom_index = atom_index,
+ .payload = try self.addExtra(bits.SymbolOffset{
.sym_index = link.File.Coff.global_symbol_bit | global_index,
}),
} },
@@ -15364,10 +15419,10 @@ fn genLazySymbolRef(
if (self.mod.pic) {
switch (tag) {
.lea, .call => try self.genSetReg(reg, Type.usize, .{
- .lea_symbol = .{ .sym = sym_index },
+ .lea_symbol = .{ .sym_index = sym_index },
}, .{}),
.mov => try self.genSetReg(reg, Type.usize, .{
- .load_symbol = .{ .sym = sym_index },
+ .load_symbol = .{ .sym_index = sym_index },
}, .{}),
else => unreachable,
}
@@ -15376,19 +15431,13 @@ fn genLazySymbolRef(
.call => try self.asmRegister(.{ ._, .call }, reg),
else => unreachable,
}
- } else {
- const reloc = bits.Symbol{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = sym_index,
- };
- switch (tag) {
- .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{
- .base = .{ .reloc = reloc },
- .mod = .{ .rm = .{ .size = .qword } },
- }),
- .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(reloc)),
- else => unreachable,
- }
+ } else switch (tag) {
+ .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{
+ .base = .{ .reloc = sym_index },
+ .mod = .{ .rm = .{ .size = .qword } },
+ }),
+ .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym_index })),
+ else => unreachable,
}
} else if (self.bin_file.cast(.plan9)) |p9_file| {
const atom_index = p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
@@ -15438,10 +15487,10 @@ fn genLazySymbolRef(
const sym = zo.symbols.items[sym_index];
switch (tag) {
.lea, .call => try self.genSetReg(reg, Type.usize, .{
- .lea_symbol = .{ .sym = sym.nlist_idx },
+ .lea_symbol = .{ .sym_index = sym.nlist_idx },
}, .{}),
.mov => try self.genSetReg(reg, Type.usize, .{
- .load_symbol = .{ .sym = sym.nlist_idx },
+ .load_symbol = .{ .sym_index = sym.nlist_idx },
}, .{}),
else => unreachable,
}
@@ -18786,7 +18835,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
.{ .frame = frame_index },
0,
Type.usize,
- .{ .lea_symbol = .{ .sym = tlv_sym } },
+ .{ .lea_symbol = .{ .sym_index = tlv_sym } },
.{},
);
break :init .{ .load_frame = .{ .index = frame_index } };
@@ -18842,8 +18891,8 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
.undef => .undef,
.immediate => |imm| .{ .immediate = imm },
.memory => |addr| .{ .memory = addr },
- .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
- .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
+ .load_symbol => |sym_index| .{ .load_symbol = .{ .sym_index = sym_index } },
+ .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index } },
.load_direct => |sym_index| .{ .load_direct = sym_index },
.lea_direct => |sym_index| .{ .lea_direct = sym_index },
.load_got => |sym_index| .{ .lea_got = sym_index },
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index f168464f6f..0461ce245a 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -1,6 +1,8 @@
//! This file contains the functionality for emitting x86_64 MIR as machine code
+air: Air,
lower: Lower,
+atom_index: u32,
debug_output: DebugInfoOutput,
code: *std.ArrayList(u8),
@@ -36,108 +38,109 @@ pub fn emitMir(emit: *Emit) Error!void {
}) switch (lowered_relocs[0].target) {
.inst => |target| try emit.relocs.append(emit.lower.allocator, .{
.source = start_offset,
+ .source_offset = end_offset - 4,
.target = target,
- .offset = end_offset - 4,
+ .target_offset = lowered_relocs[0].off,
.length = @intCast(end_offset - start_offset),
}),
- .linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
+ .linker_extern_fn => |sym_index| 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).?;
+ const atom_ptr = zo.symbol(emit.atom_index).atom(elf_file).?;
const r_type = @intFromEnum(std.elf.R_X86_64.PLT32);
- try atom_ptr.addReloc(elf_file, .{
+ try atom_ptr.addReloc(elf_file.base.comp.gpa, .{
.r_offset = end_offset - 4,
- .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
- .r_addend = -4,
- });
+ .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+ .r_addend = lowered_relocs[0].off - 4,
+ }, zo);
} 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).?;
+ const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
try atom.addReloc(macho_file, .{
.tag = .@"extern",
.offset = end_offset - 4,
- .target = symbol.sym_index,
- .addend = 0,
+ .target = sym_index,
+ .addend = lowered_relocs[0].off,
.type = .branch,
.meta = .{
.pcrel = true,
.has_subtractor = false,
.length = 2,
- .symbolnum = @intCast(symbol.sym_index),
+ .symbolnum = @intCast(sym_index),
},
});
} 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 },
+ .{ .sym_index = emit.atom_index, .file = null },
).?;
- const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0)
- coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index)
+ const target = if (link.File.Coff.global_symbol_bit & sym_index != 0)
+ coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index)
else
- link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null };
+ link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null };
try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
.type = .direct,
.target = target,
.offset = end_offset - 4,
- .addend = 0,
+ .addend = @intCast(lowered_relocs[0].off),
.pcrel = true,
.length = 2,
});
} else return emit.fail("TODO implement extern reloc for {s}", .{
@tagName(emit.lower.bin_file.tag),
}),
- .linker_tlsld => |data| {
+ .linker_tlsld => |sym_index| {
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 atom = zo.symbol(emit.atom_index).atom(elf_file).?;
const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD);
- try atom.addReloc(elf_file, .{
+ try atom.addReloc(elf_file.base.comp.gpa, .{
.r_offset = end_offset - 4,
- .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
- .r_addend = -4,
- });
+ .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+ .r_addend = lowered_relocs[0].off - 4,
+ }, zo);
},
- .linker_dtpoff => |data| {
+ .linker_dtpoff => |sym_index| {
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 atom = zo.symbol(emit.atom_index).atom(elf_file).?;
const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32);
- try atom.addReloc(elf_file, .{
+ try atom.addReloc(elf_file.base.comp.gpa, .{
.r_offset = end_offset - 4,
- .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
- .r_addend = 0,
- });
+ .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+ .r_addend = lowered_relocs[0].off,
+ }, zo);
},
- .linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
+ .linker_reloc => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
- const atom = zo.symbol(data.atom_index).atom(elf_file).?;
- const sym = zo.symbol(data.sym_index);
+ const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
+ const sym = zo.symbol(sym_index);
if (emit.lower.pic) {
const r_type: u32 = if (sym.flags.is_extern_ptr)
@intFromEnum(std.elf.R_X86_64.GOTPCREL)
else
@intFromEnum(std.elf.R_X86_64.PC32);
- try atom.addReloc(elf_file, .{
+ try atom.addReloc(elf_file.base.comp.gpa, .{
.r_offset = end_offset - 4,
- .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
- .r_addend = -4,
- });
+ .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+ .r_addend = lowered_relocs[0].off - 4,
+ }, zo);
} else {
const r_type: u32 = if (sym.flags.is_tls)
@intFromEnum(std.elf.R_X86_64.TPOFF32)
else
@intFromEnum(std.elf.R_X86_64.@"32");
- try atom.addReloc(elf_file, .{
+ try atom.addReloc(elf_file.base.comp.gpa, .{
.r_offset = end_offset - 4,
- .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
- .r_addend = 0,
- });
+ .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+ .r_addend = lowered_relocs[0].off,
+ }, zo);
}
} else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?;
- const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?;
- const sym = &zo.symbols.items[data.sym_index];
+ const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
+ const sym = &zo.symbols.items[sym_index];
const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr)
.got_load
else if (sym.flags.tlv)
@@ -147,33 +150,33 @@ pub fn emitMir(emit: *Emit) Error!void {
try atom.addReloc(macho_file, .{
.tag = .@"extern",
.offset = @intCast(end_offset - 4),
- .target = data.sym_index,
- .addend = 0,
+ .target = sym_index,
+ .addend = lowered_relocs[0].off,
.type = @"type",
.meta = .{
.pcrel = true,
.has_subtractor = false,
.length = 2,
- .symbolnum = @intCast(data.sym_index),
+ .symbolnum = @intCast(sym_index),
},
});
} else unreachable,
.linker_got,
.linker_direct,
.linker_import,
- => |symbol| if (emit.lower.bin_file.cast(.elf)) |_| {
+ => |sym_index| if (emit.lower.bin_file.cast(.elf)) |_| {
unreachable;
} else if (emit.lower.bin_file.cast(.macho)) |_| {
unreachable;
} else if (emit.lower.bin_file.cast(.coff)) |coff_file| {
const atom_index = coff_file.getAtomIndexForSymbol(.{
- .sym_index = symbol.atom_index,
+ .sym_index = emit.atom_index,
.file = null,
}).?;
- const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0)
- coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index)
+ const target = if (link.File.Coff.global_symbol_bit & sym_index != 0)
+ coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index)
else
- link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null };
+ link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null };
try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
.type = switch (lowered_relocs[0].target) {
.linker_got => .got,
@@ -183,16 +186,15 @@ pub fn emitMir(emit: *Emit) Error!void {
},
.target = target,
.offset = @intCast(end_offset - 4),
- .addend = 0,
+ .addend = @intCast(lowered_relocs[0].off),
.pcrel = true,
.length = 2,
});
} 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
+ try p9_file.addReloc(emit.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 = sym_index, // we set sym_index to just be the atom index
.offset = @intCast(end_offset - 4),
- .addend = 0,
+ .addend = @intCast(lowered_relocs[0].off),
.type = .pcrel,
});
} else return emit.fail("TODO implement linker reloc for {s}", .{
@@ -232,18 +234,163 @@ pub fn emitMir(emit: *Emit) Error!void {
.none => {},
}
},
- .pseudo_dbg_inline_func => {
+ .pseudo_dbg_enter_inline_func => {
switch (emit.debug_output) {
.dwarf => |dw| {
- log.debug("mirDbgInline (line={d}, col={d})", .{
+ log.debug("mirDbgEnterInline (line={d}, col={d})", .{
emit.prev_di_line, emit.prev_di_column,
});
- try dw.setInlineFunc(mir_inst.data.func);
+ try dw.enterInlineFunc(mir_inst.data.func, emit.code.items.len, emit.prev_di_line, emit.prev_di_column);
+ },
+ .plan9 => {},
+ .none => {},
+ }
+ },
+ .pseudo_dbg_leave_inline_func => {
+ switch (emit.debug_output) {
+ .dwarf => |dw| {
+ log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
+ emit.prev_di_line, emit.prev_di_column,
+ });
+ try dw.leaveInlineFunc(mir_inst.data.func, emit.code.items.len);
+ },
+ .plan9 => {},
+ .none => {},
+ }
+ },
+ .pseudo_dbg_local_a,
+ .pseudo_dbg_local_ai_s,
+ .pseudo_dbg_local_ai_u,
+ .pseudo_dbg_local_ai_64,
+ .pseudo_dbg_local_as,
+ .pseudo_dbg_local_aso,
+ .pseudo_dbg_local_aro,
+ .pseudo_dbg_local_af,
+ .pseudo_dbg_local_am,
+ => {
+ switch (emit.debug_output) {
+ .dwarf => |dw| {
+ var loc_buf: [2]link.File.Dwarf.Loc = undefined;
+ const air_inst_index, const loc: link.File.Dwarf.Loc = switch (mir_inst.ops) {
+ else => unreachable,
+ .pseudo_dbg_local_a => .{ mir_inst.data.a.air_inst, .empty },
+ .pseudo_dbg_local_ai_s,
+ .pseudo_dbg_local_ai_u,
+ .pseudo_dbg_local_ai_64,
+ => .{ mir_inst.data.ai.air_inst, .{ .stack_value = stack_value: {
+ loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.ai.i)) {
+ .signed => |s| .{ .consts = s },
+ .unsigned => |u| .{ .constu = u },
+ };
+ break :stack_value &loc_buf[0];
+ } } },
+ .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ .addr = .{
+ .sym = mir_inst.data.as.sym_index,
+ } } },
+ .pseudo_dbg_local_aso => loc: {
+ const sym_off = emit.lower.mir.extraData(
+ bits.SymbolOffset,
+ mir_inst.data.ax.payload,
+ ).data;
+ break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{
+ sym: {
+ loc_buf[0] = .{ .addr = .{ .sym = sym_off.sym_index } };
+ break :sym &loc_buf[0];
+ },
+ off: {
+ loc_buf[1] = .{ .consts = sym_off.off };
+ break :off &loc_buf[1];
+ },
+ } } };
+ },
+ .pseudo_dbg_local_aro => loc: {
+ const air_off = emit.lower.mir.extraData(
+ Mir.AirOffset,
+ mir_inst.data.rx.payload,
+ ).data;
+ break :loc .{ air_off.air_inst, .{ .plus = .{
+ reg: {
+ loc_buf[0] = .{ .breg = mir_inst.data.rx.r1.dwarfNum() };
+ break :reg &loc_buf[0];
+ },
+ off: {
+ loc_buf[1] = .{ .consts = air_off.off };
+ break :off &loc_buf[1];
+ },
+ } } };
+ },
+ .pseudo_dbg_local_af => loc: {
+ const reg_off = emit.lower.mir.resolveFrameAddr(emit.lower.mir.extraData(
+ bits.FrameAddr,
+ mir_inst.data.ax.payload,
+ ).data);
+ break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{
+ reg: {
+ loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() };
+ break :reg &loc_buf[0];
+ },
+ off: {
+ loc_buf[1] = .{ .consts = reg_off.off };
+ break :off &loc_buf[1];
+ },
+ } } };
+ },
+ .pseudo_dbg_local_am => loc: {
+ const mem = emit.lower.mem(mir_inst.data.ax.payload);
+ break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{
+ base: {
+ loc_buf[0] = switch (mem.base()) {
+ .none => .{ .constu = 0 },
+ .reg => |reg| .{ .breg = reg.dwarfNum() },
+ .frame => unreachable,
+ .reloc => |sym_index| .{ .addr = .{ .sym = sym_index } },
+ };
+ break :base &loc_buf[0];
+ },
+ disp: {
+ loc_buf[1] = switch (mem.disp()) {
+ .signed => |s| .{ .consts = s },
+ .unsigned => |u| .{ .constu = u },
+ };
+ break :disp &loc_buf[1];
+ },
+ } } };
+ },
+ };
+ const ip = &emit.lower.bin_file.comp.module.?.intern_pool;
+ const air_inst = emit.air.instructions.get(@intFromEnum(air_inst_index));
+ const name: Air.NullTerminatedString = switch (air_inst.tag) {
+ else => unreachable,
+ .arg => air_inst.data.arg.name,
+ .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => @enumFromInt(air_inst.data.pl_op.payload),
+ };
+ try dw.genLocalDebugInfo(
+ switch (air_inst.tag) {
+ else => unreachable,
+ .arg, .dbg_arg_inline => .local_arg,
+ .dbg_var_ptr, .dbg_var_val => .local_var,
+ },
+ name.toSlice(emit.air),
+ switch (air_inst.tag) {
+ else => unreachable,
+ .arg => emit.air.typeOfIndex(air_inst_index, ip),
+ .dbg_var_ptr => emit.air.typeOf(air_inst.data.pl_op.operand, ip).childTypeIp(ip),
+ .dbg_var_val, .dbg_arg_inline => emit.air.typeOf(air_inst.data.pl_op.operand, ip),
+ },
+ loc,
+ );
},
.plan9 => {},
.none => {},
}
},
+ .pseudo_dbg_var_args_none => {
+ switch (emit.debug_output) {
+ .dwarf => |dw| try dw.genVarArgsDebugInfo(),
+ .plan9 => {},
+ .none => {},
+ }
+ },
.pseudo_dead_none => {},
},
}
@@ -268,10 +415,12 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
const Reloc = struct {
/// Offset of the instruction.
source: usize,
+ /// Offset of the relocation within the instruction.
+ source_offset: u32,
/// Target of the relocation.
target: Mir.Inst.Index,
- /// Offset of the relocation within the instruction.
- offset: u32,
+ /// Offset from the target instruction.
+ target_offset: i32,
/// Length of the instruction.
length: u5,
};
@@ -284,8 +433,8 @@ fn fixupRelocs(emit: *Emit) Error!void {
for (emit.relocs.items) |reloc| {
const target = emit.code_offset_mapping.get(reloc.target) orelse
return emit.fail("JMP/CALL relocation target not found!", .{});
- const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length));
- mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], @intCast(disp), .little);
+ const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)) + reloc.target_offset;
+ std.mem.writeInt(i32, emit.code.items[reloc.source_offset..][0..4], @intCast(disp), .little);
}
}
@@ -338,11 +487,12 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
}
}
+const bits = @import("bits.zig");
const link = @import("../../link.zig");
const log = std.log.scoped(.emit);
-const mem = std.mem;
const std = @import("std");
+const Air = @import("../../Air.zig");
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
const Emit = @This();
const Lower = @import("Lower.zig");
diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig
index 2275ed5f9b..69cd548cc3 100644
--- a/src/arch/x86_64/Lower.zig
+++ b/src/arch/x86_64/Lower.zig
@@ -4,10 +4,10 @@ bin_file: *link.File,
output_mode: std.builtin.OutputMode,
link_mode: std.builtin.LinkMode,
pic: bool,
-allocator: Allocator,
+allocator: std.mem.Allocator,
mir: Mir,
cc: std.builtin.CallingConvention,
-err_msg: ?*ErrorMsg = null,
+err_msg: ?*Zcu.ErrorMsg = null,
src_loc: Zcu.LazySrcLoc,
result_insts_len: u8 = undefined,
result_relocs_len: u8 = undefined,
@@ -52,16 +52,17 @@ pub const Error = error{
pub const Reloc = struct {
lowered_inst_index: u8,
target: Target,
+ off: i32,
const Target = union(enum) {
inst: Mir.Inst.Index,
- linker_reloc: bits.Symbol,
- linker_tlsld: bits.Symbol,
- linker_dtpoff: bits.Symbol,
- linker_extern_fn: bits.Symbol,
- linker_got: bits.Symbol,
- linker_direct: bits.Symbol,
- linker_import: bits.Symbol,
+ linker_reloc: u32,
+ linker_tlsld: u32,
+ linker_dtpoff: u32,
+ linker_extern_fn: u32,
+ linker_got: u32,
+ linker_direct: u32,
+ linker_import: u32,
};
};
@@ -173,19 +174,19 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.pseudo_j_z_and_np_inst => {
assert(inst.data.inst.fixes == ._);
try lower.emit(.none, .jnz, &.{
- .{ .imm = lower.reloc(.{ .inst = index + 1 }) },
+ .{ .imm = lower.reloc(.{ .inst = index + 1 }, 0) },
});
try lower.emit(.none, .jnp, &.{
- .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
+ .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) },
});
},
.pseudo_j_nz_or_p_inst => {
assert(inst.data.inst.fixes == ._);
try lower.emit(.none, .jnz, &.{
- .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
+ .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) },
});
try lower.emit(.none, .jp, &.{
- .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
+ .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) },
});
},
@@ -195,7 +196,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.{ .imm = Immediate.s(@bitCast(inst.data.ri.i)) },
});
try lower.emit(.none, .jz, &.{
- .{ .imm = lower.reloc(.{ .inst = index + 1 }) },
+ .{ .imm = lower.reloc(.{ .inst = index + 1 }, 0) },
});
try lower.emit(.none, .lea, &.{
.{ .reg = inst.data.ri.r1 },
@@ -211,7 +212,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.{ .reg = inst.data.ri.r1.to32() },
});
try lower.emit(.none, .jmp, &.{
- .{ .imm = lower.reloc(.{ .inst = index }) },
+ .{ .imm = lower.reloc(.{ .inst = index }, 0) },
});
assert(lower.result_insts_len == pseudo_probe_align_insts);
},
@@ -257,7 +258,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.{ .imm = Immediate.s(page_size) },
});
try lower.emit(.none, .jae, &.{
- .{ .imm = lower.reloc(.{ .inst = index }) },
+ .{ .imm = lower.reloc(.{ .inst = index }, 0) },
});
assert(lower.result_insts_len == pseudo_probe_adjust_loop_insts);
},
@@ -267,7 +268,18 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.pseudo_dbg_prologue_end_none,
.pseudo_dbg_line_line_column,
.pseudo_dbg_epilogue_begin_none,
- .pseudo_dbg_inline_func,
+ .pseudo_dbg_enter_inline_func,
+ .pseudo_dbg_leave_inline_func,
+ .pseudo_dbg_local_a,
+ .pseudo_dbg_local_ai_s,
+ .pseudo_dbg_local_ai_u,
+ .pseudo_dbg_local_ai_64,
+ .pseudo_dbg_local_as,
+ .pseudo_dbg_local_aso,
+ .pseudo_dbg_local_aro,
+ .pseudo_dbg_local_af,
+ .pseudo_dbg_local_am,
+ .pseudo_dbg_var_args_none,
.pseudo_dead_none,
=> {},
else => unreachable,
@@ -283,17 +295,18 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
@setCold(true);
assert(lower.err_msg == null);
- lower.err_msg = try ErrorMsg.create(lower.allocator, lower.src_loc, format, args);
+ lower.err_msg = try Zcu.ErrorMsg.create(lower.allocator, lower.src_loc, format, args);
return error.LowerFail;
}
-fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
+pub fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
return switch (ops) {
.rri_s,
.ri_s,
.i_s,
.mi_s,
.rmi_s,
+ .pseudo_dbg_local_ai_s,
=> Immediate.s(@bitCast(i)),
.rrri,
@@ -306,22 +319,26 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
.mri,
.rrm,
.rrmi,
+ .pseudo_dbg_local_ai_u,
=> Immediate.u(i),
- .ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
+ .ri_64,
+ .pseudo_dbg_local_ai_64,
+ => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
else => unreachable,
};
}
-fn mem(lower: Lower, payload: u32) Memory {
+pub fn mem(lower: Lower, payload: u32) Memory {
return lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode();
}
-fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
+fn reloc(lower: *Lower, target: Reloc.Target, off: i32) Immediate {
lower.result_relocs[lower.result_relocs_len] = .{
.lowered_inst_index = lower.result_insts_len,
.target = target,
+ .off = off,
};
lower.result_relocs_len += 1;
return Immediate.s(0);
@@ -337,37 +354,36 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
else => op,
.mem => |mem_op| switch (mem_op.base()) {
else => op,
- .reloc => |sym| op: {
+ .reloc => |sym_index| op: {
assert(prefix == .none);
assert(mem_op.sib.disp == 0);
assert(mem_op.sib.scale_index.scale == 0);
if (lower.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
- const elf_sym = zo.symbol(sym.sym_index);
+ const elf_sym = zo.symbol(sym_index);
if (elf_sym.flags.is_tls) {
// TODO handle extern TLS vars, i.e., emit GD model
if (lower.pic) {
// Here, we currently assume local dynamic TLS vars, and so
// we emit LD model.
- _ = lower.reloc(.{ .linker_tlsld = sym });
+ _ = lower.reloc(.{ .linker_tlsld = sym_index }, 0);
lower.result_insts[lower.result_insts_len] =
try Instruction.new(.none, .lea, &[_]Operand{
.{ .reg = .rdi },
.{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },
});
lower.result_insts_len += 1;
- _ = lower.reloc(.{ .linker_extern_fn = .{
- .atom_index = sym.atom_index,
- .sym_index = try elf_file.getGlobalSymbol("__tls_get_addr", null),
- } });
+ _ = lower.reloc(.{
+ .linker_extern_fn = try elf_file.getGlobalSymbol("__tls_get_addr", null),
+ }, 0);
lower.result_insts[lower.result_insts_len] =
try Instruction.new(.none, .call, &[_]Operand{
.{ .imm = Immediate.s(0) },
});
lower.result_insts_len += 1;
- _ = lower.reloc(.{ .linker_dtpoff = sym });
+ _ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0);
emit_mnemonic = .lea;
break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
.base = .{ .reg = .rax },
@@ -381,7 +397,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
.{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) },
});
lower.result_insts_len += 1;
- _ = lower.reloc(.{ .linker_reloc = sym });
+ _ = lower.reloc(.{ .linker_reloc = sym_index }, 0);
emit_mnemonic = .lea;
break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
.base = .{ .reg = .rax },
@@ -390,7 +406,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
}
}
- _ = lower.reloc(.{ .linker_reloc = sym });
+ _ = lower.reloc(.{ .linker_reloc = sym_index }, 0);
if (lower.pic) switch (mnemonic) {
.lea => {
if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov;
@@ -427,10 +443,10 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
}
} else if (lower.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?;
- const macho_sym = zo.symbols.items[sym.sym_index];
+ const macho_sym = zo.symbols.items[sym_index];
if (macho_sym.flags.tlv) {
- _ = lower.reloc(.{ .linker_reloc = sym });
+ _ = lower.reloc(.{ .linker_reloc = sym_index }, 0);
lower.result_insts[lower.result_insts_len] =
try Instruction.new(.none, .mov, &[_]Operand{
.{ .reg = .rdi },
@@ -446,7 +462,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
break :op .{ .reg = .rax };
}
- _ = lower.reloc(.{ .linker_reloc = sym });
+ _ = lower.reloc(.{ .linker_reloc = sym_index }, 0);
break :op switch (mnemonic) {
.lea => {
if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov;
@@ -490,8 +506,8 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.rrrr => inst.data.rrrr.fixes,
.rrri => inst.data.rrri.fixes,
.rri_s, .rri_u => inst.data.rri.fixes,
- .ri_s, .ri_u => inst.data.ri.fixes,
- .ri64, .rm, .rmi_s, .mr => inst.data.rx.fixes,
+ .ri_s, .ri_u, .ri_64 => inst.data.ri.fixes,
+ .rm, .rmi_s, .mr => inst.data.rx.fixes,
.mrr, .rrm, .rmr => inst.data.rrx.fixes,
.rmi, .mri => inst.data.rix.fixes,
.rrmr => inst.data.rrrx.fixes,
@@ -525,7 +541,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
}, switch (inst.ops) {
.none => &.{},
.inst => &.{
- .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
+ .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) },
},
.i_s, .i_u => &.{
.{ .imm = lower.imm(inst.ops, inst.data.i.i) },
@@ -554,14 +570,10 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.{ .reg = inst.data.rrri.r3 },
.{ .imm = lower.imm(inst.ops, inst.data.rrri.i) },
},
- .ri_s, .ri_u => &.{
+ .ri_s, .ri_u, .ri_64 => &.{
.{ .reg = inst.data.ri.r1 },
.{ .imm = lower.imm(inst.ops, inst.data.ri.i) },
},
- .ri64 => &.{
- .{ .reg = inst.data.rx.r1 },
- .{ .imm = lower.imm(inst.ops, inst.data.rx.payload) },
- },
.rri_s, .rri_u => &.{
.{ .reg = inst.data.rri.r1 },
.{ .reg = inst.data.rri.r2 },
@@ -631,17 +643,17 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
},
.extern_fn_reloc, .rel => &.{
- .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
+ .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc.sym_index }, inst.data.reloc.off) },
},
.got_reloc, .direct_reloc, .import_reloc => ops: {
const reg = inst.data.rx.r1;
- const extra = lower.mir.extraData(bits.Symbol, inst.data.rx.payload).data;
+ const extra = lower.mir.extraData(bits.SymbolOffset, inst.data.rx.payload).data;
_ = lower.reloc(switch (inst.ops) {
- .got_reloc => .{ .linker_got = extra },
- .direct_reloc => .{ .linker_direct = extra },
- .import_reloc => .{ .linker_import = extra },
+ .got_reloc => .{ .linker_got = extra.sym_index },
+ .direct_reloc => .{ .linker_direct = extra.sym_index },
+ .import_reloc => .{ .linker_import = extra.sym_index },
else => unreachable,
- });
+ }, extra.off);
break :ops &.{
.{ .reg = reg },
.{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
@@ -670,9 +682,6 @@ const encoder = @import("encoder.zig");
const link = @import("../../link.zig");
const std = @import("std");
-const Air = @import("../../Air.zig");
-const Allocator = std.mem.Allocator;
-const ErrorMsg = Zcu.ErrorMsg;
const Immediate = Instruction.Immediate;
const Instruction = encoder.Instruction;
const Lower = @This();
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 75fe8cffe2..2ccb609839 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -760,8 +760,8 @@ pub const Inst = struct {
/// Uses `ri` payload.
ri_u,
/// Register, 64-bit unsigned immediate operands.
- /// Uses `rx` payload with payload type `Imm64`.
- ri64,
+ /// Uses `ri` payload with `i` index of extra data of type `Imm64`.
+ ri_64,
/// Immediate (sign-extended) operand.
/// Uses `imm` payload.
i_s,
@@ -796,7 +796,7 @@ pub const Inst = struct {
/// Uses `rrix` payload with extra data of type `Memory`.
rrmi,
/// Single memory operand.
- /// Uses `x` with extra data of type `Memory`.
+ /// Uses `x` payload with extra data of type `Memory`.
m,
/// Memory, immediate (sign-extend) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `Memory`.
@@ -820,16 +820,16 @@ pub const Inst = struct {
/// Uses `reloc` payload.
extern_fn_reloc,
/// Linker relocation - GOT indirection.
- /// Uses `rx` payload with extra data of type `bits.Symbol`.
+ /// Uses `rx` payload with extra data of type `bits.SymbolOffset`.
got_reloc,
/// Linker relocation - direct reference.
- /// Uses `rx` payload with extra data of type `bits.Symbol`.
+ /// Uses `rx` payload with extra data of type `bits.SymbolOffset`.
direct_reloc,
/// Linker relocation - imports table indirection (binding).
- /// Uses `rx` payload with extra data of type `bits.Symbol`.
+ /// Uses `rx` payload with extra data of type `bits.SymbolOffset`.
import_reloc,
/// Linker relocation - threadlocal variable via GOT indirection.
- /// Uses `rx` payload with extra data of type `bits.Symbol`.
+ /// Uses `rx` payload with extra data of type `bits.SymbolOffset`.
tlv_reloc,
// Pseudo instructions:
@@ -868,16 +868,16 @@ pub const Inst = struct {
pseudo_j_nz_or_p_inst,
/// Probe alignment
- /// Uses `ri` payload
+ /// Uses `ri` payload.
pseudo_probe_align_ri_s,
/// Probe adjust unrolled
- /// Uses `ri` payload
+ /// Uses `ri` payload.
pseudo_probe_adjust_unrolled_ri_s,
/// Probe adjust setup
- /// Uses `rri` payload
+ /// Uses `rri` payload.
pseudo_probe_adjust_setup_rri_s,
/// Probe adjust loop
- /// Uses `rr` payload
+ /// Uses `rr` payload.
pseudo_probe_adjust_loop_rr,
/// Push registers
/// Uses `reg_list` payload.
@@ -893,8 +893,39 @@ pub const Inst = struct {
pseudo_dbg_line_line_column,
/// Start of epilogue
pseudo_dbg_epilogue_begin_none,
- /// Start or end of inline function
- pseudo_dbg_inline_func,
+ /// Start of inline function
+ pseudo_dbg_enter_inline_func,
+ /// End of inline function
+ pseudo_dbg_leave_inline_func,
+ /// Local argument or variable.
+ /// Uses `a` payload.
+ pseudo_dbg_local_a,
+ /// Local argument or variable.
+ /// Uses `ai` payload.
+ pseudo_dbg_local_ai_s,
+ /// Local argument or variable.
+ /// Uses `ai` payload.
+ pseudo_dbg_local_ai_u,
+ /// Local argument or variable.
+ /// Uses `ai` payload with extra data of type `Imm64`.
+ pseudo_dbg_local_ai_64,
+ /// Local argument or variable.
+ /// Uses `as` payload.
+ pseudo_dbg_local_as,
+ /// Local argument or variable.
+ /// Uses `ax` payload with extra data of type `bits.SymbolOffset`.
+ pseudo_dbg_local_aso,
+ /// Local argument or variable.
+ /// Uses `rx` payload with extra data of type `AirOffset`.
+ pseudo_dbg_local_aro,
+ /// Local argument or variable.
+ /// Uses `ax` payload with extra data of type `bits.FrameAddr`.
+ pseudo_dbg_local_af,
+ /// Local argument or variable.
+ /// Uses `ax` payload with extra data of type `Memory`.
+ pseudo_dbg_local_am,
+ /// Remaining arguments are varargs.
+ pseudo_dbg_var_args_none,
/// Tombstone
/// Emitter should skip this instruction.
@@ -997,10 +1028,28 @@ pub const Inst = struct {
fixes: Fixes = ._,
payload: u32,
},
+ ix: struct {
+ payload: u32,
+ },
+ a: struct {
+ air_inst: Air.Inst.Index,
+ },
+ ai: struct {
+ air_inst: Air.Inst.Index,
+ i: u32,
+ },
+ as: struct {
+ air_inst: Air.Inst.Index,
+ sym_index: u32,
+ },
+ ax: struct {
+ air_inst: Air.Inst.Index,
+ payload: u32,
+ },
/// Relocation for the linker where:
- /// * `atom_index` is the index of the source
/// * `sym_index` is the index of the target
- reloc: bits.Symbol,
+ /// * `off` is the offset from the target
+ reloc: bits.SymbolOffset,
/// Debug line and column position
line_column: struct {
line: u32,
@@ -1020,6 +1069,8 @@ pub const Inst = struct {
}
};
+pub const AirOffset = struct { air_inst: Air.Inst.Index, off: i32 };
+
/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
pub const RegisterList = struct {
bitset: BitSet = BitSet.initEmpty(),
@@ -1118,15 +1169,13 @@ pub const Memory = struct {
.none => undefined,
.reg => |reg| @intFromEnum(reg),
.frame => |frame_index| @intFromEnum(frame_index),
- .reloc => |symbol| symbol.sym_index,
+ .reloc => |sym_index| sym_index,
},
.off = switch (mem.mod) {
.rm => |rm| @bitCast(rm.disp),
.off => |off| @truncate(off),
},
- .extra = if (mem.base == .reloc)
- mem.base.reloc.atom_index
- else if (mem.mod == .off)
+ .extra = if (mem.mod == .off)
@intCast(mem.mod.off >> 32)
else
undefined,
@@ -1146,7 +1195,7 @@ pub const Memory = struct {
.none => .none,
.reg => .{ .reg = @enumFromInt(mem.base) },
.frame => .{ .frame = @enumFromInt(mem.base) },
- .reloc => .{ .reloc = .{ .atom_index = mem.extra, .sym_index = mem.base } },
+ .reloc => .{ .reloc = mem.base },
},
.scale_index = switch (mem.info.index) {
.none => null,
@@ -1186,6 +1235,7 @@ pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end:
@field(result, field.name) = switch (field.type) {
u32 => mir.extra[i],
i32, Memory.Info => @bitCast(mir.extra[i]),
+ bits.FrameIndex, Air.Inst.Index => @enumFromInt(mir.extra[i]),
else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
};
i += 1;
@@ -1201,6 +1251,11 @@ pub const FrameLoc = struct {
disp: i32,
};
+pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffset {
+ const frame_loc = mir.frame_locs.get(@intFromEnum(frame_addr.index));
+ return .{ .reg = frame_loc.base, .off = frame_loc.disp + frame_addr.off };
+}
+
pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
return switch (mem.info.base) {
.none, .reg, .reloc => mem,
@@ -1225,6 +1280,7 @@ const builtin = @import("builtin");
const encoder = @import("encoder.zig");
const std = @import("std");
+const Air = @import("../../Air.zig");
const IntegerBitSet = std.bit_set.IntegerBitSet;
const InternPool = @import("../../InternPool.zig");
const Mir = @This();
diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig
index 56b5fcc5d4..839084456a 100644
--- a/src/arch/x86_64/bits.zig
+++ b/src/arch/x86_64/bits.zig
@@ -447,26 +447,11 @@ pub const FrameIndex = enum(u32) {
}
};
-/// A linker symbol not yet allocated in VM.
-pub const Symbol = struct {
- /// Index of the containing atom.
- atom_index: u32,
- /// Index into the linker's symbol table.
- sym_index: u32,
+pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
- pub fn format(
- sym: Symbol,
- comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
- writer: anytype,
- ) @TypeOf(writer).Error!void {
- try writer.writeAll("Symbol(");
- try std.fmt.formatType(sym.atom_index, fmt, options, writer, 0);
- try writer.writeAll(", ");
- try std.fmt.formatType(sym.sym_index, fmt, options, writer, 0);
- try writer.writeByte(')');
- }
-};
+pub const RegisterOffset = struct { reg: Register, off: i32 = 0 };
+
+pub const SymbolOffset = struct { sym_index: u32, off: i32 = 0 };
pub const Memory = struct {
base: Base,
@@ -476,7 +461,7 @@ pub const Memory = struct {
none,
reg: Register,
frame: FrameIndex,
- reloc: Symbol,
+ reloc: u32,
pub const Tag = @typeInfo(Base).Union.tag_type.?;
@@ -568,7 +553,7 @@ pub const Memory = struct {
pub const Immediate = union(enum) {
signed: i32,
unsigned: u64,
- reloc: Symbol,
+ reloc: SymbolOffset,
pub fn u(x: u64) Immediate {
return .{ .unsigned = x };
@@ -578,19 +563,19 @@ pub const Immediate = union(enum) {
return .{ .signed = x };
}
- pub fn rel(symbol: Symbol) Immediate {
- return .{ .reloc = symbol };
+ pub fn rel(sym_off: SymbolOffset) Immediate {
+ return .{ .reloc = sym_off };
}
pub fn format(
imm: Immediate,
- comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
+ comptime _: []const u8,
+ _: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
switch (imm) {
- .reloc => |x| try std.fmt.formatType(x, fmt, options, writer, 0),
- inline else => |x| try writer.print("{d}", .{x}),
+ inline else => |int| try writer.print("{d}", .{int}),
+ .reloc => |sym_off| try writer.print("Symbol({[sym_index]d}) + {[off]d}", sym_off),
}
}
};
diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig
index b525b0e11e..ce5b9c4d0f 100644
--- a/src/arch/x86_64/encoder.zig
+++ b/src/arch/x86_64/encoder.zig
@@ -128,8 +128,8 @@ pub const Instruction = struct {
} };
}
- pub fn rip(ptr_size: PtrSize, disp: i32) Memory {
- return .{ .rip = .{ .ptr_size = ptr_size, .disp = disp } };
+ pub fn rip(ptr_size: PtrSize, displacement: i32) Memory {
+ return .{ .rip = .{ .ptr_size = ptr_size, .disp = displacement } };
}
pub fn isSegmentRegister(mem: Memory) bool {
@@ -158,6 +158,14 @@ pub const Instruction = struct {
};
}
+ pub fn disp(mem: Memory) Immediate {
+ return switch (mem) {
+ .sib => |s| Immediate.s(s.disp),
+ .rip => |r| Immediate.s(r.disp),
+ .moffs => |m| Immediate.u(m.offset),
+ };
+ }
+
pub fn bitSize(mem: Memory) u64 {
return switch (mem) {
.rip => |r| r.ptr_size.bitSize(),
@@ -258,17 +266,12 @@ pub const Instruction = struct {
try writer.writeByte('[');
- var any = false;
+ var any = true;
switch (sib.base) {
- .none => {},
- .reg => |reg| {
- try writer.print("{s}", .{@tagName(reg)});
- any = true;
- },
- inline .frame, .reloc => |payload| {
- try writer.print("{}", .{payload});
- any = true;
- },
+ .none => any = false,
+ .reg => |reg| try writer.print("{s}", .{@tagName(reg)}),
+ .frame => |frame_index| try writer.print("{}", .{frame_index}),
+ .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
}
if (mem.scaleIndex()) |si| {
if (any) try writer.writeAll(" + ");
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 7c35a178a0..397cb071b6 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -3293,7 +3293,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.dbg_stmt => try airDbgStmt(f, inst),
.dbg_inline_block => try airDbgInlineBlock(f, inst),
- .dbg_var_ptr, .dbg_var_val => try airDbgVar(f, inst),
+ .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => try airDbgVar(f, inst),
.call => try airCall(f, inst, .auto),
.call_always_tail => .none,
@@ -4590,14 +4590,15 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
+ const tag = f.air.instructions.items(.tag)[@intFromEnum(inst)];
const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
- const name = f.air.nullTerminatedString(pl_op.payload);
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
const operand_is_undef = if (try f.air.value(pl_op.operand, pt)) |v| v.isUndefDeep(zcu) else false;
if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand);
try reap(f, inst, &.{pl_op.operand});
const writer = f.object.writer();
- try writer.print("/* var:{s} */\n", .{name});
+ try writer.print("/* {s}:{s} */\n", .{ @tagName(tag), name.toSlice(f.air) });
return .none;
}
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 8fb4fa7ef9..233cf7e3eb 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1665,6 +1665,7 @@ pub const Object = struct {
.ret_ptr = ret_ptr,
.args = args.items,
.arg_index = 0,
+ .arg_inline_index = 0,
.func_inst_table = .{},
.blocks = .{},
.sync_scope = if (owner_mod.single_threaded) .singlethread else .system,
@@ -4769,7 +4770,8 @@ pub const FuncGen = struct {
/// it omits 0-bit types. If the function uses sret as the first parameter,
/// this slice does not include it.
args: []const Builder.Value,
- arg_index: usize,
+ arg_index: u32,
+ arg_inline_index: u32,
err_ret_trace: Builder.Value = .none,
@@ -5082,7 +5084,8 @@ pub const FuncGen = struct {
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr => try self.airDbgVarPtr(inst),
- .dbg_var_val => try self.airDbgVarVal(inst),
+ .dbg_var_val => try self.airDbgVarVal(inst, false),
+ .dbg_arg_inline => try self.airDbgVarVal(inst, true),
.c_va_arg => try self.airCVaArg(inst),
.c_va_copy => try self.airCVaCopy(inst),
@@ -6677,6 +6680,7 @@ pub const FuncGen = struct {
fn airDbgInlineBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
+ self.arg_inline_index = 0;
return self.lowerBlock(inst, extra.data.func, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
}
@@ -6685,11 +6689,11 @@ pub const FuncGen = struct {
const mod = o.pt.zcu;
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const operand = try self.resolveInst(pl_op.operand);
- const name = self.air.nullTerminatedString(pl_op.payload);
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
const ptr_ty = self.typeOf(pl_op.operand);
const debug_local_var = try o.builder.debugLocalVar(
- try o.builder.metadataString(name),
+ try o.builder.metadataString(name.toSlice(self.air)),
self.file,
self.scope,
self.prev_dbg_line,
@@ -6712,15 +6716,25 @@ pub const FuncGen = struct {
return .none;
}
- fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
+ fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index, is_arg: bool) !Builder.Value {
const o = self.ng.object;
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const operand = try self.resolveInst(pl_op.operand);
const operand_ty = self.typeOf(pl_op.operand);
- const name = self.air.nullTerminatedString(pl_op.payload);
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
- const debug_local_var = try o.builder.debugLocalVar(
- try o.builder.metadataString(name),
+ const debug_local_var = if (is_arg) try o.builder.debugParameter(
+ try o.builder.metadataString(name.toSlice(self.air)),
+ self.file,
+ self.scope,
+ self.prev_dbg_line,
+ try o.lowerDebugType(operand_ty),
+ arg_no: {
+ self.arg_inline_index += 1;
+ break :arg_no self.arg_inline_index;
+ },
+ ) else try o.builder.debugLocalVar(
+ try o.builder.metadataString(name.toSlice(self.air)),
self.file,
self.scope,
self.prev_dbg_line,
@@ -8835,12 +8849,12 @@ pub const FuncGen = struct {
const lbrace_col = func.lbrace_column + 1;
const debug_parameter = try o.builder.debugParameter(
- try o.builder.metadataString(self.air.nullTerminatedString(@intFromEnum(name))),
+ try o.builder.metadataString(name.toSlice(self.air)),
self.file,
self.scope,
lbrace_line,
try o.lowerDebugType(inst_ty),
- @intCast(self.arg_index),
+ self.arg_index,
);
const old_location = self.wip.debug_location;
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index b13be401ab..a89dd8f10b 100644
--- a/src/codegen/spirv.zig
+++ b/src/codegen/spirv.zig
@@ -6366,8 +6366,8 @@ const NavGen = struct {
fn airDbgVar(self: *NavGen, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const target_id = try self.resolve(pl_op.operand);
- const name = self.air.nullTerminatedString(pl_op.payload);
- try self.spv.debugName(target_id, name);
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
+ try self.spv.debugName(target_id, name.toSlice(self.air));
}
fn airAssembly(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
diff --git a/src/introspect.zig b/src/introspect.zig
index 341b1cddeb..4193440461 100644
--- a/src/introspect.zig
+++ b/src/introspect.zig
@@ -90,8 +90,11 @@ pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 {
if (builtin.os.tag != .windows) {
if (std.zig.EnvVar.XDG_CACHE_HOME.getPosix()) |cache_root| {
- return fs.path.join(allocator, &[_][]const u8{ cache_root, appname });
- } else if (std.zig.EnvVar.HOME.getPosix()) |home| {
+ if (cache_root.len > 0) {
+ return fs.path.join(allocator, &[_][]const u8{ cache_root, appname });
+ }
+ }
+ if (std.zig.EnvVar.HOME.getPosix()) |home| {
return fs.path.join(allocator, &[_][]const u8{ home, ".cache", appname });
}
}
diff --git a/src/link.zig b/src/link.zig
index b3e0aaa4a8..894074cdda 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -11,6 +11,7 @@ const wasi_libc = @import("wasi_libc.zig");
const Air = @import("Air.zig");
const Allocator = std.mem.Allocator;
const Cache = std.Build.Cache;
+const Path = Cache.Path;
const Compilation = @import("Compilation.zig");
const LibCInstallation = std.zig.LibCInstallation;
const Liveness = @import("Liveness.zig");
@@ -56,7 +57,7 @@ pub const File = struct {
/// The owner of this output File.
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
file: ?fs.File,
/// When linking with LLD, this linker code will output an object file only at
@@ -189,7 +190,7 @@ pub const File = struct {
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: OpenOptions,
) !*File {
switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
@@ -204,7 +205,7 @@ pub const File = struct {
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: OpenOptions,
) !*File {
switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
@@ -243,8 +244,8 @@ pub const File = struct {
emit.sub_path, std.crypto.random.int(u32),
});
defer gpa.free(tmp_sub_path);
- try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{});
- try emit.directory.handle.rename(tmp_sub_path, emit.sub_path);
+ try emit.root_dir.handle.copyFile(emit.sub_path, emit.root_dir.handle, tmp_sub_path, .{});
+ try emit.root_dir.handle.rename(tmp_sub_path, emit.sub_path);
switch (builtin.os.tag) {
.linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
log.warn("ptrace failure: {s}", .{@errorName(err)});
@@ -260,7 +261,7 @@ pub const File = struct {
const use_lld = build_options.have_llvm and comp.config.use_lld;
const output_mode = comp.config.output_mode;
const link_mode = comp.config.link_mode;
- base.file = try emit.directory.handle.createFile(emit.sub_path, .{
+ base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.truncate = false,
.read = true,
.mode = determineMode(use_lld, output_mode, link_mode),
@@ -603,7 +604,7 @@ pub const File = struct {
// Until then, we do `lld -r -o output.o input.o` even though the output is the same
// as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
// to the final location. See also the corresponding TODO in Coff linking.
- const full_out_path = try emit.directory.join(gpa, &[_][]const u8{emit.sub_path});
+ const full_out_path = try emit.root_dir.join(gpa, &[_][]const u8{emit.sub_path});
defer gpa.free(full_out_path);
assert(comp.c_object_table.count() == 1);
const the_key = comp.c_object_table.keys()[0];
@@ -751,7 +752,7 @@ pub const File = struct {
const comp = base.comp;
const gpa = comp.gpa;
- const directory = base.emit.directory; // Just an alias to make it shorter to type.
+ const directory = base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path});
const full_out_path_z = try arena.dupeZ(u8, full_out_path);
const opt_zcu = comp.module;
@@ -1029,7 +1030,10 @@ pub const File = struct {
llvm_object: LlvmObject.Ptr,
prog_node: std.Progress.Node,
) !void {
- return base.comp.emitLlvmObject(arena, base.emit, .{
+ return base.comp.emitLlvmObject(arena, .{
+ .root_dir = base.emit.root_dir,
+ .sub_path = std.fs.path.dirname(base.emit.sub_path) orelse "",
+ }, .{
.directory = null,
.basename = base.zcu_object_sub_path.?,
}, llvm_object, prog_node);
diff --git a/src/link/C.zig b/src/link/C.zig
index e7c8f6a7b0..585389aa3f 100644
--- a/src/link/C.zig
+++ b/src/link/C.zig
@@ -3,6 +3,7 @@ const mem = std.mem;
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const fs = std.fs;
+const Path = std.Build.Cache.Path;
const C = @This();
const build_options = @import("build_options");
@@ -104,7 +105,7 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String {
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*C {
return createEmpty(arena, comp, emit, options);
@@ -113,7 +114,7 @@ pub fn open(
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*C {
const target = comp.root_mod.resolved_target.result;
@@ -127,7 +128,7 @@ pub fn createEmpty(
assert(!use_lld);
assert(!use_llvm);
- const file = try emit.directory.handle.createFile(emit.sub_path, .{
+ const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
// Truncation is done on `flush`.
.truncate = false,
});
@@ -316,8 +317,18 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !
defer tracy.end();
const gpa = self.base.comp.gpa;
-
const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+
+ const nav = ip.getNav(nav_index);
+ const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
+ .func => return,
+ .@"extern" => .none,
+ .variable => |variable| variable.init,
+ else => nav.status.resolved.val,
+ };
+ if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) return;
+
const gop = try self.navs.getOrPut(gpa, nav_index);
errdefer _ = self.navs.pop();
if (!gop.found_existing) gop.value_ptr.* = .{};
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index 7bdcc8d411..d6ebcc278e 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -219,7 +219,7 @@ pub const min_text_capacity = padToIdeal(minimum_text_block_size);
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*Coff {
const target = comp.root_mod.resolved_target.result;
@@ -315,7 +315,7 @@ pub fn createEmpty(
// If using LLD to link, this code should produce an object file so that it
// can be passed to LLD.
const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
- self.base.file = try emit.directory.handle.createFile(sub_path, .{
+ self.base.file = try emit.root_dir.handle.createFile(sub_path, .{
.truncate = true,
.read = true,
.mode = link.File.determineMode(use_lld, output_mode, link_mode),
@@ -416,7 +416,7 @@ pub fn createEmpty(
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*Coff {
// TODO: restore saved linker state, don't truncate the file, and
@@ -1207,6 +1207,7 @@ pub fn updateNav(
const nav_val = zcu.navValue(nav_index);
const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
+ .func => return,
.variable => |variable| Value.fromInterned(variable.init),
.@"extern" => |@"extern"| {
if (ip.isFunctionType(@"extern".ty)) return;
@@ -1220,7 +1221,7 @@ pub fn updateNav(
else => nav_val,
};
- if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
+ if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) {
const atom_index = try self.getOrCreateAtomForNav(nav_index);
Atom.freeRelocations(self, atom_index);
const atom = self.getAtom(atom_index);
@@ -2714,6 +2715,7 @@ const math = std.math;
const mem = std.mem;
const Allocator = std.mem.Allocator;
+const Path = std.Build.Cache.Path;
const codegen = @import("../codegen.zig");
const link = @import("../link.zig");
diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig
index ae56183e77..7273aa39b6 100644
--- a/src/link/Coff/lld.zig
+++ b/src/link/Coff/lld.zig
@@ -27,7 +27,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
const comp = self.base.comp;
const gpa = comp.gpa;
- const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
+ const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
// If there is no Zig code to compile, then we should skip flushing the output file because it
@@ -248,7 +248,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
if (comp.implib_emit) |emit| {
- const implib_out_path = try emit.directory.join(arena, &[_][]const u8{emit.sub_path});
+ const implib_out_path = try emit.root_dir.join(arena, &[_][]const u8{emit.sub_path});
try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path}));
}
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
index 1b5739030b..26ea6207e8 100644
--- a/src/link/Dwarf.zig
+++ b/src/link/Dwarf.zig
@@ -21,8 +21,9 @@ pub const UpdateError =
std.fs.File.OpenError ||
std.fs.File.SetEndPosError ||
std.fs.File.CopyRangeError ||
+ std.fs.File.PReadError ||
std.fs.File.PWriteError ||
- error{ Overflow, Underflow, UnexpectedEndOfFile };
+ error{ EndOfStream, Overflow, Underflow, UnexpectedEndOfFile };
pub const FlushError =
UpdateError ||
@@ -54,7 +55,10 @@ const ModInfo = struct {
const DebugAbbrev = struct {
section: Section,
const unit: Unit.Index = @enumFromInt(0);
- const entry: Entry.Index = @enumFromInt(0);
+
+ const header_bytes = 0;
+
+ const trailer_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.null));
};
const DebugAranges = struct {
@@ -118,8 +122,7 @@ const DebugLine = struct {
1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.directory_index) + uleb128Bytes(@intFromEnum(dir_index_info.form)) + uleb128Bytes(DW.LNCT.LLVM_source) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(file_count) + (dwarf.sectionOffsetBytes() + dir_index_info.bytes + dwarf.sectionOffsetBytes()) * file_count;
}
- const trailer_bytes = 1 + uleb128Bytes(0) +
- 1 + uleb128Bytes(1) + 1;
+ const trailer_bytes = 1 + uleb128Bytes(1) + 1;
};
const DebugLocLists = struct {
@@ -172,10 +175,15 @@ const StringSection = struct {
errdefer _ = str_sec.map.pop();
const entry: Entry.Index = @enumFromInt(gop.index);
if (!gop.found_existing) {
- assert(try str_sec.section.addEntry(unit, dwarf) == entry);
- errdefer _ = str_sec.section.getUnit(unit).entries.pop();
- const entry_ptr = str_sec.section.getUnit(unit).getEntry(entry);
- assert(entry_ptr.off == str_sec.contents.items.len);
+ const unit_ptr = str_sec.section.getUnit(unit);
+ assert(try str_sec.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
+ errdefer _ = unit_ptr.entries.pop();
+ const entry_ptr = unit_ptr.getEntry(entry);
+ if (unit_ptr.last.unwrap()) |last_entry|
+ unit_ptr.getEntry(last_entry).next = entry.toOptional();
+ entry_ptr.prev = unit_ptr.last;
+ unit_ptr.last = entry.toOptional();
+ entry_ptr.off = @intCast(str_sec.contents.items.len);
entry_ptr.len = @intCast(str.len + 1);
try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1);
str_sec.contents.appendSliceAssumeCapacity(str);
@@ -200,7 +208,7 @@ const StringSection = struct {
};
/// A linker section containing a sequence of `Unit`s.
-const Section = struct {
+pub const Section = struct {
dirty: bool,
pad_to_ideal: bool,
alignment: InternPool.Alignment,
@@ -242,7 +250,7 @@ const Section = struct {
fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
const unit: Unit.Index = @enumFromInt(sec.units.items.len);
const unit_ptr = try sec.units.addOne(dwarf.gpa);
- errdefer sec.popUnit();
+ errdefer sec.popUnit(dwarf.gpa);
unit_ptr.* = .{
.prev = sec.last,
.next = .none,
@@ -253,10 +261,8 @@ const Section = struct {
.trailer_len = trailer_len,
.len = header_len + trailer_len,
.entries = .{},
- .cross_entry_relocs = .{},
.cross_unit_relocs = .{},
.cross_section_relocs = .{},
- .external_relocs = .{},
};
if (sec.last.unwrap()) |last_unit| {
const last_unit_ptr = sec.getUnit(last_unit);
@@ -278,23 +284,34 @@ const Section = struct {
if (sec.last.unwrap().? == unit) sec.last = unit_ptr.prev;
}
- fn popUnit(sec: *Section) void {
- const unit: Unit.Index = @enumFromInt(sec.units.items.len - 1);
- sec.unlinkUnit(unit);
- _ = sec.units.pop();
- }
-
- fn addEntry(sec: *Section, unit: Unit.Index, dwarf: *Dwarf) UpdateError!Entry.Index {
- return sec.getUnit(unit).addEntry(sec, dwarf);
+ fn popUnit(sec: *Section, gpa: std.mem.Allocator) void {
+ const unit_index: Unit.Index = @enumFromInt(sec.units.items.len - 1);
+ sec.unlinkUnit(unit_index);
+ var unit = sec.units.pop();
+ unit.deinit(gpa);
}
- fn getUnit(sec: *Section, unit: Unit.Index) *Unit {
+ pub fn getUnit(sec: *Section, unit: Unit.Index) *Unit {
return &sec.units.items[@intFromEnum(unit)];
}
fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
const unit_ptr = sec.getUnit(unit);
- try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
+ const entry_ptr = unit_ptr.getEntry(entry);
+ if (contents.len > 0) {
+ if (entry_ptr.len == 0) {
+ assert(entry_ptr.prev == .none and entry_ptr.next == .none);
+ entry_ptr.off = if (unit_ptr.last.unwrap()) |last_entry| off: {
+ const last_entry_ptr = unit_ptr.getEntry(last_entry);
+ last_entry_ptr.next = entry.toOptional();
+ break :off last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
+ } else 0;
+ entry_ptr.prev = unit_ptr.last;
+ unit_ptr.last = entry.toOptional();
+ }
+ try entry_ptr.replace(unit_ptr, sec, dwarf, contents);
+ }
+ assert(entry_ptr.len == contents.len);
}
fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
@@ -358,10 +375,8 @@ const Unit = struct {
/// data length in bytes
len: u32,
entries: std.ArrayListUnmanaged(Entry),
- cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc),
cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc),
cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc),
- external_relocs: std.ArrayListUnmanaged(ExternalReloc),
const Index = enum(u32) {
main,
@@ -371,7 +386,7 @@ const Unit = struct {
none = std.math.maxInt(u32),
_,
- fn unwrap(uio: Optional) ?Index {
+ pub fn unwrap(uio: Optional) ?Index {
return if (uio != .none) @enumFromInt(@intFromEnum(uio)) else null;
}
};
@@ -381,36 +396,36 @@ const Unit = struct {
}
};
+ fn clear(unit: *Unit) void {
+ unit.cross_unit_relocs.clearRetainingCapacity();
+ unit.cross_section_relocs.clearRetainingCapacity();
+ }
+
fn deinit(unit: *Unit, gpa: std.mem.Allocator) void {
+ for (unit.entries.items) |*entry| entry.deinit(gpa);
unit.entries.deinit(gpa);
- unit.cross_entry_relocs.deinit(gpa);
unit.cross_unit_relocs.deinit(gpa);
unit.cross_section_relocs.deinit(gpa);
- unit.external_relocs.deinit(gpa);
unit.* = undefined;
}
- fn addEntry(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!Entry.Index {
+ fn addEntry(unit: *Unit, gpa: std.mem.Allocator) std.mem.Allocator.Error!Entry.Index {
const entry: Entry.Index = @enumFromInt(unit.entries.items.len);
- const entry_ptr = try unit.entries.addOne(dwarf.gpa);
+ const entry_ptr = try unit.entries.addOne(gpa);
entry_ptr.* = .{
- .prev = unit.last,
+ .prev = .none,
.next = .none,
.off = 0,
.len = 0,
+ .cross_entry_relocs = .{},
+ .cross_unit_relocs = .{},
+ .cross_section_relocs = .{},
+ .external_relocs = .{},
};
- if (unit.last.unwrap()) |last_entry| {
- const last_entry_ptr = unit.getEntry(last_entry);
- last_entry_ptr.next = entry.toOptional();
- entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
- }
- if (unit.first == .none)
- unit.first = entry.toOptional();
- unit.last = entry.toOptional();
return entry;
}
- fn getEntry(unit: *Unit, entry: Entry.Index) *Entry {
+ pub fn getEntry(unit: *Unit, entry: Entry.Index) *Entry {
return &unit.entries.items[@intFromEnum(entry)];
}
@@ -451,6 +466,14 @@ const Unit = struct {
unit_ptr.len = len;
}
+ fn trim(unit: *Unit) void {
+ const len = unit.getEntry(unit.first.unwrap() orelse return).off;
+ if (len == 0) return;
+ for (unit.entries.items) |*entry| entry.off -= len;
+ unit.off += len;
+ unit.len -= len;
+ }
+
fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
if (unit.off == new_off) return;
if (try dwarf.getFile().?.copyRangeAll(
@@ -463,6 +486,7 @@ const Unit = struct {
}
fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
+ unit.trim();
if (unit.header_len == len) return;
const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: {
const prev_unit_ptr = sec.getUnit(prev_unit);
@@ -495,63 +519,61 @@ const Unit = struct {
const last_entry_ptr = unit.getEntry(last_entry);
break :end last_entry_ptr.off + last_entry_ptr.len;
} else 0;
- const end = if (unit.next.unwrap()) |next_unit|
- sec.getUnit(next_unit).off
- else
- sec.len;
- const trailer_len: usize = @intCast(end - start);
- assert(trailer_len >= unit.trailer_len);
- var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, trailer_len);
+ const end = if (unit.next.unwrap()) |next_unit| sec.getUnit(next_unit).off else sec.len;
+ const len: usize = @intCast(end - start);
+ assert(len >= unit.trailer_len);
+ if (sec == &dwarf.debug_line.section) {
+ var buf: [1 + uleb128Bytes(std.math.maxInt(u32)) + 1]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buf);
+ const writer = fbs.writer();
+ writer.writeByte(DW.LNS.extended_op) catch unreachable;
+ const extended_op_bytes = fbs.pos;
+ var op_len_bytes: u5 = 1;
+ while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) {
+ .lt => break uleb128(writer, len - extended_op_bytes - op_len_bytes) catch unreachable,
+ .eq => {
+ // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
+ op_len_bytes += 1;
+ std.leb.writeUnsignedExtended(buf[fbs.pos..][0..op_len_bytes], len - extended_op_bytes - op_len_bytes);
+ fbs.pos += op_len_bytes;
+ break;
+ },
+ .gt => op_len_bytes += 1,
+ };
+ assert(fbs.pos == extended_op_bytes + op_len_bytes);
+ writer.writeByte(DW.LNE.padding) catch unreachable;
+ assert(fbs.pos >= unit.trailer_len and fbs.pos <= len);
+ return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + start);
+ }
+ var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, len);
defer trailer.deinit();
- const fill_byte: u8 = if (sec == &dwarf.debug_aranges.section) fill: {
+ const fill_byte: u8 = if (sec == &dwarf.debug_abbrev.section) fill: {
+ assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
+ trailer.appendAssumeCapacity(@intFromEnum(AbbrevCode.null));
+ break :fill @intFromEnum(AbbrevCode.null);
+ } else if (sec == &dwarf.debug_aranges.section) fill: {
trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2);
break :fill 0;
} else if (sec == &dwarf.debug_info.section) fill: {
assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2);
break :fill @intFromEnum(AbbrevCode.null);
- } else if (sec == &dwarf.debug_line.section) fill: {
- unit.len -= unit.trailer_len;
- const extra_len: u32 = @intCast((trailer_len - DebugLine.trailer_bytes) & 1);
- unit.trailer_len = DebugLine.trailer_bytes + extra_len;
- unit.len += unit.trailer_len;
-
- // prevent end sequence from emitting an invalid file index
- trailer.appendAssumeCapacity(DW.LNS.set_file);
- uleb128(trailer.fixedWriter(), 0) catch unreachable;
-
- trailer.appendAssumeCapacity(DW.LNS.extended_op);
- std.leb.writeUnsignedExtended(trailer.addManyAsSliceAssumeCapacity(uleb128Bytes(1) + extra_len), 1);
- trailer.appendAssumeCapacity(DW.LNE.end_sequence);
- break :fill DW.LNS.extended_op;
} else if (sec == &dwarf.debug_rnglists.section) fill: {
trailer.appendAssumeCapacity(DW.RLE.end_of_list);
break :fill DW.RLE.end_of_list;
} else unreachable;
assert(trailer.items.len == unit.trailer_len);
- trailer.appendNTimesAssumeCapacity(fill_byte, trailer_len - trailer.items.len);
- assert(trailer.items.len == trailer_len);
+ trailer.appendNTimesAssumeCapacity(fill_byte, len - trailer.items.len);
+ assert(trailer.items.len == len);
try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);
}
fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
- for (unit.cross_entry_relocs.items) |reloc| {
- try dwarf.resolveReloc(
- sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
- unit.header_len + unit.getEntry(source_entry).off
- else
- 0) + reloc.source_off,
- unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off,
- dwarf.sectionOffsetBytes(),
- );
- }
+ const unit_off = sec.off + unit.off;
for (unit.cross_unit_relocs.items) |reloc| {
const target_unit = sec.getUnit(reloc.target_unit);
try dwarf.resolveReloc(
- sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
- unit.header_len + unit.getEntry(source_entry).off
- else
- 0) + reloc.source_off,
+ unit_off + reloc.source_off,
target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
else
@@ -565,10 +587,7 @@ const Unit = struct {
};
const target_unit = target_sec.getUnit(reloc.target_unit);
try dwarf.resolveReloc(
- sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry|
- unit.header_len + unit.getEntry(source_entry).off
- else
- 0) + reloc.source_off,
+ unit_off + reloc.source_off,
target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
else
@@ -576,57 +595,8 @@ const Unit = struct {
dwarf.sectionOffsetBytes(),
);
}
- if (dwarf.bin_file.cast(.elf)) |elf_file| {
- const zo = elf_file.zigObjectPtr().?;
- for (unit.external_relocs.items) |reloc| {
- const symbol = zo.symbol(reloc.target_sym);
- try dwarf.resolveReloc(
- sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off,
- @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) -
- if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
- @intFromEnum(dwarf.address_size),
- );
- }
- } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
- const zo = macho_file.getZigObject().?;
- for (unit.external_relocs.items) |reloc| {
- const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
- try dwarf.resolveReloc(
- sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off,
- ref.getSymbol(macho_file).?.getAddress(.{}, macho_file),
- @intFromEnum(dwarf.address_size),
- );
- }
- }
+ for (unit.entries.items) |*entry| try entry.resolveRelocs(unit, sec, dwarf);
}
-
- const CrossEntryReloc = struct {
- source_entry: Entry.Index.Optional = .none,
- source_off: u32 = 0,
- target_entry: Entry.Index,
- target_off: u32 = 0,
- };
- const CrossUnitReloc = struct {
- source_entry: Entry.Index.Optional = .none,
- source_off: u32 = 0,
- target_unit: Unit.Index,
- target_entry: Entry.Index.Optional = .none,
- target_off: u32 = 0,
- };
- const CrossSectionReloc = struct {
- source_entry: Entry.Index.Optional = .none,
- source_off: u32 = 0,
- target_sec: Section.Index,
- target_unit: Unit.Index,
- target_entry: Entry.Index.Optional = .none,
- target_off: u32 = 0,
- };
- const ExternalReloc = struct {
- source_entry: Entry.Index,
- source_off: u32 = 0,
- target_sym: u32,
- target_off: u64 = 0,
- };
};
/// An indivisible entry within a `Unit` containing section-specific data.
@@ -637,6 +607,25 @@ const Entry = struct {
off: u32,
/// data length in bytes
len: u32,
+ cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc),
+ cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc),
+ cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc),
+ external_relocs: std.ArrayListUnmanaged(ExternalReloc),
+
+ fn clear(entry: *Entry) void {
+ entry.cross_entry_relocs.clearRetainingCapacity();
+ entry.cross_unit_relocs.clearRetainingCapacity();
+ entry.cross_section_relocs.clearRetainingCapacity();
+ entry.external_relocs.clearRetainingCapacity();
+ }
+
+ fn deinit(entry: *Entry, gpa: std.mem.Allocator) void {
+ entry.cross_entry_relocs.deinit(gpa);
+ entry.cross_unit_relocs.deinit(gpa);
+ entry.cross_section_relocs.deinit(gpa);
+ entry.external_relocs.deinit(gpa);
+ entry.* = undefined;
+ }
const Index = enum(u32) {
_,
@@ -645,7 +634,7 @@ const Entry = struct {
none = std.math.maxInt(u32),
_,
- fn unwrap(eio: Optional) ?Index {
+ pub fn unwrap(eio: Optional) ?Index {
return if (eio != .none) @enumFromInt(@intFromEnum(eio)) else null;
}
};
@@ -656,45 +645,62 @@ const Entry = struct {
};
fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
+ assert(entry.len > 0);
const start = entry.off + entry.len;
const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
- if (sec == &dwarf.debug_info.section) {
- var buf: [
- @max(
- uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)),
- uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
- )
- ]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- switch (len) {
- 0 => {},
- 1 => uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_1)) catch unreachable,
- else => {
- uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_n)) catch unreachable;
- const abbrev_code_bytes = fbs.pos;
- var block_len_bytes: u5 = 1;
- while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
- .lt => break uleb128(fbs.writer(), len - abbrev_code_bytes - block_len_bytes) catch unreachable,
- .eq => {
- // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
- block_len_bytes += 1;
- std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes);
- fbs.pos += block_len_bytes;
- break;
- },
- .gt => block_len_bytes += 1,
- };
- assert(fbs.pos == abbrev_code_bytes + block_len_bytes);
- },
- }
- assert(fbs.pos <= len);
- try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
- } else if (sec == &dwarf.debug_line.section) {
- const buf = try dwarf.gpa.alloc(u8, len);
- defer dwarf.gpa.free(buf);
- @memset(buf, DW.LNS.const_add_pc);
- try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start);
+ var buf: [
+ @max(
+ uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)),
+ uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
+ 1 + uleb128Bytes(std.math.maxInt(u32)) + 1,
+ )
+ ]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buf);
+ const writer = fbs.writer();
+ if (sec == &dwarf.debug_info.section) switch (len) {
+ 0 => {},
+ 1 => uleb128(writer, try dwarf.refAbbrevCode(.pad_1)) catch unreachable,
+ else => {
+ uleb128(writer, try dwarf.refAbbrevCode(.pad_n)) catch unreachable;
+ const abbrev_code_bytes = fbs.pos;
+ var block_len_bytes: u5 = 1;
+ while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
+ .lt => break uleb128(writer, len - abbrev_code_bytes - block_len_bytes) catch unreachable,
+ .eq => {
+ // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
+ block_len_bytes += 1;
+ std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes);
+ fbs.pos += block_len_bytes;
+ break;
+ },
+ .gt => block_len_bytes += 1,
+ };
+ assert(fbs.pos == abbrev_code_bytes + block_len_bytes);
+ },
+ } else if (sec == &dwarf.debug_line.section) switch (len) {
+ 0 => {},
+ 1 => writer.writeByte(DW.LNS.const_add_pc) catch unreachable,
+ else => {
+ writer.writeByte(DW.LNS.extended_op) catch unreachable;
+ const extended_op_bytes = fbs.pos;
+ var op_len_bytes: u5 = 1;
+ while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) {
+ .lt => break uleb128(writer, len - extended_op_bytes - op_len_bytes) catch unreachable,
+ .eq => {
+ // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
+ op_len_bytes += 1;
+ std.leb.writeUnsignedExtended(buf[fbs.pos..][0..op_len_bytes], len - extended_op_bytes - op_len_bytes);
+ fbs.pos += op_len_bytes;
+ break;
+ },
+ .gt => op_len_bytes += 1,
+ };
+ assert(fbs.pos == extended_op_bytes + op_len_bytes);
+ if (len > 2) writer.writeByte(DW.LNE.padding) catch unreachable;
+ },
} else assert(!sec.pad_to_ideal and len == 0);
+ assert(fbs.pos <= len);
+ try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
}
fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
@@ -722,15 +728,7 @@ const Entry = struct {
try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(contents.len) + unit.trailer_len));
}
entry_ptr.len = @intCast(contents.len);
- {
- var prev_entry_ptr = entry_ptr;
- while (prev_entry_ptr.prev.unwrap()) |prev_entry| {
- prev_entry_ptr = unit.getEntry(prev_entry);
- if (prev_entry_ptr.len == 0) continue;
- try prev_entry_ptr.pad(unit, sec, dwarf);
- break;
- }
- }
+ if (entry_ptr.prev.unwrap()) |prev_entry| try unit.getEntry(prev_entry).pad(unit, sec, dwarf);
try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
try entry_ptr.pad(unit, sec, dwarf);
if (false) {
@@ -767,7 +765,7 @@ const Entry = struct {
}
}
- fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry {
+ pub fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry {
if (entry.len > 0) return entry;
if (std.debug.runtime_safety) {
log.err("missing {} from {s}", .{
@@ -803,6 +801,88 @@ const Entry = struct {
}
@panic("missing dwarf relocation target");
}
+
+ fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
+ const entry_off = sec.off + unit.off + unit.header_len + entry.off;
+ for (entry.cross_entry_relocs.items) |reloc| {
+ try dwarf.resolveReloc(
+ entry_off + reloc.source_off,
+ unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off,
+ dwarf.sectionOffsetBytes(),
+ );
+ }
+ for (entry.cross_unit_relocs.items) |reloc| {
+ const target_unit = sec.getUnit(reloc.target_unit);
+ try dwarf.resolveReloc(
+ entry_off + reloc.source_off,
+ target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
+ target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
+ else
+ 0) + reloc.target_off,
+ dwarf.sectionOffsetBytes(),
+ );
+ }
+ for (entry.cross_section_relocs.items) |reloc| {
+ const target_sec = switch (reloc.target_sec) {
+ inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
+ };
+ const target_unit = target_sec.getUnit(reloc.target_unit);
+ try dwarf.resolveReloc(
+ entry_off + reloc.source_off,
+ target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry|
+ target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off
+ else
+ 0) + reloc.target_off,
+ dwarf.sectionOffsetBytes(),
+ );
+ }
+ if (dwarf.bin_file.cast(.elf)) |elf_file| {
+ const zo = elf_file.zigObjectPtr().?;
+ for (entry.external_relocs.items) |reloc| {
+ const symbol = zo.symbol(reloc.target_sym);
+ try dwarf.resolveReloc(
+ entry_off + reloc.source_off,
+ @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) -
+ if (symbol.flags.is_tls) elf_file.dtpAddress() else 0),
+ @intFromEnum(dwarf.address_size),
+ );
+ }
+ } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
+ const zo = macho_file.getZigObject().?;
+ for (entry.external_relocs.items) |reloc| {
+ const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
+ try dwarf.resolveReloc(
+ entry_off + reloc.source_off,
+ ref.getSymbol(macho_file).?.getAddress(.{}, macho_file),
+ @intFromEnum(dwarf.address_size),
+ );
+ }
+ }
+ }
+};
+
+const CrossEntryReloc = struct {
+ source_off: u32 = 0,
+ target_entry: Entry.Index,
+ target_off: u32 = 0,
+};
+const CrossUnitReloc = struct {
+ source_off: u32 = 0,
+ target_unit: Unit.Index,
+ target_entry: Entry.Index.Optional = .none,
+ target_off: u32 = 0,
+};
+const CrossSectionReloc = struct {
+ source_off: u32 = 0,
+ target_sec: Section.Index,
+ target_unit: Unit.Index,
+ target_entry: Entry.Index.Optional = .none,
+ target_off: u32 = 0,
+};
+const ExternalReloc = struct {
+ source_off: u32 = 0,
+ target_sym: u32,
+ target_off: u64 = 0,
};
pub const Loc = union(enum) {
@@ -986,7 +1066,12 @@ pub const WipNav = struct {
entry: Entry.Index,
any_children: bool,
func: InternPool.Index,
+ func_sym_index: u32,
func_high_reloc: u32,
+ inlined_funcs: std.ArrayListUnmanaged(struct {
+ abbrev_code: u32,
+ high_reloc: u32,
+ }),
debug_info: std.ArrayListUnmanaged(u8),
debug_line: std.ArrayListUnmanaged(u8),
debug_loclists: std.ArrayListUnmanaged(u8),
@@ -994,6 +1079,7 @@ pub const WipNav = struct {
pub fn deinit(wip_nav: *WipNav) void {
const gpa = wip_nav.dwarf.gpa;
+ if (wip_nav.func != .none) wip_nav.inlined_funcs.deinit(gpa);
wip_nav.debug_info.deinit(gpa);
wip_nav.debug_line.deinit(gpa);
wip_nav.debug_loclists.deinit(gpa);
@@ -1004,23 +1090,28 @@ pub const WipNav = struct {
return wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
}
- pub const VarTag = enum { local_arg, local_var };
- pub fn genVarDebugInfo(
+ pub const LocalTag = enum { local_arg, local_var };
+ pub fn genLocalDebugInfo(
wip_nav: *WipNav,
- tag: VarTag,
+ tag: LocalTag,
name: []const u8,
ty: Type,
loc: Loc,
) UpdateError!void {
- wip_nav.any_children = true;
assert(wip_nav.func != .none);
- const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
- try uleb128(diw, @intFromEnum(switch (tag) {
+ try wip_nav.abbrevCode(switch (tag) {
inline else => |ct_tag| @field(AbbrevCode, @tagName(ct_tag)),
- }));
+ });
try wip_nav.strp(name);
try wip_nav.refType(ty);
try wip_nav.exprloc(loc);
+ wip_nav.any_children = true;
+ }
+
+ pub fn genVarArgsDebugInfo(wip_nav: *WipNav) UpdateError!void {
+ assert(wip_nav.func != .none);
+ try wip_nav.abbrevCode(.is_var_args);
+ wip_nav.any_children = true;
}
pub fn advancePCAndLine(
@@ -1078,6 +1169,53 @@ pub const WipNav = struct {
try dlw.writeByte(DW.LNS.set_epilogue_begin);
}
+ pub fn enterInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64, line: u32, column: u32) UpdateError!void {
+ const dwarf = wip_nav.dwarf;
+ const zcu = wip_nav.pt.zcu;
+ const diw = wip_nav.debug_info.writer(dwarf.gpa);
+ const inlined_func = try wip_nav.inlined_funcs.addOne(dwarf.gpa);
+
+ inlined_func.abbrev_code = @intCast(wip_nav.debug_info.items.len);
+ try wip_nav.abbrevCode(.inlined_func);
+ try wip_nav.refNav(zcu.funcInfo(func).owner_nav);
+ try uleb128(diw, zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1);
+ try uleb128(diw, column + 1);
+ const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
+ try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2);
+ external_relocs.appendAssumeCapacity(.{
+ .source_off = @intCast(wip_nav.debug_info.items.len),
+ .target_sym = wip_nav.func_sym_index,
+ .target_off = code_off,
+ });
+ try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
+ inlined_func.high_reloc = @intCast(external_relocs.items.len);
+ external_relocs.appendAssumeCapacity(.{
+ .source_off = @intCast(wip_nav.debug_info.items.len),
+ .target_sym = wip_nav.func_sym_index,
+ .target_off = undefined,
+ });
+ try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
+ try wip_nav.setInlineFunc(func);
+ wip_nav.any_children = false;
+ }
+
+ pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void {
+ const inlined_func_bytes = comptime uleb128Bytes(@intFromEnum(AbbrevCode.inlined_func));
+ const inlined_func = wip_nav.inlined_funcs.pop();
+ const external_relocs = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
+ external_relocs.items[inlined_func.high_reloc].target_off = code_off;
+ if (wip_nav.any_children)
+ try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), @intFromEnum(AbbrevCode.null))
+ else
+ std.leb.writeUnsignedFixed(
+ inlined_func_bytes,
+ wip_nav.debug_info.items[inlined_func.abbrev_code..][0..inlined_func_bytes],
+ try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func),
+ );
+ try wip_nav.setInlineFunc(func);
+ wip_nav.any_children = true;
+ }
+
pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
const zcu = wip_nav.pt.zcu;
const dwarf = wip_nav.dwarf;
@@ -1096,8 +1234,7 @@ pub const WipNav = struct {
try dlw.writeByte(DW.LNS.extended_op);
try uleb128(dlw, 1 + dwarf.sectionOffsetBytes());
try dlw.writeByte(DW.LNE.ZIG_set_decl);
- try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{
- .source_entry = wip_nav.entry.toOptional(),
+ try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
.source_off = @intCast(wip_nav.debug_line.items.len),
.target_sec = .debug_info,
.target_unit = new_unit,
@@ -1130,12 +1267,16 @@ pub const WipNav = struct {
wip_nav.func = func;
}
+ fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) UpdateError!void {
+ try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), try wip_nav.dwarf.refAbbrevCode(abbrev_code));
+ }
+
fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void {
const dwarf = wip_nav.dwarf;
const gpa = dwarf.gpa;
+ const entry_ptr = dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
if (sec != .debug_info) {
- try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_section_relocs.append(gpa, .{
- .source_entry = wip_nav.entry.toOptional(),
+ try entry_ptr.cross_section_relocs.append(gpa, .{
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_sec = sec,
.target_unit = unit,
@@ -1143,16 +1284,14 @@ pub const WipNav = struct {
.target_off = off,
});
} else if (unit != wip_nav.unit) {
- try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_unit_relocs.append(gpa, .{
- .source_entry = wip_nav.entry.toOptional(),
+ try entry_ptr.cross_unit_relocs.append(gpa, .{
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_unit = unit,
.target_entry = entry.toOptional(),
.target_off = off,
});
} else {
- try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.append(gpa, .{
- .source_entry = wip_nav.entry.toOptional(),
+ try entry_ptr.cross_entry_relocs.append(gpa, .{
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_entry = entry,
.target_off = off,
@@ -1167,8 +1306,7 @@ pub const WipNav = struct {
fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
const dwarf = wip_nav.dwarf;
- try dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
- .source_entry = wip_nav.entry,
+ try dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_sym = sym_index,
});
@@ -1217,12 +1355,20 @@ pub const WipNav = struct {
try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
}
+ fn refNav(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!void {
+ const zcu = wip_nav.pt.zcu;
+ const ip = &zcu.intern_pool;
+ const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav_index).srcInst(ip).resolveFile(ip)).mod);
+ const nav_gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index);
+ if (!nav_gop.found_existing) nav_gop.value_ptr.* = try wip_nav.dwarf.addCommonEntry(unit);
+ try wip_nav.infoSectionOffset(.debug_info, unit, nav_gop.value_ptr.*, 0);
+ }
+
fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 {
const dwarf = wip_nav.dwarf;
- const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs;
+ const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs;
const reloc_index: u32 = @intCast(cross_entry_relocs.items.len);
try cross_entry_relocs.append(dwarf.gpa, .{
- .source_entry = wip_nav.entry.toOptional(),
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_entry = undefined,
.target_off = undefined,
@@ -1232,7 +1378,7 @@ pub const WipNav = struct {
}
fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
- const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.items[reloc_index];
+ const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index];
reloc.target_entry = wip_nav.entry;
reloc.target_off = @intCast(wip_nav.debug_info.items.len);
}
@@ -1240,9 +1386,13 @@ pub const WipNav = struct {
fn enumConstValue(
wip_nav: *WipNav,
loaded_enum: InternPool.LoadedEnumType,
- abbrev_code: std.enums.EnumFieldStruct(std.builtin.Signedness, AbbrevCode, null),
+ abbrev_code: struct {
+ sdata: AbbrevCode,
+ udata: AbbrevCode,
+ block: AbbrevCode,
+ },
field_index: usize,
- ) std.mem.Allocator.Error!void {
+ ) UpdateError!void {
const zcu = wip_nav.pt.zcu;
const ip = &zcu.intern_pool;
const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
@@ -1250,20 +1400,15 @@ pub const WipNav = struct {
.comptime_int_type => .signed,
else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness,
};
- try uleb128(diw, @intFromEnum(switch (signedness) {
- inline .signed, .unsigned => |ct_signedness| @field(abbrev_code, @tagName(ct_signedness)),
- }));
- if (loaded_enum.values.len > 0) switch (ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage) {
- .u64 => |value| switch (signedness) {
- .signed => try sleb128(diw, value),
- .unsigned => try uleb128(diw, value),
- },
- .i64 => |value| switch (signedness) {
- .signed => try sleb128(diw, value),
- .unsigned => unreachable,
- },
- .big_int => |big_int| {
- const bits = big_int.bitCountTwosCompForSignedness(signedness);
+ if (loaded_enum.values.len > 0) {
+ var big_int_space: InternPool.Key.Int.Storage.BigIntSpace = undefined;
+ const big_int = ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage.toBigInt(&big_int_space);
+ const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness));
+ if (bits <= 64) {
+ try wip_nav.abbrevCode(switch (signedness) {
+ .signed => abbrev_code.sdata,
+ .unsigned => abbrev_code.udata,
+ });
try wip_nav.debug_info.ensureUnusedCapacity(wip_nav.dwarf.gpa, std.math.divCeil(usize, bits, 7) catch unreachable);
var bit: usize = 0;
var carry: u1 = 1;
@@ -1272,11 +1417,8 @@ pub const WipNav = struct {
const limb_index = bit / limb_bits;
const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits);
const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift);
- const abs_part = if (limb_shift > limb_bits - 7) abs_part: {
- const next_limb: std.math.big.Limb = if (limb_index + 1 < big_int.limbs.len)
- big_int.limbs[limb_index + 1]
- else if (big_int.positive) 0 else std.math.maxInt(std.math.big.Limb);
- const high_abs_part: u7 = @truncate(next_limb << -%limb_shift);
+ const abs_part = if (limb_shift > limb_bits - 7 and limb_index + 1 < big_int.limbs.len) abs_part: {
+ const high_abs_part: u7 = @truncate(big_int.limbs[limb_index + 1] << -%limb_shift);
break :abs_part high_abs_part | low_abs_part;
} else low_abs_part;
const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: {
@@ -1285,11 +1427,21 @@ pub const WipNav = struct {
};
wip_nav.debug_info.appendAssumeCapacity(@as(u8, if (bit + 7 < bits) 0x80 else 0x00) | twos_comp_part);
}
- },
- .lazy_align, .lazy_size => unreachable,
+ } else {
+ try wip_nav.abbrevCode(abbrev_code.block);
+ const bytes = Type.fromInterned(loaded_enum.tag_ty).abiSize(wip_nav.pt);
+ try uleb128(diw, bytes);
+ big_int.writeTwosComplement(try wip_nav.debug_info.addManyAsSlice(wip_nav.dwarf.gpa, @intCast(bytes)), wip_nav.dwarf.endian);
+ }
} else switch (signedness) {
- .signed => try sleb128(diw, field_index),
- .unsigned => try uleb128(diw, field_index),
+ .signed => {
+ try wip_nav.abbrevCode(abbrev_code.sdata);
+ try sleb128(diw, field_index);
+ },
+ .unsigned => {
+ try wip_nav.abbrevCode(abbrev_code.udata);
+ try uleb128(diw, field_index);
+ },
}
}
@@ -1441,20 +1593,21 @@ pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
dwarf.reloadSectionMetadata();
dwarf.debug_abbrev.section.pad_to_ideal = false;
- assert(try dwarf.debug_abbrev.section.addUnit(0, 0, dwarf) == DebugAbbrev.unit);
- errdefer dwarf.debug_abbrev.section.popUnit();
- assert(try dwarf.debug_abbrev.section.addEntry(DebugAbbrev.unit, dwarf) == DebugAbbrev.entry);
+ assert(try dwarf.debug_abbrev.section.addUnit(DebugAbbrev.header_bytes, DebugAbbrev.trailer_bytes, dwarf) == DebugAbbrev.unit);
+ errdefer dwarf.debug_abbrev.section.popUnit(dwarf.gpa);
+ for (std.enums.values(AbbrevCode)) |abbrev_code|
+ assert(@intFromEnum(try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).addEntry(dwarf.gpa)) == @intFromEnum(abbrev_code));
dwarf.debug_aranges.section.pad_to_ideal = false;
dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);
dwarf.debug_line_str.section.pad_to_ideal = false;
assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
- errdefer dwarf.debug_line_str.section.popUnit();
+ errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa);
dwarf.debug_str.section.pad_to_ideal = false;
assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
- errdefer dwarf.debug_str.section.popUnit();
+ errdefer dwarf.debug_str.section.popUnit(dwarf.gpa);
dwarf.debug_loclists.section.pad_to_ideal = false;
@@ -1495,31 +1648,31 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index {
DebugAranges.trailerBytes(dwarf),
dwarf,
) == unit);
- errdefer dwarf.debug_aranges.section.popUnit();
+ errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
assert(try dwarf.debug_info.section.addUnit(
DebugInfo.headerBytes(dwarf),
DebugInfo.trailer_bytes,
dwarf,
) == unit);
- errdefer dwarf.debug_info.section.popUnit();
+ errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);
assert(try dwarf.debug_line.section.addUnit(
DebugLine.headerBytes(dwarf, 5, 25),
DebugLine.trailer_bytes,
dwarf,
) == unit);
- errdefer dwarf.debug_line.section.popUnit();
+ errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);
assert(try dwarf.debug_loclists.section.addUnit(
DebugLocLists.headerBytes(dwarf),
DebugLocLists.trailer_bytes,
dwarf,
) == unit);
- errdefer dwarf.debug_loclists.section.popUnit();
+ errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);
assert(try dwarf.debug_rnglists.section.addUnit(
DebugRngLists.headerBytes(dwarf),
DebugRngLists.trailer_bytes,
dwarf,
) == unit);
- errdefer dwarf.debug_rnglists.section.popUnit();
+ errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa);
}
return unit;
}
@@ -1545,7 +1698,15 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
const unit = try dwarf.getUnit(file.mod);
const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
errdefer _ = dwarf.navs.pop();
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (nav_gop.found_existing) {
+ for ([_]*Section{
+ &dwarf.debug_aranges.section,
+ &dwarf.debug_info.section,
+ &dwarf.debug_line.section,
+ &dwarf.debug_loclists.section,
+ &dwarf.debug_rnglists.section,
+ }) |sec| sec.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear();
+ } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
const nav_val = zcu.navValue(nav_index);
var wip_nav: WipNav = .{
.dwarf = dwarf,
@@ -1554,7 +1715,9 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
.entry = nav_gop.value_ptr.*,
.any_children = false,
.func = .none,
+ .func_sym_index = undefined,
.func_high_reloc = undefined,
+ .inlined_funcs = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@@ -1595,7 +1758,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
} else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
+ try wip_nav.abbrevCode(.decl_var);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -1608,18 +1771,9 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
try wip_nav.exprloc(.{ .addr = .{ .sym = sym_index } });
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
ty.abiAlignment(pt).toByteUnits().?);
- const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
- try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
- zcu.all_exports.items[export_index..][0..1]
- else if (zcu.multi_exports.get(func_unit)) |export_range|
- zcu.all_exports.items[export_range.index..][0..export_range.len]
- else
- &.{}) |@"export"|
- {
- if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
- } else false));
+ try diw.writeByte(@intFromBool(false));
wip_nav.finishForward(ty_reloc_index);
- try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
+ try wip_nav.abbrevCode(.is_const);
try wip_nav.refType(ty);
},
.variable => |variable| {
@@ -1654,7 +1808,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
} else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
+ try wip_nav.abbrevCode(.decl_var);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -1668,16 +1822,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
try wip_nav.exprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr);
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
ty.abiAlignment(pt).toByteUnits().?);
- const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
- try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
- zcu.all_exports.items[export_index..][0..1]
- else if (zcu.multi_exports.get(func_unit)) |export_range|
- zcu.all_exports.items[export_range.index..][0..export_range.len]
- else
- &.{}) |@"export"|
- {
- if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
- } else false));
+ try diw.writeByte(@intFromBool(false));
},
.func => |func| {
assert(file.zir_loaded);
@@ -1712,9 +1857,11 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
const func_type = ip.indexToKey(func.ty).func_type;
wip_nav.func = nav_val.toIntern();
+ wip_nav.func_sym_index = sym_index;
+ wip_nav.inlined_funcs = .{};
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_func));
+ try wip_nav.abbrevCode(.decl_func);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -1723,32 +1870,23 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
try wip_nav.strp(nav.name.toSlice(ip));
try wip_nav.strp(nav.fqn.toSlice(ip));
try wip_nav.refType(Type.fromInterned(func_type.return_type));
- const external_relocs = &dwarf.debug_info.section.getUnit(unit).external_relocs;
- try external_relocs.append(dwarf.gpa, .{
- .source_entry = wip_nav.entry,
+ const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
+ try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2);
+ external_relocs.appendAssumeCapacity(.{
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_sym = sym_index,
});
try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
wip_nav.func_high_reloc = @intCast(external_relocs.items.len);
- try external_relocs.append(dwarf.gpa, .{
- .source_entry = wip_nav.entry,
+ external_relocs.appendAssumeCapacity(.{
.source_off = @intCast(wip_nav.debug_info.items.len),
.target_sym = sym_index,
+ .target_off = undefined,
});
try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
target_info.defaultFunctionAlignment(file.mod.resolved_target.result).toByteUnits().?);
- const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() });
- try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index|
- zcu.all_exports.items[export_index..][0..1]
- else if (zcu.multi_exports.get(func_unit)) |export_range|
- zcu.all_exports.items[export_range.index..][0..export_range.len]
- else
- &.{}) |@"export"|
- {
- if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true;
- } else false));
+ try diw.writeByte(@intFromBool(false));
try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type));
const dlw = wip_nav.debug_line.writer(dwarf.gpa);
@@ -1756,8 +1894,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
if (dwarf.incremental()) {
try uleb128(dlw, 1 + dwarf.sectionOffsetBytes());
try dlw.writeByte(DW.LNE.ZIG_set_decl);
- try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{
- .source_entry = wip_nav.entry.toOptional(),
+ try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
.source_off = @intCast(wip_nav.debug_line.items.len),
.target_sec = .debug_info,
.target_unit = wip_nav.unit,
@@ -1772,8 +1909,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
} else {
try uleb128(dlw, 1 + @intFromEnum(dwarf.address_size));
try dlw.writeByte(DW.LNE.set_address);
- try dwarf.debug_line.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
- .source_entry = wip_nav.entry,
+ try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
.source_off = @intCast(wip_nav.debug_line.items.len),
.target_sym = sym_index,
});
@@ -1806,19 +1942,19 @@ pub fn finishWipNav(
log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});
if (wip_nav.func != .none) {
- dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
+ const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
+ external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
if (wip_nav.any_children) {
const diw = wip_nav.debug_info.writer(dwarf.gpa);
try uleb128(diw, @intFromEnum(AbbrevCode.null));
} else std.leb.writeUnsignedFixed(
AbbrevCode.decl_bytes,
wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],
- @intFromEnum(AbbrevCode.decl_func_empty),
+ try dwarf.refAbbrevCode(.decl_empty_func),
);
var aranges_entry = [1]u8{0} ** (8 + 8);
- try dwarf.debug_aranges.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{
- .source_entry = wip_nav.entry,
+ try dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
.target_sym = sym.index,
});
dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
@@ -1832,14 +1968,12 @@ pub fn finishWipNav(
aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2],
);
- try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).external_relocs.appendSlice(dwarf.gpa, &.{
+ try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{
.{
- .source_entry = wip_nav.entry,
.source_off = 1,
.target_sym = sym.index,
},
.{
- .source_entry = wip_nav.entry,
.source_off = 1 + @intFromEnum(dwarf.address_size),
.target_sym = sym.index,
.target_off = sym.size,
@@ -1883,15 +2017,16 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
const loc = tree.tokenLocation(0, tree.nodes.items(.main_token)[decl_inst.data.declaration.src_node]);
assert(loc.line == zcu.navSrcLine(nav_index));
- const unit = try dwarf.getUnit(file.mod);
var wip_nav: WipNav = .{
.dwarf = dwarf,
.pt = pt,
- .unit = unit,
+ .unit = try dwarf.getUnit(file.mod),
.entry = undefined,
.any_children = false,
.func = .none,
+ .func_sym_index = undefined,
.func_high_reloc = undefined,
+ .inlined_funcs = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@@ -1902,6 +2037,65 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
errdefer _ = dwarf.navs.pop();
switch (ip.indexToKey(nav_val.toIntern())) {
+ .func => |func| {
+ if (nav_gop.found_existing) {
+ const unit_ptr = dwarf.debug_info.section.getUnit(wip_nav.unit);
+ const entry_ptr = unit_ptr.getEntry(nav_gop.value_ptr.*);
+ if (entry_ptr.len >= AbbrevCode.decl_bytes) {
+ var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;
+ if (try dwarf.getFile().?.preadAll(
+ &abbrev_code_buf,
+ dwarf.debug_info.section.off + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
+ ) != abbrev_code_buf.len) return error.InputOutput;
+ var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf);
+ const abbrev_code: AbbrevCode = @enumFromInt(
+ std.leb.readUleb128(@typeInfo(AbbrevCode).Enum.tag_type, abbrev_code_fbs.reader()) catch unreachable,
+ );
+ switch (abbrev_code) {
+ else => unreachable,
+ .decl_func, .decl_empty_func => return,
+ .decl_func_generic, .decl_empty_func_generic => {},
+ }
+ }
+ entry_ptr.clear();
+ } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
+ wip_nav.entry = nav_gop.value_ptr.*;
+
+ const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
+ const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
+ break :parent .{
+ parent_namespace_ptr.owner_type,
+ if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu }))
+ DW.ACCESS.public
+ else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu }))
+ DW.ACCESS.private
+ else
+ unreachable,
+ };
+ } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
+
+ const func_type = ip.indexToKey(func.ty).func_type;
+ const diw = wip_nav.debug_info.writer(dwarf.gpa);
+ try wip_nav.abbrevCode(if (func_type.param_types.len > 0 or func_type.is_var_args)
+ .decl_func_generic
+ else
+ .decl_empty_func_generic);
+ try wip_nav.refType(Type.fromInterned(parent_type));
+ assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
+ try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
+ try uleb128(diw, loc.column + 1);
+ try diw.writeByte(accessibility);
+ try wip_nav.strp(nav.name.toSlice(ip));
+ try wip_nav.refType(Type.fromInterned(func_type.return_type));
+ if (func_type.param_types.len > 0 or func_type.is_var_args) {
+ for (0..func_type.param_types.len) |param_index| {
+ try wip_nav.abbrevCode(.func_type_param);
+ try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
+ }
+ if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
+ try uleb128(diw, @intFromEnum(AbbrevCode.null));
+ }
+ },
.struct_type => done: {
const loaded_struct = ip.loadStructType(nav_val.toIntern());
@@ -1941,8 +2135,14 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
if (type_inst_info.inst != value_inst) break :decl_struct;
const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (type_gop.found_existing) {
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
+ nav_gop.value_ptr.* = type_gop.value_ptr.*;
+ } else {
+ if (nav_gop.found_existing)
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+ else
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
type_gop.value_ptr.* = nav_gop.value_ptr.*;
}
wip_nav.entry = nav_gop.value_ptr.*;
@@ -1950,10 +2150,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
switch (loaded_struct.layout) {
.auto, .@"extern" => {
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
- .decl_namespace_struct
- else
- .decl_struct)));
+ try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .decl_namespace_struct else .decl_struct);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -1965,7 +2162,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
try uleb128(diw, nav_val.toType().abiAlignment(pt).toByteUnits().?);
for (0..loaded_struct.field_types.len) |field_index| {
const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
+ try wip_nav.abbrevCode(if (is_comptime) .struct_field_comptime else .struct_field);
if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
defer dwarf.gpa.free(field_name);
@@ -1983,7 +2180,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
}
},
.@"packed" => {
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_packed_struct));
+ try wip_nav.abbrevCode(.decl_packed_struct);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -1993,7 +2190,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
var field_bit_offset: u16 = 0;
for (0..loaded_struct.field_types.len) |field_index| {
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
+ try wip_nav.abbrevCode(.packed_struct_field);
try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
try wip_nav.refType(field_type);
@@ -2006,10 +2203,13 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
break :done;
}
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (nav_gop.found_existing)
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+ else
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
wip_nav.entry = nav_gop.value_ptr.*;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
+ try wip_nav.abbrevCode(.decl_alias);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2057,13 +2257,19 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
if (type_inst_info.inst != value_inst) break :decl_enum;
const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (type_gop.found_existing) {
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
+ nav_gop.value_ptr.* = type_gop.value_ptr.*;
+ } else {
+ if (nav_gop.found_existing)
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+ else
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
type_gop.value_ptr.* = nav_gop.value_ptr.*;
}
wip_nav.entry = nav_gop.value_ptr.*;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_enum));
+ try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .decl_enum else .decl_empty_enum);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2073,19 +2279,23 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
for (0..loaded_enum.names.len) |field_index| {
try wip_nav.enumConstValue(loaded_enum, .{
- .signed = .signed_enum_field,
- .unsigned = .unsigned_enum_field,
+ .sdata = .signed_enum_field,
+ .udata = .unsigned_enum_field,
+ .block = .big_enum_field,
}, field_index);
try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
}
- try uleb128(diw, @intFromEnum(AbbrevCode.null));
+ if (loaded_enum.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
break :done;
}
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (nav_gop.found_existing)
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+ else
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
wip_nav.entry = nav_gop.value_ptr.*;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
+ try wip_nav.abbrevCode(.decl_alias);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2131,13 +2341,19 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
if (type_inst_info.inst != value_inst) break :decl_union;
const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (type_gop.found_existing) {
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
+ nav_gop.value_ptr.* = type_gop.value_ptr.*;
+ } else {
+ if (nav_gop.found_existing)
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+ else
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
type_gop.value_ptr.* = nav_gop.value_ptr.*;
}
wip_nav.entry = nav_gop.value_ptr.*;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_union));
+ try wip_nav.abbrevCode(.decl_union);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2149,7 +2365,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
try uleb128(diw, union_layout.abi_align.toByteUnits().?);
const loaded_tag = loaded_union.loadTagType(ip);
if (loaded_union.hasTag(ip)) {
- try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
+ try wip_nav.abbrevCode(.tagged_union);
try wip_nav.infoSectionOffset(
.debug_info,
wip_nav.unit,
@@ -2157,18 +2373,19 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
@intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("tag");
try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
try uleb128(diw, union_layout.tagOffset());
for (0..loaded_union.field_types.len) |field_index| {
try wip_nav.enumConstValue(loaded_tag, .{
- .signed = .signed_tagged_union_field,
- .unsigned = .unsigned_tagged_union_field,
+ .sdata = .signed_tagged_union_field,
+ .udata = .unsigned_tagged_union_field,
+ .block = .big_tagged_union_field,
}, field_index);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
+ try wip_nav.abbrevCode(.struct_field);
try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
try wip_nav.refType(field_type);
@@ -2184,7 +2401,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
} else for (0..loaded_union.field_types.len) |field_index| {
- try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
+ try wip_nav.abbrevCode(.untagged_union_field);
try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
try wip_nav.refType(field_type);
@@ -2195,10 +2412,13 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
break :done;
}
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (nav_gop.found_existing)
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+ else
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
wip_nav.entry = nav_gop.value_ptr.*;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
+ try wip_nav.abbrevCode(.decl_alias);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2244,13 +2464,19 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
if (type_inst_info.inst != value_inst) break :decl_opaque;
const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) nav_gop.value_ptr.* = type_gop.value_ptr.* else {
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (type_gop.found_existing) {
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).clear();
+ nav_gop.value_ptr.* = type_gop.value_ptr.*;
+ } else {
+ if (nav_gop.found_existing)
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+ else
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
type_gop.value_ptr.* = nav_gop.value_ptr.*;
}
wip_nav.entry = nav_gop.value_ptr.*;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_namespace_struct));
+ try wip_nav.abbrevCode(.decl_namespace_struct);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2261,10 +2487,13 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
break :done;
}
- if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
+ if (nav_gop.found_existing)
+ dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
+ else
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
wip_nav.entry = nav_gop.value_ptr.*;
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
+ try wip_nav.abbrevCode(.decl_alias);
try wip_nav.refType(Type.fromInterned(parent_type));
assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2279,7 +2508,6 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
},
}
try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
- try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items);
try wip_nav.flush();
}
@@ -2304,7 +2532,9 @@ fn updateType(
.entry = dwarf.types.get(type_index).?,
.any_children = false,
.func = .none,
+ .func_sym_index = undefined,
.func_high_reloc = undefined,
+ .inlined_funcs = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@@ -2324,7 +2554,7 @@ fn updateType(
switch (ip.indexToKey(type_index)) {
.int_type => |int_type| {
- try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
+ try wip_nav.abbrevCode(.numeric_type);
try wip_nav.strp(name);
try diw.writeByte(switch (int_type.signedness) {
inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
@@ -2336,7 +2566,7 @@ fn updateType(
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
.One, .Many, .C => {
const ptr_child_type = Type.fromInterned(ptr_type.child);
- try uleb128(diw, @intFromEnum(AbbrevCode.ptr_type));
+ try wip_nav.abbrevCode(.ptr_type);
try wip_nav.strp(name);
try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse
ptr_child_type.abiAlignment(pt).toByteUnits().?);
@@ -2348,7 +2578,7 @@ fn updateType(
@intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
) else try wip_nav.refType(ptr_child_type);
if (ptr_type.flags.is_const) {
- try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
+ try wip_nav.abbrevCode(.is_const);
if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
.debug_info,
wip_nav.unit,
@@ -2357,21 +2587,21 @@ fn updateType(
) else try wip_nav.refType(ptr_child_type);
}
if (ptr_type.flags.is_volatile) {
- try uleb128(diw, @intFromEnum(AbbrevCode.is_volatile));
+ try wip_nav.abbrevCode(.is_volatile);
try wip_nav.refType(ptr_child_type);
}
},
.Slice => {
- try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
+ try wip_nav.abbrevCode(.struct_type);
try wip_nav.strp(name);
try uleb128(diw, ty.abiSize(pt));
try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("ptr");
const ptr_field_type = ty.slicePtrFieldType(zcu);
try wip_nav.refType(ptr_field_type);
try uleb128(diw, 0);
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("len");
const len_field_type = Type.usize;
try wip_nav.refType(len_field_type);
@@ -2380,28 +2610,28 @@ fn updateType(
},
},
inline .array_type, .vector_type => |array_type, ty_tag| {
- try uleb128(diw, @intFromEnum(AbbrevCode.array_type));
+ try wip_nav.abbrevCode(.array_type);
try wip_nav.strp(name);
try wip_nav.refType(Type.fromInterned(array_type.child));
try diw.writeByte(@intFromBool(ty_tag == .vector_type));
- try uleb128(diw, @intFromEnum(AbbrevCode.array_index));
+ try wip_nav.abbrevCode(.array_index);
try wip_nav.refType(Type.usize);
try uleb128(diw, array_type.len);
try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
.opt_type => |opt_child_type_index| {
const opt_child_type = Type.fromInterned(opt_child_type_index);
- try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
+ try wip_nav.abbrevCode(.union_type);
try wip_nav.strp(name);
try uleb128(diw, ty.abiSize(pt));
try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
if (opt_child_type.isNoReturn(zcu)) {
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("null");
try wip_nav.refType(Type.null);
try uleb128(diw, 0);
} else {
- try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
+ try wip_nav.abbrevCode(.tagged_union);
try wip_nav.infoSectionOffset(
.debug_info,
wip_nav.unit,
@@ -2409,7 +2639,7 @@ fn updateType(
@intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("has_value");
const repr: enum { unpacked, error_set, pointer } = switch (opt_child_type_index) {
.anyerror_type => .error_set,
@@ -2440,19 +2670,19 @@ fn updateType(
},
}
- try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
+ try wip_nav.abbrevCode(.unsigned_tagged_union_field);
try uleb128(diw, 0);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("null");
try wip_nav.refType(Type.null);
try uleb128(diw, 0);
}
try uleb128(diw, @intFromEnum(AbbrevCode.null));
- try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
+ try wip_nav.abbrevCode(.tagged_union_default_field);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("?");
try wip_nav.refType(opt_child_type);
try uleb128(diw, 0);
@@ -2467,15 +2697,27 @@ fn updateType(
.error_union_type => |error_union_type| {
const error_union_error_set_type = Type.fromInterned(error_union_type.error_set_type);
const error_union_payload_type = Type.fromInterned(error_union_type.payload_type);
- const error_union_error_set_offset = codegen.errUnionErrorOffset(error_union_payload_type, pt);
- const error_union_payload_offset = codegen.errUnionPayloadOffset(error_union_payload_type, pt);
+ const error_union_error_set_offset, const error_union_payload_offset = switch (error_union_type.payload_type) {
+ .generic_poison_type => .{ 0, 0 },
+ else => .{
+ codegen.errUnionErrorOffset(error_union_payload_type, pt),
+ codegen.errUnionPayloadOffset(error_union_payload_type, pt),
+ },
+ };
- try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
+ try wip_nav.abbrevCode(.union_type);
try wip_nav.strp(name);
- try uleb128(diw, ty.abiSize(pt));
- try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
+ if (error_union_type.error_set_type != .generic_poison_type and
+ error_union_type.payload_type != .generic_poison_type)
+ {
+ try uleb128(diw, ty.abiSize(pt));
+ try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
+ } else {
+ try uleb128(diw, 0);
+ try uleb128(diw, 1);
+ }
{
- try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
+ try wip_nav.abbrevCode(.tagged_union);
try wip_nav.infoSectionOffset(
.debug_info,
wip_nav.unit,
@@ -2483,7 +2725,7 @@ fn updateType(
@intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("is_error");
try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
@@ -2491,19 +2733,19 @@ fn updateType(
} })));
try uleb128(diw, error_union_error_set_offset);
- try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
+ try wip_nav.abbrevCode(.unsigned_tagged_union_field);
try uleb128(diw, 0);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("value");
try wip_nav.refType(error_union_payload_type);
try uleb128(diw, error_union_payload_offset);
}
try uleb128(diw, @intFromEnum(AbbrevCode.null));
- try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
+ try wip_nav.abbrevCode(.tagged_union_default_field);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("error");
try wip_nav.refType(error_union_error_set_type);
try uleb128(diw, error_union_error_set_offset);
@@ -2534,7 +2776,7 @@ fn updateType(
.c_longdouble,
.bool,
=> {
- try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
+ try wip_nav.abbrevCode(.numeric_type);
try wip_nav.strp(name);
try diw.writeByte(if (type_index == .bool_type)
DW.ATE.boolean
@@ -2561,7 +2803,7 @@ fn updateType(
.enum_literal,
.generic_poison,
=> {
- try uleb128(diw, @intFromEnum(AbbrevCode.void_type));
+ try wip_nav.abbrevCode(.void_type);
try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name);
},
.anyerror => return, // delay until flush
@@ -2571,15 +2813,19 @@ fn updateType(
.union_type,
.opaque_type,
=> unreachable,
- .anon_struct_type => |anon_struct_type| {
- try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
+ .anon_struct_type => |anon_struct_type| if (anon_struct_type.types.len == 0) {
+ try wip_nav.abbrevCode(.namespace_struct_type);
+ try wip_nav.strp(name);
+ try diw.writeByte(@intFromBool(false));
+ } else {
+ try wip_nav.abbrevCode(.struct_type);
try wip_nav.strp(name);
try uleb128(diw, ty.abiSize(pt));
try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
var field_byte_offset: u64 = 0;
for (0..anon_struct_type.types.len) |field_index| {
const comptime_value = anon_struct_type.values.get(ip)[field_index];
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (comptime_value != .none) .struct_field_comptime else .struct_field)));
+ try wip_nav.abbrevCode(if (comptime_value != .none) .struct_field_comptime else .struct_field);
if (anon_struct_type.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
defer dwarf.gpa.free(field_name);
@@ -2599,21 +2845,22 @@ fn updateType(
},
.enum_type => {
const loaded_enum = ip.loadEnumType(type_index);
- try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
+ try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .enum_type else .empty_enum_type);
try wip_nav.strp(name);
try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
for (0..loaded_enum.names.len) |field_index| {
try wip_nav.enumConstValue(loaded_enum, .{
- .signed = .signed_enum_field,
- .unsigned = .unsigned_enum_field,
+ .sdata = .signed_enum_field,
+ .udata = .unsigned_enum_field,
+ .block = .big_enum_field,
}, field_index);
try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
}
- try uleb128(diw, @intFromEnum(AbbrevCode.null));
+ if (loaded_enum.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
.func_type => |func_type| {
const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_nullary) .nullary_func_type else .func_type)));
+ try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
try wip_nav.strp(name);
try diw.writeByte(@intFromEnum(@as(DW.CC, switch (func_type.cc) {
.Unspecified, .C => .normal,
@@ -2633,15 +2880,15 @@ fn updateType(
try wip_nav.refType(Type.fromInterned(func_type.return_type));
if (!is_nullary) {
for (0..func_type.param_types.len) |param_index| {
- try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param));
+ try wip_nav.abbrevCode(.func_type_param);
try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
}
- if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args));
+ if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
try uleb128(diw, @intFromEnum(AbbrevCode.null));
}
},
.error_set_type => |error_set_type| {
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (error_set_type.names.len > 0) .enum_type else .empty_enum_type)));
+ try wip_nav.abbrevCode(if (error_set_type.names.len > 0) .enum_type else .empty_enum_type);
try wip_nav.strp(name);
try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
@@ -2649,16 +2896,22 @@ fn updateType(
} })));
for (0..error_set_type.names.len) |field_index| {
const field_name = error_set_type.names.get(ip)[field_index];
- try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
+ try wip_nav.abbrevCode(.unsigned_enum_field);
try uleb128(diw, ip.getErrorValueIfExists(field_name).?);
try wip_nav.strp(field_name.toSlice(ip));
}
if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
- .inferred_error_set_type => |func| {
- try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type));
- try wip_nav.strp(name);
- try wip_nav.refType(Type.fromInterned(ip.funcIesResolvedUnordered(func)));
+ .inferred_error_set_type => |func| switch (ip.funcIesResolvedUnordered(func)) {
+ .none => {
+ try wip_nav.abbrevCode(.void_type);
+ try wip_nav.strp(name);
+ },
+ else => |ies| {
+ try wip_nav.abbrevCode(.inferred_error_set_type);
+ try wip_nav.strp(name);
+ try wip_nav.refType(Type.fromInterned(ies));
+ },
},
// values, not types
@@ -2705,7 +2958,9 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
.entry = type_gop.value_ptr.*,
.any_children = false,
.func = .none,
+ .func_sym_index = undefined,
.func_high_reloc = undefined,
+ .inlined_funcs = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@@ -2716,7 +2971,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
const loaded_struct = ip.loadStructType(type_index);
const diw = wip_nav.debug_info.writer(dwarf.gpa);
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) .namespace_file else .file)));
+ try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .namespace_file else .file);
const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
try uleb128(diw, file_gop.index);
try wip_nav.strp(loaded_struct.name.toSlice(ip));
@@ -2725,7 +2980,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
for (0..loaded_struct.field_types.len) |field_index| {
const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
+ try wip_nav.abbrevCode(if (is_comptime) .struct_field_comptime else .struct_field);
if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
defer dwarf.gpa.free(field_name);
@@ -2766,7 +3021,9 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
.entry = type_gop.value_ptr.*,
.any_children = false,
.func = .none,
+ .func_sym_index = undefined,
.func_high_reloc = undefined,
+ .inlined_funcs = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@@ -2782,17 +3039,14 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
const loaded_struct = ip.loadStructType(type_index);
switch (loaded_struct.layout) {
.auto, .@"extern" => {
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
- .namespace_struct_type
- else
- .struct_type)));
+ try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .namespace_struct_type else .struct_type);
try wip_nav.strp(name);
if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
try uleb128(diw, ty.abiSize(pt));
try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
for (0..loaded_struct.field_types.len) |field_index| {
const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
+ try wip_nav.abbrevCode(if (is_comptime) .struct_field_comptime else .struct_field);
if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
defer dwarf.gpa.free(field_name);
@@ -2810,46 +3064,47 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
}
},
.@"packed" => {
- try uleb128(diw, @intFromEnum(AbbrevCode.packed_struct_type));
+ try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
try wip_nav.strp(name);
try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
var field_bit_offset: u16 = 0;
for (0..loaded_struct.field_types.len) |field_index| {
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
+ try wip_nav.abbrevCode(.packed_struct_field);
try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
try wip_nav.refType(field_type);
try uleb128(diw, field_bit_offset);
field_bit_offset += @intCast(field_type.bitSize(pt));
}
- try uleb128(diw, @intFromEnum(AbbrevCode.null));
+ if (loaded_struct.field_types.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
}
},
.enum_type => {
const loaded_enum = ip.loadEnumType(type_index);
- try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
+ try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .enum_type else .empty_enum_type);
try wip_nav.strp(name);
try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
for (0..loaded_enum.names.len) |field_index| {
try wip_nav.enumConstValue(loaded_enum, .{
- .signed = .signed_enum_field,
- .unsigned = .unsigned_enum_field,
+ .sdata = .signed_enum_field,
+ .udata = .unsigned_enum_field,
+ .block = .big_enum_field,
}, field_index);
try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
}
- try uleb128(diw, @intFromEnum(AbbrevCode.null));
+ if (loaded_enum.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
.union_type => {
const loaded_union = ip.loadUnionType(type_index);
- try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
+ try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
try wip_nav.strp(name);
const union_layout = pt.getUnionLayout(loaded_union);
try uleb128(diw, union_layout.abi_size);
try uleb128(diw, union_layout.abi_align.toByteUnits().?);
const loaded_tag = loaded_union.loadTagType(ip);
if (loaded_union.hasTag(ip)) {
- try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
+ try wip_nav.abbrevCode(.tagged_union);
try wip_nav.infoSectionOffset(
.debug_info,
wip_nav.unit,
@@ -2857,18 +3112,19 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
@intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+ try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("tag");
try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
try uleb128(diw, union_layout.tagOffset());
for (0..loaded_union.field_types.len) |field_index| {
try wip_nav.enumConstValue(loaded_tag, .{
- .signed = .signed_tagged_union_field,
- .unsigned = .unsigned_tagged_union_field,
+ .sdata = .signed_tagged_union_field,
+ .udata = .unsigned_tagged_union_field,
+ .block = .big_tagged_union_field,
}, field_index);
{
- try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
+ try wip_nav.abbrevCode(.struct_field);
try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
try wip_nav.refType(field_type);
@@ -2884,17 +3140,17 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
} else for (0..loaded_union.field_types.len) |field_index| {
- try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
+ try wip_nav.abbrevCode(.untagged_union_field);
try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
try wip_nav.refType(field_type);
try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
field_type.abiAlignment(pt).toByteUnits().?);
}
- try uleb128(diw, @intFromEnum(AbbrevCode.null));
+ if (loaded_union.field_types.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
.opaque_type => {
- try uleb128(diw, @intFromEnum(AbbrevCode.namespace_struct_type));
+ try wip_nav.abbrevCode(.namespace_struct_type);
try wip_nav.strp(name);
try diw.writeByte(@intFromBool(true));
},
@@ -2930,6 +3186,23 @@ pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
_ = nav_index;
}
+fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(AbbrevCode).Enum.tag_type {
+ assert(abbrev_code != .null);
+ const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code));
+ if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @intFromEnum(abbrev_code);
+ var debug_abbrev = std.ArrayList(u8).init(dwarf.gpa);
+ defer debug_abbrev.deinit();
+ const daw = debug_abbrev.writer();
+ const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
+ try uleb128(daw, @intFromEnum(abbrev_code));
+ try uleb128(daw, @intFromEnum(abbrev.tag));
+ try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
+ for (abbrev.attrs) |*attr| inline for (attr) |info| try uleb128(daw, @intFromEnum(info));
+ for (0..2) |_| try uleb128(daw, 0);
+ try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev.items);
+ return @intFromEnum(abbrev_code);
+}
+
pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
const ip = &pt.zcu.intern_pool;
if (dwarf.types.get(.anyerror_type)) |entry| {
@@ -2940,7 +3213,9 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
.entry = entry,
.any_children = false,
.func = .none,
+ .func_sym_index = undefined,
.func_high_reloc = undefined,
+ .inlined_funcs = undefined,
.debug_info = .{},
.debug_line = .{},
.debug_loclists = .{},
@@ -2949,14 +3224,14 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
defer wip_nav.deinit();
const diw = wip_nav.debug_info.writer(dwarf.gpa);
const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
- try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (global_error_set_names.len > 0) .enum_type else .empty_enum_type)));
+ try wip_nav.abbrevCode(if (global_error_set_names.len > 0) .enum_type else .empty_enum_type);
try wip_nav.strp("anyerror");
try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = pt.zcu.errorSetBits(),
} })));
for (global_error_set_names, 1..) |name, value| {
- try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
+ try wip_nav.abbrevCode(.unsigned_enum_field);
try uleb128(diw, value);
try wip_nav.strp(name.toSlice(ip));
}
@@ -2980,25 +3255,11 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
var header = std.ArrayList(u8).init(dwarf.gpa);
defer header.deinit();
- if (dwarf.debug_abbrev.section.dirty) {
- for (1.., &AbbrevCode.abbrevs) |code, *abbrev| {
- try uleb128(header.writer(), code);
- try uleb128(header.writer(), @intFromEnum(abbrev.tag));
- try header.append(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
- for (abbrev.attrs) |*attr| {
- try uleb128(header.writer(), @intFromEnum(attr[0]));
- try uleb128(header.writer(), @intFromEnum(attr[1]));
- }
- try header.appendSlice(&.{ 0, 0 });
- }
- try header.append(@intFromEnum(AbbrevCode.null));
- try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, DebugAbbrev.entry, dwarf, header.items);
- dwarf.debug_abbrev.section.dirty = false;
- }
if (dwarf.debug_aranges.section.dirty) {
for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
const unit: Unit.Index = @enumFromInt(unit_index);
- try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 1);
+ unit_ptr.clear();
+ try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 1);
header.clearRetainingCapacity();
try header.ensureTotalCapacity(unit_ptr.header_len);
const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
@@ -3029,8 +3290,9 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
if (dwarf.debug_info.section.dirty) {
for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {
const unit: Unit.Index = @enumFromInt(unit_index);
- try unit_ptr.cross_unit_relocs.ensureUnusedCapacity(dwarf.gpa, 1);
- try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 7);
+ unit_ptr.clear();
+ try unit_ptr.cross_unit_relocs.ensureTotalCapacity(dwarf.gpa, 1);
+ try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 7);
header.clearRetainingCapacity();
try header.ensureTotalCapacity(unit_ptr.header_len);
const unit_len = (if (unit_ptr.next.unwrap()) |next_unit|
@@ -3050,11 +3312,10 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
.source_off = @intCast(header.items.len),
.target_sec = .debug_abbrev,
.target_unit = DebugAbbrev.unit,
- .target_entry = DebugAbbrev.entry.toOptional(),
});
header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
const compile_unit_off: u32 = @intCast(header.items.len);
- uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.compile_unit)) catch unreachable;
+ uleb128(header.fixedWriter(), try dwarf.refAbbrevCode(.compile_unit)) catch unreachable;
header.appendAssumeCapacity(DW.LANG.Zig);
unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
.source_off = @intCast(header.items.len),
@@ -3097,7 +3358,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
});
header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
uleb128(header.fixedWriter(), 0) catch unreachable;
- uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.module)) catch unreachable;
+ uleb128(header.fixedWriter(), try dwarf.refAbbrevCode(.module)) catch unreachable;
unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
.source_off = @intCast(header.items.len),
.target_sec = .debug_str,
@@ -3111,6 +3372,11 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
}
dwarf.debug_info.section.dirty = false;
}
+ if (dwarf.debug_abbrev.section.dirty) {
+ assert(!dwarf.debug_info.section.dirty);
+ try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).writeTrailer(&dwarf.debug_abbrev.section, dwarf);
+ dwarf.debug_abbrev.section.dirty = false;
+ }
if (dwarf.debug_str.section.dirty) {
const contents = dwarf.debug_str.contents.items;
try dwarf.debug_str.section.resize(dwarf, contents.len);
@@ -3118,10 +3384,14 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
dwarf.debug_str.section.dirty = false;
}
if (dwarf.debug_line.section.dirty) {
- for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit|
- try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())));
+ for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| try unit.resizeHeader(
+ &dwarf.debug_line.section,
+ dwarf,
+ DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())),
+ );
for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| {
- try unit.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count()));
+ unit.clear();
+ try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count()));
header.clearRetainingCapacity();
try header.ensureTotalCapacity(unit.header_len);
const unit_len = (if (unit.next.unwrap()) |next_unit|
@@ -3137,14 +3407,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
}
std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
- switch (dwarf.format) {
- inline .@"32", .@"64" => |format| std.mem.writeInt(
- SectionOffset(format),
- header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
- @intCast(unit.header_len - header.items.len),
- dwarf.endian,
- ),
- }
+ dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), unit.header_len - header.items.len);
const StandardOpcode = DeclValEnum(DW.LNS);
header.appendSliceAssumeCapacity(&[_]u8{
dwarf.debug_line.header.minimum_instruction_length,
@@ -3226,6 +3489,9 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off);
dwarf.debug_line_str.section.dirty = false;
}
+ if (dwarf.debug_loclists.section.dirty) {
+ dwarf.debug_loclists.section.dirty = false;
+ }
if (dwarf.debug_rnglists.section.dirty) {
for (dwarf.debug_rnglists.section.units.items) |*unit| {
header.clearRetainingCapacity();
@@ -3244,19 +3510,20 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), 1, dwarf.endian);
- switch (dwarf.format) {
- inline .@"32", .@"64" => |format| std.mem.writeInt(
- SectionOffset(format),
- header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
- @sizeOf(SectionOffset(format)),
- dwarf.endian,
- ),
- }
+ dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), dwarf.sectionOffsetBytes() * 1);
try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items);
try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
}
dwarf.debug_rnglists.section.dirty = false;
}
+ assert(!dwarf.debug_abbrev.section.dirty);
+ assert(!dwarf.debug_aranges.section.dirty);
+ assert(!dwarf.debug_info.section.dirty);
+ assert(!dwarf.debug_line.section.dirty);
+ assert(!dwarf.debug_line_str.section.dirty);
+ assert(!dwarf.debug_loclists.section.dirty);
+ assert(!dwarf.debug_rnglists.section.dirty);
+ assert(!dwarf.debug_str.section.dirty);
}
pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
@@ -3295,7 +3562,7 @@ fn DeclValEnum(comptime T: type) type {
} });
}
-const AbbrevCode = enum(u8) {
+const AbbrevCode = enum {
null,
// padding codes must be one byte uleb128 values to function
pad_1,
@@ -3303,13 +3570,16 @@ const AbbrevCode = enum(u8) {
// decl codes are assumed to all have the same uleb128 length
decl_alias,
decl_enum,
+ decl_empty_enum,
decl_namespace_struct,
decl_struct,
decl_packed_struct,
decl_union,
decl_var,
decl_func,
- decl_func_empty,
+ decl_empty_func,
+ decl_func_generic,
+ decl_empty_func_generic,
// the rest are unrestricted
compile_unit,
module,
@@ -3317,6 +3587,7 @@ const AbbrevCode = enum(u8) {
file,
signed_enum_field,
unsigned_enum_field,
+ big_enum_field,
generated_field,
struct_field,
struct_field_comptime,
@@ -3325,6 +3596,7 @@ const AbbrevCode = enum(u8) {
tagged_union,
signed_tagged_union_field,
unsigned_tagged_union_field,
+ big_tagged_union_field,
tagged_union_default_field,
void_type,
numeric_type,
@@ -3343,11 +3615,15 @@ const AbbrevCode = enum(u8) {
namespace_struct_type,
struct_type,
packed_struct_type,
+ empty_packed_struct_type,
union_type,
+ empty_union_type,
+ empty_inlined_func,
+ inlined_func,
local_arg,
local_var,
- const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_empty));
+ const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_empty_func_generic));
const Attr = struct {
DeclValEnum(DW.AT),
@@ -3387,6 +3663,12 @@ const AbbrevCode = enum(u8) {
.{ .type, .ref_addr },
},
},
+ .decl_empty_enum = .{
+ .tag = .enumeration_type,
+ .attrs = decl_abbrev_common_attrs ++ .{
+ .{ .type, .ref_addr },
+ },
+ },
.decl_namespace_struct = .{
.tag = .structure_type,
.attrs = decl_abbrev_common_attrs ++ .{
@@ -3439,7 +3721,7 @@ const AbbrevCode = enum(u8) {
.{ .noreturn, .flag },
},
},
- .decl_func_empty = .{
+ .decl_empty_func = .{
.tag = .subprogram,
.attrs = decl_abbrev_common_attrs ++ .{
.{ .linkage_name, .strp },
@@ -3451,6 +3733,19 @@ const AbbrevCode = enum(u8) {
.{ .noreturn, .flag },
},
},
+ .decl_func_generic = .{
+ .tag = .subprogram,
+ .children = true,
+ .attrs = decl_abbrev_common_attrs ++ .{
+ .{ .type, .ref_addr },
+ },
+ },
+ .decl_empty_func_generic = .{
+ .tag = .subprogram,
+ .attrs = decl_abbrev_common_attrs ++ .{
+ .{ .type, .ref_addr },
+ },
+ },
.compile_unit = .{
.tag = .compile_unit,
.children = true,
@@ -3504,6 +3799,13 @@ const AbbrevCode = enum(u8) {
.{ .name, .strp },
},
},
+ .big_enum_field = .{
+ .tag = .enumerator,
+ .attrs = &.{
+ .{ .const_value, .block },
+ .{ .name, .strp },
+ },
+ },
.generated_field = .{
.tag = .member,
.attrs = &.{
@@ -3567,6 +3869,13 @@ const AbbrevCode = enum(u8) {
.{ .discr_value, .udata },
},
},
+ .big_tagged_union_field = .{
+ .tag = .variant,
+ .children = true,
+ .attrs = &.{
+ .{ .discr_value, .block },
+ },
+ },
.tagged_union_default_field = .{
.tag = .variant,
.children = true,
@@ -3697,6 +4006,13 @@ const AbbrevCode = enum(u8) {
.{ .type, .ref_addr },
},
},
+ .empty_packed_struct_type = .{
+ .tag = .structure_type,
+ .attrs = &.{
+ .{ .name, .strp },
+ .{ .type, .ref_addr },
+ },
+ },
.union_type = .{
.tag = .union_type,
.children = true,
@@ -3706,6 +4022,35 @@ const AbbrevCode = enum(u8) {
.{ .alignment, .udata },
},
},
+ .empty_union_type = .{
+ .tag = .union_type,
+ .attrs = &.{
+ .{ .name, .strp },
+ .{ .byte_size, .udata },
+ .{ .alignment, .udata },
+ },
+ },
+ .empty_inlined_func = .{
+ .tag = .inlined_subroutine,
+ .attrs = &.{
+ .{ .abstract_origin, .ref_addr },
+ .{ .call_line, .udata },
+ .{ .call_column, .udata },
+ .{ .low_pc, .addr },
+ .{ .high_pc, .addr },
+ },
+ },
+ .inlined_func = .{
+ .tag = .inlined_subroutine,
+ .children = true,
+ .attrs = &.{
+ .{ .abstract_origin, .ref_addr },
+ .{ .call_line, .udata },
+ .{ .call_column, .udata },
+ .{ .low_pc, .addr },
+ .{ .high_pc, .addr },
+ },
+ },
.local_arg = .{
.tag = .formal_parameter,
.attrs = &.{
@@ -3723,7 +4068,7 @@ const AbbrevCode = enum(u8) {
},
},
.null = undefined,
- }).values[1..].*;
+ });
};
fn getFile(dwarf: *Dwarf) ?std.fs.File {
@@ -3732,11 +4077,11 @@ fn getFile(dwarf: *Dwarf) ?std.fs.File {
}
fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
- const entry = try dwarf.debug_aranges.section.addEntry(unit, dwarf);
- assert(try dwarf.debug_info.section.addEntry(unit, dwarf) == entry);
- assert(try dwarf.debug_line.section.addEntry(unit, dwarf) == entry);
- assert(try dwarf.debug_loclists.section.addEntry(unit, dwarf) == entry);
- assert(try dwarf.debug_rnglists.section.addEntry(unit, dwarf) == entry);
+ const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
+ assert(try dwarf.debug_info.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
+ assert(try dwarf.debug_line.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
+ assert(try dwarf.debug_loclists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
+ assert(try dwarf.debug_rnglists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
return entry;
}
@@ -3770,13 +4115,6 @@ fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
};
}
-fn SectionOffset(comptime format: DW.Format) type {
- return switch (format) {
- .@"32" => u32,
- .@"64" => u64,
- };
-}
-
fn uleb128Bytes(value: anytype) u32 {
var cw = std.io.countingWriter(std.io.null_writer);
try uleb128(cw.writer(), value);
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 5a35e67b02..333e490d17 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -204,7 +204,7 @@ pub const SortSection = enum { name, alignment };
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*Elf {
const target = comp.root_mod.resolved_target.result;
@@ -321,7 +321,7 @@ pub fn createEmpty(
// If using LLD to link, this code should produce an object file so that it
// can be passed to LLD.
const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
- self.base.file = try emit.directory.handle.createFile(sub_path, .{
+ self.base.file = try emit.root_dir.handle.createFile(sub_path, .{
.truncate = true,
.read = true,
.mode = link.File.determineMode(use_lld, output_mode, link_mode),
@@ -401,7 +401,7 @@ pub fn createEmpty(
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*Elf {
// TODO: restore saved linker state, don't truncate the file, and
@@ -585,7 +585,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
const ptr_size = self.ptrWidthBytes();
const target = self.base.comp.root_mod.resolved_target.result;
const ptr_bit_width = target.ptrBitWidth();
- const zig_object = self.zigObjectPtr().?;
+ const zo = self.zigObjectPtr().?;
const fillSection = struct {
fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) !void {
@@ -766,7 +766,27 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
}
- if (zig_object.dwarf) |*dwarf| {
+ if (zo.dwarf) |*dwarf| {
+ const addSectionSymbol = struct {
+ fn addSectionSymbol(
+ zig_object: *ZigObject,
+ alloc: Allocator,
+ name: [:0]const u8,
+ alignment: Atom.Alignment,
+ shndx: u32,
+ ) !Symbol.Index {
+ const name_off = try zig_object.addString(alloc, name);
+ const index = try zig_object.newSymbolWithAtom(alloc, name_off);
+ const sym = zig_object.symbol(index);
+ const esym = &zig_object.symtab.items(.elf_sym)[sym.esym_index];
+ esym.st_info |= elf.STT_SECTION;
+ const atom_ptr = zig_object.atom(sym.ref.index).?;
+ atom_ptr.alignment = alignment;
+ atom_ptr.output_section_index = shndx;
+ return index;
+ }
+ }.addSectionSymbol;
+
if (self.debug_str_section_index == null) {
self.debug_str_section_index = try self.addSection(.{
.name = try self.insertShString(".debug_str"),
@@ -775,7 +795,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
.type = elf.SHT_PROGBITS,
.addralign = 1,
});
- zig_object.debug_str_section_dirty = true;
+ zo.debug_str_section_dirty = true;
+ zo.debug_str_index = try addSectionSymbol(zo, gpa, ".debug_str", .@"1", self.debug_str_section_index.?);
try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{});
}
@@ -785,7 +806,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
.type = elf.SHT_PROGBITS,
.addralign = 1,
});
- zig_object.debug_info_section_dirty = true;
+ zo.debug_info_section_dirty = true;
+ zo.debug_info_index = try addSectionSymbol(zo, gpa, ".debug_info", .@"1", self.debug_info_section_index.?);
try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{});
}
@@ -795,7 +817,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
.type = elf.SHT_PROGBITS,
.addralign = 1,
});
- zig_object.debug_abbrev_section_dirty = true;
+ zo.debug_abbrev_section_dirty = true;
+ zo.debug_abbrev_index = try addSectionSymbol(zo, gpa, ".debug_abbrev", .@"1", self.debug_abbrev_section_index.?);
try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{});
}
@@ -805,7 +828,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
.type = elf.SHT_PROGBITS,
.addralign = 16,
});
- zig_object.debug_aranges_section_dirty = true;
+ zo.debug_aranges_section_dirty = true;
+ zo.debug_aranges_index = try addSectionSymbol(zo, gpa, ".debug_aranges", .@"16", self.debug_aranges_section_index.?);
try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{});
}
@@ -815,7 +839,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
.type = elf.SHT_PROGBITS,
.addralign = 1,
});
- zig_object.debug_line_section_dirty = true;
+ zo.debug_line_section_dirty = true;
+ zo.debug_line_index = try addSectionSymbol(zo, gpa, ".debug_line", .@"1", self.debug_line_section_index.?);
try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});
}
@@ -827,7 +852,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
.type = elf.SHT_PROGBITS,
.addralign = 1,
});
- zig_object.debug_line_str_section_dirty = true;
+ zo.debug_line_str_section_dirty = true;
+ zo.debug_line_str_index = try addSectionSymbol(zo, gpa, ".debug_line_str", .@"1", self.debug_line_str_section_index.?);
try self.output_sections.putNoClobber(gpa, self.debug_line_str_section_index.?, .{});
}
@@ -837,7 +863,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
.type = elf.SHT_PROGBITS,
.addralign = 1,
});
- zig_object.debug_loclists_section_dirty = true;
+ zo.debug_loclists_section_dirty = true;
+ zo.debug_loclists_index = try addSectionSymbol(zo, gpa, ".debug_loclists", .@"1", self.debug_loclists_section_index.?);
try self.output_sections.putNoClobber(gpa, self.debug_loclists_section_index.?, .{});
}
@@ -847,7 +874,8 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
.type = elf.SHT_PROGBITS,
.addralign = 1,
});
- zig_object.debug_rnglists_section_dirty = true;
+ zo.debug_rnglists_section_dirty = true;
+ zo.debug_rnglists_index = try addSectionSymbol(zo, gpa, ".debug_rnglists", .@"1", self.debug_rnglists_section_index.?);
try self.output_sections.putNoClobber(gpa, self.debug_rnglists_section_index.?, .{});
}
@@ -999,7 +1027,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
const target = comp.root_mod.resolved_target.result;
const link_mode = comp.config.link_mode;
- const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
+ const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| {
@@ -1254,7 +1282,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
try self.addCommentString();
try self.finalizeMergeSections();
try self.initOutputSections();
- try self.initMergeSections();
if (self.linkerDefinedPtr()) |obj| {
try obj.initStartStopSymbols(self);
}
@@ -1317,8 +1344,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
try self.base.file.?.pwriteAll(code, file_offset);
}
- if (zo.dwarf) |*dwarf| try dwarf.resolveRelocs();
-
if (has_reloc_errors) return error.FlushFailure;
}
@@ -1356,7 +1381,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
const target = self.base.comp.root_mod.resolved_target.result;
const link_mode = self.base.comp.config.link_mode;
- const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
+ const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| {
@@ -2054,7 +2079,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
const comp = self.base.comp;
const gpa = comp.gpa;
- const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
+ const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
// If there is no Zig code to compile, then we should skip flushing the output file because it
@@ -2652,15 +2677,6 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
}
}
-fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
- const target = self.base.comp.root_mod.resolved_target.result;
- const target_endian = target.cpu.arch.endian();
- switch (self.ptr_width) {
- .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(addr)), target_endian),
- .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian),
- }
-}
-
pub fn writeShdrTable(self: *Elf) !void {
const gpa = self.base.comp.gpa;
const target = self.base.comp.root_mod.resolved_target.result;
@@ -3032,16 +3048,16 @@ pub fn finalizeMergeSections(self: *Elf) !void {
pub fn updateMergeSectionSizes(self: *Elf) !void {
for (self.merge_sections.items) |*msec| {
+ msec.updateSize();
+ }
+ for (self.merge_sections.items) |*msec| {
const shdr = &self.shdrs.items[msec.output_section_index];
- for (msec.finalized_subsections.items) |msub_index| {
- const msub = msec.mergeSubsection(msub_index);
- assert(msub.alive);
- const offset = msub.alignment.forward(shdr.sh_size);
- const padding = offset - shdr.sh_size;
- msub.value = @intCast(offset);
- shdr.sh_size += padding + msub.size;
- shdr.sh_addralign = @max(shdr.sh_addralign, msub.alignment.toByteUnits() orelse 1);
- }
+ const offset = msec.alignment.forward(shdr.sh_size);
+ const padding = offset - shdr.sh_size;
+ msec.value = @intCast(offset);
+ shdr.sh_size += padding + msec.size;
+ shdr.sh_addralign = @max(shdr.sh_addralign, msec.alignment.toByteUnits() orelse 1);
+ shdr.sh_entsize = if (shdr.sh_entsize == 0) msec.entsize else @min(shdr.sh_entsize, msec.entsize);
}
}
@@ -3052,7 +3068,8 @@ pub fn writeMergeSections(self: *Elf) !void {
for (self.merge_sections.items) |*msec| {
const shdr = self.shdrs.items[msec.output_section_index];
- const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
+ const fileoff = math.cast(usize, msec.value + shdr.sh_offset) orelse return error.Overflow;
+ const size = math.cast(usize, msec.size) orelse return error.Overflow;
try buffer.ensureTotalCapacity(size);
buffer.appendNTimesAssumeCapacity(0, size);
@@ -3064,7 +3081,7 @@ pub fn writeMergeSections(self: *Elf) !void {
@memcpy(buffer.items[off..][0..string.len], string);
}
- try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
+ try self.base.file.?.pwriteAll(buffer.items, fileoff);
buffer.clearRetainingCapacity();
}
}
@@ -3073,26 +3090,9 @@ fn initOutputSections(self: *Elf) !void {
for (self.objects.items) |index| {
try self.file(index).?.object.initOutputSections(self);
}
-}
-
-pub fn initMergeSections(self: *Elf) !void {
for (self.merge_sections.items) |*msec| {
if (msec.finalized_subsections.items.len == 0) continue;
- const name = msec.name(self);
- const shndx = self.sectionByName(name) orelse try self.addSection(.{
- .name = msec.name_offset,
- .type = msec.type,
- .flags = msec.flags,
- });
- msec.output_section_index = shndx;
-
- var entsize = msec.mergeSubsection(msec.finalized_subsections.items[0]).entsize;
- for (msec.finalized_subsections.items) |msub_index| {
- const msub = msec.mergeSubsection(msub_index);
- entsize = @min(entsize, msub.entsize);
- }
- const shdr = &self.shdrs.items[shndx];
- shdr.sh_entsize = entsize;
+ try msec.initOutputSection(self);
}
}
@@ -4184,26 +4184,21 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
shdr.sh_offset,
new_offset,
});
- const zig_object = self.zigObjectPtr().?;
- const existing_size = blk: {
- if (shndx == self.debug_info_section_index.?)
- break :blk zig_object.debug_info_section_zig_size;
- if (shndx == self.debug_abbrev_section_index.?)
- break :blk zig_object.debug_abbrev_section_zig_size;
- if (shndx == self.debug_str_section_index.?)
- break :blk zig_object.debug_str_section_zig_size;
- if (shndx == self.debug_aranges_section_index.?)
- break :blk zig_object.debug_aranges_section_zig_size;
- if (shndx == self.debug_line_section_index.?)
- break :blk zig_object.debug_line_section_zig_size;
- if (shndx == self.debug_line_str_section_index.?)
- break :blk zig_object.debug_line_str_section_zig_size;
- if (shndx == self.debug_loclists_section_index.?)
- break :blk zig_object.debug_loclists_section_zig_size;
- if (shndx == self.debug_rnglists_section_index.?)
- break :blk zig_object.debug_rnglists_section_zig_size;
- unreachable;
- };
+ const zo = self.zigObjectPtr().?;
+ const existing_size = for ([_]Symbol.Index{
+ zo.debug_info_index.?,
+ zo.debug_abbrev_index.?,
+ zo.debug_aranges_index.?,
+ zo.debug_str_index.?,
+ zo.debug_line_index.?,
+ zo.debug_line_str_index.?,
+ zo.debug_loclists_index.?,
+ zo.debug_rnglists_index.?,
+ }) |sym_index| {
+ const sym = zo.symbol(sym_index);
+ const atom_ptr = sym.atom(self).?;
+ if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
+ } else 0;
const amt = try self.base.file.?.copyRangeAll(
shdr.sh_offset,
self.base.file.?,
@@ -4299,24 +4294,21 @@ fn writeAtoms(self: *Elf) !void {
// TODO really, really handle debug section separately
const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
- const zig_object = self.zigObjectPtr().?;
- if (shndx == self.debug_info_section_index.?)
- break :blk zig_object.debug_info_section_zig_size;
- if (shndx == self.debug_abbrev_section_index.?)
- break :blk zig_object.debug_abbrev_section_zig_size;
- if (shndx == self.debug_str_section_index.?)
- break :blk zig_object.debug_str_section_zig_size;
- if (shndx == self.debug_aranges_section_index.?)
- break :blk zig_object.debug_aranges_section_zig_size;
- if (shndx == self.debug_line_section_index.?)
- break :blk zig_object.debug_line_section_zig_size;
- if (shndx == self.debug_line_str_section_index.?)
- break :blk zig_object.debug_line_str_section_zig_size;
- if (shndx == self.debug_loclists_section_index.?)
- break :blk zig_object.debug_loclists_section_zig_size;
- if (shndx == self.debug_rnglists_section_index.?)
- break :blk zig_object.debug_rnglists_section_zig_size;
- unreachable;
+ const zo = self.zigObjectPtr().?;
+ break :blk for ([_]Symbol.Index{
+ zo.debug_info_index.?,
+ zo.debug_abbrev_index.?,
+ zo.debug_aranges_index.?,
+ zo.debug_str_index.?,
+ zo.debug_line_index.?,
+ zo.debug_line_str_index.?,
+ zo.debug_loclists_index.?,
+ zo.debug_rnglists_index.?,
+ }) |sym_index| {
+ const sym = zo.symbol(sym_index);
+ const atom_ptr = sym.atom(self).?;
+ if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
+ } else 0;
} else 0;
const sh_offset = shdr.sh_offset + base_offset;
const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
@@ -4410,7 +4402,6 @@ pub fn updateSymtabSize(self: *Elf) !void {
if (self.eh_frame_section_index) |_| {
nlocals += 1;
}
- nlocals += @intCast(self.merge_sections.items.len);
if (self.requiresThunks()) for (self.thunks.items) |*th| {
th.output_symtab_ctx.ilocal = nlocals + 1;
@@ -4734,30 +4725,12 @@ fn writeSectionSymbols(self: *Elf) void {
};
ilocal += 1;
}
-
- for (self.merge_sections.items) |msec| {
- const shdr = self.shdrs.items[msec.output_section_index];
- const out_sym = &self.symtab.items[ilocal];
- out_sym.* = .{
- .st_name = 0,
- .st_value = shdr.sh_addr,
- .st_info = elf.STT_SECTION,
- .st_shndx = @intCast(msec.output_section_index),
- .st_size = 0,
- .st_other = 0,
- };
- ilocal += 1;
- }
}
pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {
if (self.eh_frame_section_index) |index| {
if (index == shndx) return @intCast(self.output_sections.keys().len + 1);
}
- const base: usize = if (self.eh_frame_section_index == null) 0 else 1;
- for (self.merge_sections.items, 0..) |msec, index| {
- if (msec.output_section_index == shndx) return @intCast(self.output_sections.keys().len + 1 + index + base);
- }
return @intCast(self.output_sections.getIndex(shndx).? + 1);
}
@@ -5520,10 +5493,11 @@ fn formatShdr(
_ = options;
_ = unused_fmt_string;
const shdr = ctx.shdr;
- try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : flags({})", .{
+ try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({})", .{
ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
shdr.sh_addr, shdr.sh_addralign,
- shdr.sh_size, fmtShdrFlags(shdr.sh_flags),
+ shdr.sh_size, shdr.sh_entsize,
+ fmtShdrFlags(shdr.sh_flags),
});
}
@@ -6016,6 +5990,7 @@ const Allocator = std.mem.Allocator;
const Archive = @import("Elf/Archive.zig");
pub const Atom = @import("Elf/Atom.zig");
const Cache = std.Build.Cache;
+const Path = Cache.Path;
const Compilation = @import("../Compilation.zig");
const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
const CopyRelSection = synthetic_sections.CopyRelSection;
diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig
index a9050dcd00..3eb447ab75 100644
--- a/src/link/Elf/Atom.zig
+++ b/src/link/Elf/Atom.zig
@@ -302,7 +302,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
}
// TODO create relocs free list
- self.freeRelocs(elf_file);
+ self.freeRelocs(zo);
// TODO figure out how to free input section mappind in ZigModule
// const zig_object = elf_file.zigObjectPtr().?
// assert(zig_object.atoms.swapRemove(self.atom_index));
@@ -377,21 +377,19 @@ pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
}
}
-pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {
- const comp = elf_file.base.comp;
- const gpa = comp.gpa;
- const file_ptr = self.file(elf_file).?;
- assert(file_ptr == .zig_object);
- const zig_object = file_ptr.zig_object;
- const rels = &zig_object.relocs.items[self.relocs_section_index];
- try rels.append(gpa, reloc);
+pub fn addReloc(self: Atom, alloc: Allocator, reloc: elf.Elf64_Rela, zo: *ZigObject) !void {
+ const rels = &zo.relocs.items[self.relocs_section_index];
+ try rels.ensureUnusedCapacity(alloc, 1);
+ self.addRelocAssumeCapacity(reloc, zo);
}
-pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
- const file_ptr = self.file(elf_file).?;
- assert(file_ptr == .zig_object);
- const zig_object = file_ptr.zig_object;
- zig_object.relocs.items[self.relocs_section_index].clearRetainingCapacity();
+pub fn addRelocAssumeCapacity(self: Atom, reloc: elf.Elf64_Rela, zo: *ZigObject) void {
+ const rels = &zo.relocs.items[self.relocs_section_index];
+ rels.appendAssumeCapacity(reloc);
+}
+
+pub fn freeRelocs(self: Atom, zo: *ZigObject) void {
+ zo.relocs.items[self.relocs_section_index].clearRetainingCapacity();
}
pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {
diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig
index d592f6e9d3..ef6ec27b41 100644
--- a/src/link/Elf/ZigObject.zig
+++ b/src/link/Elf/ZigObject.zig
@@ -50,16 +50,14 @@ debug_line_str_section_dirty: bool = false,
debug_loclists_section_dirty: bool = false,
debug_rnglists_section_dirty: bool = false,
-/// Size contribution of Zig's metadata to each debug section.
-/// Used to track start of metadata from input object files.
-debug_info_section_zig_size: u64 = 0,
-debug_abbrev_section_zig_size: u64 = 0,
-debug_str_section_zig_size: u64 = 0,
-debug_aranges_section_zig_size: u64 = 0,
-debug_line_section_zig_size: u64 = 0,
-debug_line_str_section_zig_size: u64 = 0,
-debug_loclists_section_zig_size: u64 = 0,
-debug_rnglists_section_zig_size: u64 = 0,
+debug_info_index: ?Symbol.Index = null,
+debug_abbrev_index: ?Symbol.Index = null,
+debug_aranges_index: ?Symbol.Index = null,
+debug_str_index: ?Symbol.Index = null,
+debug_line_index: ?Symbol.Index = null,
+debug_line_str_index: ?Symbol.Index = null,
+debug_loclists_index: ?Symbol.Index = null,
+debug_rnglists_index: ?Symbol.Index = null,
pub const global_symbol_bit: u32 = 0x80000000;
pub const symbol_mask: u32 = 0x7fffffff;
@@ -172,12 +170,209 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
try dwarf.flushModule(pt);
+ const gpa = elf_file.base.comp.gpa;
+ const cpu_arch = elf_file.getTarget().cpu.arch;
+
+ // TODO invert this logic so that we manage the output section with the atom, not the
+ // other way around
+ for ([_]u32{
+ self.debug_info_index.?,
+ self.debug_abbrev_index.?,
+ self.debug_str_index.?,
+ self.debug_aranges_index.?,
+ self.debug_line_index.?,
+ self.debug_line_str_index.?,
+ self.debug_loclists_index.?,
+ self.debug_rnglists_index.?,
+ }, [_]*Dwarf.Section{
+ &dwarf.debug_info.section,
+ &dwarf.debug_abbrev.section,
+ &dwarf.debug_str.section,
+ &dwarf.debug_aranges.section,
+ &dwarf.debug_line.section,
+ &dwarf.debug_line_str.section,
+ &dwarf.debug_loclists.section,
+ &dwarf.debug_rnglists.section,
+ }) |sym_index, sect| {
+ const sym = self.symbol(sym_index);
+ const atom_ptr = self.atom(sym.ref.index).?;
+ if (!atom_ptr.alive) continue;
+ const shndx = sym.outputShndx(elf_file).?;
+ const shdr = elf_file.shdrs.items[shndx];
+ const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
+ esym.st_size = shdr.sh_size;
+ atom_ptr.size = shdr.sh_size;
+ atom_ptr.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
+
+ log.debug("parsing relocs in {s}", .{sym.name(elf_file)});
+
+ const relocs = &self.relocs.items[atom_ptr.relocsShndx().?];
+ for (sect.units.items) |*unit| {
+ try relocs.ensureUnusedCapacity(gpa, unit.cross_unit_relocs.items.len +
+ unit.cross_section_relocs.items.len);
+ for (unit.cross_unit_relocs.items) |reloc| {
+ const target_unit = sect.getUnit(reloc.target_unit);
+ const r_offset = unit.off + reloc.source_off;
+ const r_addend: i64 = @intCast(target_unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
+ target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
+ else
+ 0));
+ const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
+ log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
+ self.symbol(sym_index).name(elf_file),
+ r_offset,
+ r_addend,
+ relocation.fmtRelocType(r_type, cpu_arch),
+ });
+ atom_ptr.addRelocAssumeCapacity(.{
+ .r_offset = r_offset,
+ .r_addend = r_addend,
+ .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+ }, self);
+ }
+ for (unit.cross_section_relocs.items) |reloc| {
+ const target_sym_index = switch (reloc.target_sec) {
+ .debug_abbrev => self.debug_abbrev_index.?,
+ .debug_info => self.debug_info_index.?,
+ .debug_line => self.debug_line_index.?,
+ .debug_line_str => self.debug_line_str_index.?,
+ .debug_loclists => self.debug_loclists_index.?,
+ .debug_rnglists => self.debug_rnglists_index.?,
+ .debug_str => self.debug_str_index.?,
+ };
+ const target_sec = switch (reloc.target_sec) {
+ inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
+ };
+ const target_unit = target_sec.getUnit(reloc.target_unit);
+ const r_offset = unit.off + reloc.source_off;
+ const r_addend: i64 = @intCast(target_unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
+ target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
+ else
+ 0));
+ const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
+ log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
+ self.symbol(target_sym_index).name(elf_file),
+ r_offset,
+ r_addend,
+ relocation.fmtRelocType(r_type, cpu_arch),
+ });
+ atom_ptr.addRelocAssumeCapacity(.{
+ .r_offset = r_offset,
+ .r_addend = r_addend,
+ .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | r_type,
+ }, self);
+ }
+
+ for (unit.entries.items) |*entry| {
+ const entry_off = unit.off + unit.header_len + entry.off;
+
+ try relocs.ensureUnusedCapacity(gpa, entry.cross_entry_relocs.items.len +
+ entry.cross_unit_relocs.items.len + entry.cross_section_relocs.items.len +
+ entry.external_relocs.items.len);
+ for (entry.cross_entry_relocs.items) |reloc| {
+ const r_offset = entry_off + reloc.source_off;
+ const r_addend: i64 = @intCast(unit.off + reloc.target_off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sect, dwarf).off);
+ const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
+ log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
+ self.symbol(sym_index).name(elf_file),
+ r_offset,
+ r_addend,
+ relocation.fmtRelocType(r_type, cpu_arch),
+ });
+ atom_ptr.addRelocAssumeCapacity(.{
+ .r_offset = r_offset,
+ .r_addend = r_addend,
+ .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+ }, self);
+ }
+ for (entry.cross_unit_relocs.items) |reloc| {
+ const target_unit = sect.getUnit(reloc.target_unit);
+ const r_offset = entry_off + reloc.source_off;
+ const r_addend: i64 = @intCast(target_unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
+ target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
+ else
+ 0));
+ const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
+ log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
+ self.symbol(sym_index).name(elf_file),
+ r_offset,
+ r_addend,
+ relocation.fmtRelocType(r_type, cpu_arch),
+ });
+ atom_ptr.addRelocAssumeCapacity(.{
+ .r_offset = r_offset,
+ .r_addend = r_addend,
+ .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
+ }, self);
+ }
+ for (entry.cross_section_relocs.items) |reloc| {
+ const target_sym_index = switch (reloc.target_sec) {
+ .debug_abbrev => self.debug_abbrev_index.?,
+ .debug_info => self.debug_info_index.?,
+ .debug_line => self.debug_line_index.?,
+ .debug_line_str => self.debug_line_str_index.?,
+ .debug_loclists => self.debug_loclists_index.?,
+ .debug_rnglists => self.debug_rnglists_index.?,
+ .debug_str => self.debug_str_index.?,
+ };
+ const target_sec = switch (reloc.target_sec) {
+ inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
+ };
+ const target_unit = target_sec.getUnit(reloc.target_unit);
+ const r_offset = entry_off + reloc.source_off;
+ const r_addend: i64 = @intCast(target_unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
+ target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
+ else
+ 0));
+ const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
+ log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
+ self.symbol(target_sym_index).name(elf_file),
+ r_offset,
+ r_addend,
+ relocation.fmtRelocType(r_type, cpu_arch),
+ });
+ atom_ptr.addRelocAssumeCapacity(.{
+ .r_offset = r_offset,
+ .r_addend = r_addend,
+ .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | r_type,
+ }, self);
+ }
+ for (entry.external_relocs.items) |reloc| {
+ const target_sym = self.symbol(reloc.target_sym);
+ const r_offset = entry_off + reloc.source_off;
+ const r_addend: i64 = @intCast(reloc.target_off);
+ const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch);
+ log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
+ target_sym.name(elf_file),
+ r_offset,
+ r_addend,
+ relocation.fmtRelocType(r_type, cpu_arch),
+ });
+ atom_ptr.addRelocAssumeCapacity(.{
+ .r_offset = r_offset,
+ .r_addend = r_addend,
+ .r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | r_type,
+ }, self);
+ }
+ }
+ }
+
+ if (elf_file.base.isRelocatable() and relocs.items.len > 0) {
+ const gop = try elf_file.output_rela_sections.getOrPut(gpa, shndx);
+ if (!gop.found_existing) {
+ const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{elf_file.getShString(shdr.sh_name)});
+ defer gpa.free(rela_sect_name);
+ const rela_sh_name = try elf_file.insertShString(rela_sect_name);
+ const rela_shndx = try elf_file.addRelaShdr(rela_sh_name, shndx);
+ gop.value_ptr.* = .{ .shndx = rela_shndx };
+ }
+ }
+ }
+
self.debug_abbrev_section_dirty = false;
self.debug_aranges_section_dirty = false;
self.debug_rnglists_section_dirty = false;
self.debug_str_section_dirty = false;
-
- self.saveDebugSectionsSizes(elf_file);
}
// The point of flushModule() is to commit changes, so in theory, nothing should
@@ -190,33 +385,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
assert(!self.debug_str_section_dirty);
}
-fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
- if (elf_file.debug_info_section_index) |shndx| {
- self.debug_info_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
- }
- if (elf_file.debug_abbrev_section_index) |shndx| {
- self.debug_abbrev_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
- }
- if (elf_file.debug_str_section_index) |shndx| {
- self.debug_str_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
- }
- if (elf_file.debug_aranges_section_index) |shndx| {
- self.debug_aranges_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
- }
- if (elf_file.debug_line_section_index) |shndx| {
- self.debug_line_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
- }
- if (elf_file.debug_line_str_section_index) |shndx| {
- self.debug_line_str_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
- }
- if (elf_file.debug_loclists_section_index) |shndx| {
- self.debug_loclists_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
- }
- if (elf_file.debug_rnglists_section_index) |shndx| {
- self.debug_rnglists_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
- }
-}
-
fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index {
try self.symtab.ensureUnusedCapacity(allocator, 1);
try self.symbols.ensureUnusedCapacity(allocator, 1);
@@ -278,7 +446,7 @@ fn newAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Atom.Index {
return index;
}
-fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
+pub fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
const atom_index = try self.newAtom(allocator, name_off);
const sym_index = try self.newLocalSymbol(allocator, name_off);
const sym = self.symbol(sym_index);
@@ -642,11 +810,11 @@ pub fn getNavVAddr(
const vaddr = this_sym.address(.{}, elf_file);
const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
- try parent_atom.addReloc(elf_file, .{
+ try parent_atom.addReloc(elf_file.base.comp.gpa, .{
.r_offset = reloc_info.offset,
.r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type,
.r_addend = reloc_info.addend,
- });
+ }, self);
return @intCast(vaddr);
}
@@ -661,11 +829,11 @@ pub fn getUavVAddr(
const vaddr = sym.address(.{}, elf_file);
const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
- try parent_atom.addReloc(elf_file, .{
+ try parent_atom.addReloc(elf_file.base.comp.gpa, .{
.r_offset = reloc_info.offset,
.r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
.r_addend = reloc_info.addend,
- });
+ }, self);
return @intCast(vaddr);
}
@@ -1012,7 +1180,7 @@ pub fn updateFunc(
log.debug("updateFunc {}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav });
const sym_index = try self.getOrCreateMetadataForNav(elf_file, func.owner_nav);
- self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
+ self.symbol(sym_index).atom(elf_file).?.freeRelocs(self);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
@@ -1122,9 +1290,9 @@ pub fn updateNav(
log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index });
- const nav_val = zcu.navValue(nav_index);
- const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
- .variable => |variable| Value.fromInterned(variable.init),
+ const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
+ .func => .none,
+ .variable => |variable| variable.init,
.@"extern" => |@"extern"| {
if (ip.isFunctionType(@"extern".ty)) return;
const sym_index = try self.getGlobalSymbol(
@@ -1135,12 +1303,12 @@ pub fn updateNav(
self.symbol(sym_index).flags.is_extern_ptr = true;
return;
},
- else => nav_val,
+ else => nav.status.resolved.val,
};
- if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
+ if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) {
const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index);
- self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
+ self.symbol(sym_index).atom(elf_file).?.freeRelocs(self);
var code_buffer = std.ArrayList(u8).init(zcu.gpa);
defer code_buffer.deinit();
@@ -1153,7 +1321,7 @@ pub fn updateNav(
&elf_file.base,
pt,
zcu.navSrcLoc(nav_index),
- nav_init,
+ Value.fromInterned(nav_init),
&code_buffer,
if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
.{ .parent_atom_index = sym_index },
@@ -1529,7 +1697,7 @@ pub fn asFile(self: *ZigObject) File {
return .{ .zig_object = self };
}
-fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
+pub fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
return self.strtab.insert(allocator, string);
}
diff --git a/src/link/Elf/merge_section.zig b/src/link/Elf/merge_section.zig
index baec316c3d..7ffb17e963 100644
--- a/src/link/Elf/merge_section.zig
+++ b/src/link/Elf/merge_section.zig
@@ -1,4 +1,8 @@
pub const MergeSection = struct {
+ value: u64 = 0,
+ size: u64 = 0,
+ alignment: Atom.Alignment = .@"1",
+ entsize: u32 = 0,
name_offset: u32 = 0,
type: u32 = 0,
flags: u64 = 0,
@@ -26,7 +30,7 @@ pub const MergeSection = struct {
pub fn address(msec: MergeSection, elf_file: *Elf) i64 {
const shdr = elf_file.shdrs.items[msec.output_section_index];
- return @intCast(shdr.sh_addr);
+ return @intCast(shdr.sh_addr + msec.value);
}
const InsertResult = struct {
@@ -90,6 +94,29 @@ pub const MergeSection = struct {
std.mem.sort(MergeSubsection.Index, msec.finalized_subsections.items, msec, sortFn);
}
+ pub fn updateSize(msec: *MergeSection) void {
+ for (msec.finalized_subsections.items) |msub_index| {
+ const msub = msec.mergeSubsection(msub_index);
+ assert(msub.alive);
+ const offset = msub.alignment.forward(msec.size);
+ const padding = offset - msec.size;
+ msub.value = @intCast(offset);
+ msec.size += padding + msub.size;
+ msec.alignment = msec.alignment.max(msub.alignment);
+ msec.entsize = if (msec.entsize == 0) msub.entsize else @min(msec.entsize, msub.entsize);
+ }
+ }
+
+ pub fn initOutputSection(msec: *MergeSection, elf_file: *Elf) !void {
+ const shndx = elf_file.sectionByName(msec.name(elf_file)) orelse try elf_file.addSection(.{
+ .name = msec.name_offset,
+ .type = msec.type,
+ .flags = msec.flags,
+ });
+ try elf_file.output_sections.put(elf_file.base.comp.gpa, shndx, .{});
+ msec.output_section_index = shndx;
+ }
+
pub fn addMergeSubsection(msec: *MergeSection, allocator: Allocator) !MergeSubsection.Index {
const index: MergeSubsection.Index = @intCast(msec.subsections.items.len);
const msub = try msec.subsections.addOne(allocator);
@@ -163,9 +190,12 @@ pub const MergeSection = struct {
_ = unused_fmt_string;
const msec = ctx.msec;
const elf_file = ctx.elf_file;
- try writer.print("{s} : @{x} : type({x}) : flags({x})\n", .{
+ try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{
msec.name(elf_file),
msec.address(elf_file),
+ msec.size,
+ msec.alignment.toByteUnits() orelse 0,
+ msec.entsize,
msec.type,
msec.flags,
});
diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig
index 213b43a95d..50b9b562d1 100644
--- a/src/link/Elf/relocatable.zig
+++ b/src/link/Elf/relocatable.zig
@@ -42,7 +42,11 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
try elf_file.finalizeMergeSections();
zig_object.claimUnresolvedObject(elf_file);
- try elf_file.initMergeSections();
+ for (elf_file.merge_sections.items) |*msec| {
+ if (msec.finalized_subsections.items.len == 0) continue;
+ try msec.initOutputSection(elf_file);
+ }
+
try elf_file.initSymtab();
try elf_file.initShStrtab();
try elf_file.sortShdrs();
@@ -198,7 +202,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
claimUnresolved(elf_file);
try initSections(elf_file);
- try elf_file.initMergeSections();
try elf_file.sortShdrs();
if (elf_file.zigObjectPtr()) |zig_object| {
try zig_object.addAtomsToRelaSections(elf_file);
@@ -294,6 +297,11 @@ fn initSections(elf_file: *Elf) !void {
try object.initRelaSections(elf_file);
}
+ for (elf_file.merge_sections.items) |*msec| {
+ if (msec.finalized_subsections.items.len == 0) continue;
+ try msec.initOutputSection(elf_file);
+ }
+
const needs_eh_frame = for (elf_file.objects.items) |index| {
if (elf_file.file(index).?.object.cies.items.len > 0) break true;
} else false;
@@ -423,24 +431,21 @@ fn writeAtoms(elf_file: *Elf) !void {
// TODO really, really handle debug section separately
const base_offset = if (elf_file.isDebugSection(@intCast(shndx))) blk: {
- const zig_object = elf_file.zigObjectPtr().?;
- if (shndx == elf_file.debug_info_section_index.?)
- break :blk zig_object.debug_info_section_zig_size;
- if (shndx == elf_file.debug_abbrev_section_index.?)
- break :blk zig_object.debug_abbrev_section_zig_size;
- if (shndx == elf_file.debug_str_section_index.?)
- break :blk zig_object.debug_str_section_zig_size;
- if (shndx == elf_file.debug_aranges_section_index.?)
- break :blk zig_object.debug_aranges_section_zig_size;
- if (shndx == elf_file.debug_line_section_index.?)
- break :blk zig_object.debug_line_section_zig_size;
- if (shndx == elf_file.debug_line_str_section_index.?)
- break :blk zig_object.debug_line_str_section_zig_size;
- if (shndx == elf_file.debug_loclists_section_index.?)
- break :blk zig_object.debug_loclists_section_zig_size;
- if (shndx == elf_file.debug_rnglists_section_index.?)
- break :blk zig_object.debug_rnglists_section_zig_size;
- unreachable;
+ const zo = elf_file.zigObjectPtr().?;
+ break :blk for ([_]Symbol.Index{
+ zo.debug_info_index.?,
+ zo.debug_abbrev_index.?,
+ zo.debug_aranges_index.?,
+ zo.debug_str_index.?,
+ zo.debug_line_index.?,
+ zo.debug_line_str_index.?,
+ zo.debug_loclists_index.?,
+ zo.debug_rnglists_index.?,
+ }) |sym_index| {
+ const sym = zo.symbol(sym_index);
+ const atom_ptr = sym.atom(elf_file).?;
+ if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
+ } else 0;
} else 0;
const sh_offset = shdr.sh_offset + base_offset;
const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
@@ -586,3 +591,4 @@ const Compilation = @import("../../Compilation.zig");
const Elf = @import("../Elf.zig");
const File = @import("file.zig").File;
const Object = @import("Object.zig");
+const Symbol = @import("Symbol.zig");
diff --git a/src/link/Elf/relocation.zig b/src/link/Elf/relocation.zig
index e1a317f67d..d6f8dc5d10 100644
--- a/src/link/Elf/relocation.zig
+++ b/src/link/Elf/relocation.zig
@@ -91,6 +91,44 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
};
}
+pub const dwarf = struct {
+ pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 {
+ return switch (cpu_arch) {
+ .x86_64 => @intFromEnum(switch (format) {
+ .@"32" => elf.R_X86_64.@"32",
+ .@"64" => .@"64",
+ }),
+ .riscv64 => @intFromEnum(switch (format) {
+ .@"32" => elf.R_RISCV.@"32",
+ .@"64" => .@"64",
+ }),
+ else => @panic("TODO unhandled cpu arch"),
+ };
+ }
+
+ pub fn externalRelocType(
+ target: Symbol,
+ address_size: Dwarf.AddressSize,
+ cpu_arch: std.Target.Cpu.Arch,
+ ) u32 {
+ return switch (cpu_arch) {
+ .x86_64 => @intFromEnum(switch (address_size) {
+ .@"32" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF32 else .@"32",
+ .@"64" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF64 else .@"64",
+ else => unreachable,
+ }),
+ .riscv64 => @intFromEnum(switch (address_size) {
+ .@"32" => elf.R_RISCV.@"32",
+ .@"64" => elf.R_RISCV.@"64",
+ else => unreachable,
+ }),
+ else => @panic("TODO unhandled cpu arch"),
+ };
+ }
+
+ const DW = std.dwarf;
+};
+
const FormatRelocTypeCtx = struct {
r_type: u32,
cpu_arch: std.Target.Cpu.Arch,
@@ -124,4 +162,6 @@ const assert = std.debug.assert;
const elf = std.elf;
const std = @import("std");
+const Dwarf = @import("../Dwarf.zig");
const Elf = @import("../Elf.zig");
+const Symbol = @import("Symbol.zig");
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index f3a6ffc58d..d99fc2185e 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -156,7 +156,7 @@ pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*MachO {
const target = comp.root_mod.resolved_target.result;
@@ -221,7 +221,7 @@ pub fn createEmpty(
}
errdefer self.base.destroy();
- self.base.file = try emit.directory.handle.createFile(emit.sub_path, .{
+ self.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.truncate = true,
.read = true,
.mode = link.File.determineMode(false, output_mode, link_mode),
@@ -260,7 +260,7 @@ pub fn createEmpty(
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*MachO {
// TODO: restore saved linker state, don't truncate the file, and
@@ -353,7 +353,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
const sub_prog_node = prog_node.start("MachO Flush", 0);
defer sub_prog_node.end();
- const directory = self.base.emit.directory;
+ const directory = self.base.emit.root_dir;
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| {
@@ -586,7 +586,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
if (codesig) |*csig| {
try self.writeCodeSignature(csig); // code signing always comes last
const emit = self.base.emit;
- try invalidateKernelCache(emit.directory.handle, emit.sub_path);
+ try invalidateKernelCache(emit.root_dir.handle, emit.sub_path);
}
}
@@ -597,7 +597,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
- const directory = self.base.emit.directory;
+ const directory = self.base.emit.root_dir;
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| {
@@ -1909,7 +1909,7 @@ fn calcSectionSizes(self: *MachO) !void {
}
}
- // At this point, we can also calculate symtab and data-in-code linkedit section sizes
+ // At this point, we can also calculate most of the symtab and data-in-code linkedit section sizes
if (self.getZigObject()) |zo| {
tp.spawnWg(&wg, File.calcSymtabSize, .{ zo.asFile(), self });
}
@@ -2463,6 +2463,9 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {
if (self.getInternalObject()) |obj| {
tp.spawnWg(&wg, File.writeSymtab, .{ obj.asFile(), self, self });
}
+ if (self.requiresThunks()) for (self.thunks.items) |th| {
+ tp.spawnWg(&wg, Thunk.writeSymtab, .{ th, self, self });
+ };
}
if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;
@@ -2725,6 +2728,14 @@ fn calcSymtabSize(self: *MachO) !void {
var nimports: u32 = 0;
var strsize: u32 = 1;
+ if (self.requiresThunks()) for (self.thunks.items) |*th| {
+ th.output_symtab_ctx.ilocal = nlocals;
+ th.output_symtab_ctx.stroff = strsize;
+ th.calcSymtabSize(self);
+ nlocals += th.output_symtab_ctx.nlocals;
+ strsize += th.output_symtab_ctx.strsize;
+ };
+
for (files.items) |index| {
const file = self.getFile(index).?;
const ctx = switch (file) {
@@ -3199,7 +3210,7 @@ fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64
}
const InitMetadataOptions = struct {
- emit: Compilation.Emit,
+ emit: Path,
zo: *ZigObject,
symbol_count_hint: u64,
program_code_size_hint: u64,
@@ -3271,7 +3282,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
);
defer gpa.free(d_sym_path);
- var d_sym_bundle = try options.emit.directory.handle.makeOpenPath(d_sym_path, .{});
+ var d_sym_bundle = try options.emit.root_dir.handle.makeOpenPath(d_sym_path, .{});
defer d_sym_bundle.close();
const d_sym_file = try d_sym_bundle.createFile(options.emit.sub_path, .{
@@ -4603,6 +4614,7 @@ pub const Atom = @import("MachO/Atom.zig");
const AtomicBool = std.atomic.Value(bool);
const Bind = bind.Bind;
const Cache = std.Build.Cache;
+const Path = Cache.Path;
const CodeSignature = @import("MachO/CodeSignature.zig");
const Compilation = @import("../Compilation.zig");
const DataInCode = synthetic.DataInCode;
diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig
index 4827dae268..d6b77243a1 100644
--- a/src/link/MachO/ZigObject.zig
+++ b/src/link/MachO/ZigObject.zig
@@ -869,10 +869,11 @@ pub fn updateNav(
const zcu = pt.zcu;
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),
+ const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
+ .func => .none,
+ .variable => |variable| variable.init,
.@"extern" => |@"extern"| {
if (ip.isFunctionType(@"extern".ty)) return;
// Extern variable gets a __got entry only
@@ -883,10 +884,10 @@ pub fn updateNav(
sym.flags.is_extern_ptr = true;
return;
},
- else => nav_val,
+ else => nav.status.resolved.val,
};
- if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
+ if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) {
const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);
self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
@@ -900,7 +901,7 @@ pub fn updateNav(
&macho_file.base,
pt,
zcu.navSrcLoc(nav_index),
- nav_init,
+ Value.fromInterned(nav_init),
&code_buffer,
if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
.{ .parent_atom_index = sym_index },
diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig
index 74d0c58cbd..a891bedbd6 100644
--- a/src/link/MachO/load_commands.zig
+++ b/src/link/MachO/load_commands.zig
@@ -53,7 +53,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
if (macho_file.base.isDynLib()) {
const emit = macho_file.base.emit;
const install_name = macho_file.install_name orelse
- try emit.directory.join(gpa, &.{emit.sub_path});
+ try emit.root_dir.join(gpa, &.{emit.sub_path});
defer if (macho_file.install_name == null) gpa.free(install_name);
sizeofcmds += calcInstallNameLen(
@sizeOf(macho.dylib_command),
@@ -237,7 +237,7 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
const emit = macho_file.base.emit;
const install_name = macho_file.install_name orelse
- try emit.directory.join(gpa, &.{emit.sub_path});
+ try emit.root_dir.join(gpa, &.{emit.sub_path});
defer if (macho_file.install_name == null) gpa.free(install_name);
const curr = comp.version orelse std.SemanticVersion{
.major = 1,
diff --git a/src/link/MachO/thunks.zig b/src/link/MachO/thunks.zig
index 37013c54c4..4248785c54 100644
--- a/src/link/MachO/thunks.zig
+++ b/src/link/MachO/thunks.zig
@@ -85,6 +85,7 @@ pub const Thunk = struct {
value: u64 = 0,
out_n_sect: u8 = 0,
symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{},
+ output_symtab_ctx: MachO.SymtabCtx = .{},
pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
thunk.symbols.deinit(allocator);
@@ -116,6 +117,34 @@ pub const Thunk = struct {
}
}
+ pub fn calcSymtabSize(thunk: *Thunk, macho_file: *MachO) void {
+ thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
+ for (thunk.symbols.keys()) |ref| {
+ const sym = ref.getSymbol(macho_file).?;
+ thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + "__thunk".len + 1));
+ }
+ }
+
+ pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {
+ var n_strx = thunk.output_symtab_ctx.stroff;
+ for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
+ const sym = ref.getSymbol(macho_file).?;
+ const name = sym.getName(macho_file);
+ const out_sym = &ctx.symtab.items[ilocal];
+ out_sym.n_strx = n_strx;
+ @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
+ n_strx += @intCast(name.len);
+ @memcpy(ctx.strtab.items[n_strx..][0.."__thunk".len], "__thunk");
+ n_strx += @intCast("__thunk".len);
+ ctx.strtab.items[n_strx] = 0;
+ n_strx += 1;
+ out_sym.n_type = macho.N_SECT;
+ out_sym.n_sect = @intCast(thunk.out_n_sect + 1);
+ out_sym.n_value = @intCast(thunk.getTargetAddress(ref, macho_file));
+ out_sym.n_desc = 0;
+ }
+ }
+
pub fn format(
thunk: Thunk,
comptime unused_fmt_string: []const u8,
diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig
index cb95779d8e..1488f65ff9 100644
--- a/src/link/NvPtx.zig
+++ b/src/link/NvPtx.zig
@@ -11,6 +11,7 @@ const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const log = std.log.scoped(.link);
+const Path = std.Build.Cache.Path;
const Zcu = @import("../Zcu.zig");
const InternPool = @import("../InternPool.zig");
@@ -28,7 +29,7 @@ llvm_object: LlvmObject.Ptr,
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*NvPtx {
const target = comp.root_mod.resolved_target.result;
@@ -70,7 +71,7 @@ pub fn createEmpty(
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*NvPtx {
const target = comp.root_mod.resolved_target.result;
diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig
index d22c3b447c..27a3bf7bc8 100644
--- a/src/link/Plan9.zig
+++ b/src/link/Plan9.zig
@@ -23,6 +23,7 @@ const mem = std.mem;
const Allocator = std.mem.Allocator;
const log = std.log.scoped(.link);
const assert = std.debug.assert;
+const Path = std.Build.Cache.Path;
base: link.File,
sixtyfour_bit: bool,
@@ -275,7 +276,7 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*Plan9 {
const target = comp.root_mod.resolved_target.result;
@@ -447,6 +448,7 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
const nav = ip.getNav(nav_index);
const nav_val = zcu.navValue(nav_index);
const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
+ .func => return,
.variable => |variable| Value.fromInterned(variable.init),
.@"extern" => {
log.debug("found extern decl: {}", .{nav.name.fmt(ip)});
@@ -455,7 +457,7 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
else => nav_val,
};
- if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
+ if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) {
const atom_idx = try self.seeNav(pt, nav_index);
var code_buffer = std.ArrayList(u8).init(gpa);
@@ -1199,7 +1201,7 @@ pub fn deinit(self: *Plan9) void {
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*Plan9 {
const target = comp.root_mod.resolved_target.result;
@@ -1213,7 +1215,7 @@ pub fn open(
const self = try createEmpty(arena, comp, emit, options);
errdefer self.base.destroy();
- const file = try emit.directory.handle.createFile(emit.sub_path, .{
+ const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.read = true,
.mode = link.File.determineMode(
use_lld,
diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig
index f76ceec2f5..9964c09df0 100644
--- a/src/link/SpirV.zig
+++ b/src/link/SpirV.zig
@@ -26,6 +26,7 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const log = std.log.scoped(.link);
+const Path = std.Build.Cache.Path;
const Zcu = @import("../Zcu.zig");
const InternPool = @import("../InternPool.zig");
@@ -54,7 +55,7 @@ object: codegen.Object,
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*SpirV {
const gpa = comp.gpa;
@@ -95,7 +96,7 @@ pub fn createEmpty(
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*SpirV {
const target = comp.root_mod.resolved_target.result;
@@ -110,7 +111,7 @@ pub fn open(
errdefer spirv.base.destroy();
// TODO: read the file and keep valid parts instead of truncating
- const file = try emit.directory.handle.createFile(emit.sub_path, .{
+ const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.truncate = true,
.read = true,
});
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 87dd8c13f9..2c5fc3fe7a 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -22,6 +22,7 @@ const Air = @import("../Air.zig");
const Allocator = std.mem.Allocator;
const Archive = @import("Wasm/Archive.zig");
const Cache = std.Build.Cache;
+const Path = Cache.Path;
const CodeGen = @import("../arch/wasm/CodeGen.zig");
const Compilation = @import("../Compilation.zig");
const Dwarf = @import("Dwarf.zig");
@@ -346,7 +347,7 @@ pub const StringTable = struct {
pub fn open(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*Wasm {
// TODO: restore saved linker state, don't truncate the file, and
@@ -357,7 +358,7 @@ pub fn open(
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
- emit: Compilation.Emit,
+ emit: Path,
options: link.File.OpenOptions,
) !*Wasm {
const gpa = comp.gpa;
@@ -430,7 +431,7 @@ pub fn createEmpty(
// can be passed to LLD.
const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
- wasm.base.file = try emit.directory.handle.createFile(sub_path, .{
+ wasm.base.file = try emit.root_dir.handle.createFile(sub_path, .{
.truncate = true,
.read = true,
.mode = if (fs.has_executable_bit)
@@ -2496,7 +2497,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
const sub_prog_node = prog_node.start("Wasm Flush", 0);
defer sub_prog_node.end();
- const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type.
+ const directory = wasm.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (wasm.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| {
@@ -3346,7 +3347,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
const gpa = comp.gpa;
- const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type.
+ const directory = wasm.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
// If there is no Zig code to compile, then we should skip flushing the output file because it
diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig
index 0f73edefab..05c15f0732 100644
--- a/src/link/Wasm/ZigObject.zig
+++ b/src/link/Wasm/ZigObject.zig
@@ -259,7 +259,7 @@ pub fn updateNav(
else => .{ false, .none, nav_val },
};
- if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) {
+ if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) {
const gpa = wasm_file.base.comp.gpa;
const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);
const atom = wasm_file.getAtomPtr(atom_index);
diff --git a/src/main.zig b/src/main.zig
index 3429500bf8..226ec79467 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -3519,7 +3519,7 @@ fn buildOutputType(
if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: {
// Default to using `zig run` to execute the produced .c code from `zig test`.
const c_code_loc = emit_bin_loc orelse break :default_exec_args;
- const c_code_directory = c_code_loc.directory orelse comp.bin_file.?.emit.directory;
+ const c_code_directory = c_code_loc.directory orelse comp.bin_file.?.emit.root_dir;
const c_code_path = try fs.path.join(arena, &[_][]const u8{
c_code_directory.path orelse ".", c_code_loc.basename,
});
@@ -4142,7 +4142,7 @@ fn serve(
if (output.errors.errorMessageCount() != 0) {
try server.serveErrorBundle(output.errors);
} else {
- try server.serveEmitBinPath(output.out_zig_path, .{
+ try server.serveEmitDigest(&output.digest, .{
.flags = .{ .cache_hit = output.cache_hit },
});
}
@@ -4229,62 +4229,10 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
return;
}
- // This logic is counter-intuitive because the protocol accounts for each
- // emitted artifact possibly being in a different location, which correctly
- // matches the behavior of the compiler, however, the build system
- // currently always passes flags that makes all build artifacts output to
- // the same local cache directory, and relies on them all being in the same
- // directory.
- //
- // So, until the build system and protocol are changed to reflect this,
- // this logic must ensure that emit_bin_path is emitted for at least one
- // thing, if there are any artifacts.
-
- switch (comp.cache_use) {
- .incremental => if (comp.bin_file) |lf| {
- const full_path = try lf.emit.directory.join(gpa, &.{lf.emit.sub_path});
- defer gpa.free(full_path);
- try s.serveEmitBinPath(full_path, .{
- .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
- });
- return;
- },
- .whole => |whole| if (whole.bin_sub_path) |sub_path| {
- const full_path = try comp.local_cache_directory.join(gpa, &.{sub_path});
- defer gpa.free(full_path);
- try s.serveEmitBinPath(full_path, .{
- .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
- });
- return;
- },
- }
-
- for ([_]?Compilation.Emit{
- comp.docs_emit,
- comp.implib_emit,
- }) |opt_emit| {
- const emit = opt_emit orelse continue;
- const full_path = try emit.directory.join(gpa, &.{emit.sub_path});
- defer gpa.free(full_path);
- try s.serveEmitBinPath(full_path, .{
- .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
- });
- return;
- }
-
- for ([_]?Compilation.EmitLoc{
- comp.emit_asm,
- comp.emit_llvm_ir,
- comp.emit_llvm_bc,
- }) |opt_emit_loc| {
- const emit_loc = opt_emit_loc orelse continue;
- const directory = emit_loc.directory orelse continue;
- const full_path = try directory.join(gpa, &.{emit_loc.basename});
- defer gpa.free(full_path);
- try s.serveEmitBinPath(full_path, .{
+ if (comp.digest) |digest| {
+ try s.serveEmitDigest(&digest, .{
.flags = .{ .cache_hit = comp.last_update_was_cache_hit },
});
- return;
}
// Serve empty error bundle to indicate the update is done.
@@ -4308,7 +4256,7 @@ fn runOrTest(
// A naive `directory.join` here will indeed get the correct path to the binary,
// however, in the case of cwd, we actually want `./foo` so that the path can be executed.
const exe_path = try fs.path.join(arena, &[_][]const u8{
- lf.emit.directory.path orelse ".", lf.emit.sub_path,
+ lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
});
var argv = std.ArrayList([]const u8).init(gpa);
@@ -4420,7 +4368,7 @@ fn runOrTestHotSwap(
// tmp zig-cache and use it to spawn the child process. This way we are free to update
// the binary with each requested hot update.
.windows => blk: {
- try lf.emit.directory.handle.copyFile(lf.emit.sub_path, comp.local_cache_directory.handle, lf.emit.sub_path, .{});
+ try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.local_cache_directory.handle, lf.emit.sub_path, .{});
break :blk try fs.path.join(gpa, &[_][]const u8{
comp.local_cache_directory.path orelse ".", lf.emit.sub_path,
});
@@ -4429,7 +4377,7 @@ fn runOrTestHotSwap(
// A naive `directory.join` here will indeed get the correct path to the binary,
// however, in the case of cwd, we actually want `./foo` so that the path can be executed.
else => try fs.path.join(gpa, &[_][]const u8{
- lf.emit.directory.path orelse ".", lf.emit.sub_path,
+ lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
}),
};
defer gpa.free(exe_path);
@@ -4539,9 +4487,11 @@ fn cmdTranslateC(
};
if (fancy_output) |p| p.cache_hit = true;
- const digest = if (try man.hit()) digest: {
+ const bin_digest, const hex_digest = if (try man.hit()) digest: {
if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
- break :digest man.final();
+ const bin_digest = man.finalBin();
+ const hex_digest = Cache.binToHex(bin_digest);
+ break :digest .{ bin_digest, hex_digest };
} else digest: {
if (fancy_output) |p| p.cache_hit = false;
var argv = std.ArrayList([]const u8).init(arena);
@@ -4576,7 +4526,12 @@ fn cmdTranslateC(
Compilation.dump_argv(argv.items);
}
- const formatted = switch (comp.config.c_frontend) {
+ const Result = union(enum) {
+ success: []const u8,
+ error_bundle: std.zig.ErrorBundle,
+ };
+
+ const result: Result = switch (comp.config.c_frontend) {
.aro => f: {
var stdout: []u8 = undefined;
try jitCmd(comp.gpa, arena, argv.items, .{
@@ -4586,7 +4541,7 @@ fn cmdTranslateC(
.capture = &stdout,
.progress_node = prog_node,
});
- break :f stdout;
+ break :f .{ .success = stdout };
},
.clang => f: {
if (!build_options.have_llvm) unreachable;
@@ -4614,33 +4569,47 @@ fn cmdTranslateC(
c_headers_dir_path_z,
) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
- error.SemanticAnalyzeFail => {
- if (fancy_output) |p| {
- p.errors = errors;
- return;
- } else {
- errors.renderToStdErr(color.renderOptions());
- process.exit(1);
- }
- },
+ error.SemanticAnalyzeFail => break :f .{ .error_bundle = errors },
};
defer tree.deinit(comp.gpa);
- break :f try tree.render(arena);
+ break :f .{ .success = try tree.render(arena) };
},
};
- if (out_dep_path) |dep_file_path| {
+ if (out_dep_path) |dep_file_path| add_deps: {
const dep_basename = fs.path.basename(dep_file_path);
// Add the files depended on to the cache system.
- try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
+ man.addDepFilePost(zig_cache_tmp_dir, dep_basename) catch |err| switch (err) {
+ error.FileNotFound => {
+ // Clang didn't emit the dep file; nothing to add to the manifest.
+ break :add_deps;
+ },
+ else => |e| return e,
+ };
// Just to save disk space, we delete the file because it is never needed again.
zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| {
warn("failed to delete '{s}': {s}", .{ dep_file_path, @errorName(err) });
};
}
- const digest = man.final();
- const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });
+ const formatted = switch (result) {
+ .success => |formatted| formatted,
+ .error_bundle => |eb| {
+ if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
+ if (fancy_output) |p| {
+ p.errors = eb;
+ return;
+ } else {
+ eb.renderToStdErr(color.renderOptions());
+ process.exit(1);
+ }
+ },
+ };
+
+ const bin_digest = man.finalBin();
+ const hex_digest = Cache.binToHex(bin_digest);
+
+ const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &hex_digest });
var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close();
@@ -4656,16 +4625,14 @@ fn cmdTranslateC(
if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
- break :digest digest;
+ break :digest .{ bin_digest, hex_digest };
};
if (fancy_output) |p| {
- p.out_zig_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
- "o", &digest, translated_zig_basename,
- });
+ p.digest = bin_digest;
p.errors = std.zig.ErrorBundle.empty;
} else {
- const out_zig_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest, translated_zig_basename });
+ const out_zig_path = try fs.path.join(arena, &[_][]const u8{ "o", &hex_digest, translated_zig_basename });
const zig_file = comp.local_cache_directory.handle.openFile(out_zig_path, .{}) catch |err| {
const path = comp.local_cache_directory.path orelse ".";
fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });
diff --git a/src/print_air.zig b/src/print_air.zig
index 137461e6e4..4db66a1d3c 100644
--- a/src/print_air.zig
+++ b/src/print_air.zig
@@ -283,6 +283,7 @@ const Writer = struct {
.dbg_var_ptr,
.dbg_var_val,
+ .dbg_arg_inline,
=> try w.writeDbgVar(s, inst),
.struct_field_ptr => try w.writeStructField(s, inst),
@@ -358,10 +359,7 @@ const Writer = struct {
try w.writeType(s, arg.ty.toType());
switch (arg.name) {
.none => {},
- _ => {
- const name = w.air.nullTerminatedString(@intFromEnum(arg.name));
- try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)});
- },
+ _ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}),
}
}
@@ -686,8 +684,8 @@ const Writer = struct {
fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
try w.writeOperand(s, inst, 0, pl_op.operand);
- const name = w.air.nullTerminatedString(pl_op.payload);
- try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)});
+ const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
+ try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))});
}
fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
diff --git a/src/register_manager.zig b/src/register_manager.zig
index 751aed988a..7ca117be0c 100644
--- a/src/register_manager.zig
+++ b/src/register_manager.zig
@@ -93,6 +93,8 @@ pub fn RegisterManager(
comptime set: []const Register,
reg: Register,
) ?std.math.IntFittingRange(0, set.len - 1) {
+ @setEvalBranchQuota(3000);
+
const Id = @TypeOf(reg.id());
comptime var min_id: Id = std.math.maxInt(Id);
comptime var max_id: Id = std.math.minInt(Id);
diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig
index d08bc82828..ab1803c5b1 100644
--- a/test/behavior/maximum_minimum.zig
+++ b/test/behavior/maximum_minimum.zig
@@ -146,6 +146,8 @@ test "@min/max for floats" {
};
inline for (.{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
+ if (T == c_longdouble and builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21090
+
try S.doTheTest(T);
try comptime S.doTheTest(T);
}
diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig
index c4e00d9b0c..214fda28d6 100644
--- a/test/behavior/vector.zig
+++ b/test/behavior/vector.zig
@@ -773,6 +773,7 @@ test "vector reduce operation" {
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21091
const S = struct {
fn testReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void {
diff --git a/test/incremental/delete_comptime_decls b/test/incremental/delete_comptime_decls
index 424dc37ea8..d0da7110c3 100644
--- a/test/incremental/delete_comptime_decls
+++ b/test/incremental/delete_comptime_decls
@@ -31,7 +31,7 @@ pub fn main() void {}
comptime {
const x: [*c]u8 = null;
var runtime_len: usize = undefined;
- runtime_len = 0;
+ runtime_len = 0;
const y = x[0..runtime_len];
_ = y;
}
diff --git a/test/incremental/modify_inline_fn b/test/incremental/modify_inline_fn
new file mode 100644
index 0000000000..633e7a0728
--- /dev/null
+++ b/test/incremental/modify_inline_fn
@@ -0,0 +1,23 @@
+#target=x86_64-linux
+#update=initial version
+#file=main.zig
+const std = @import("std");
+pub fn main() !void {
+ const str = getStr();
+ try std.io.getStdOut().writeAll(str);
+}
+inline fn getStr() []const u8 {
+ return "foo\n";
+}
+#expect_stdout="foo\n"
+#update=change the string
+#file=main.zig
+const std = @import("std");
+pub fn main() !void {
+ const str = getStr();
+ try std.io.getStdOut().writeAll(str);
+}
+inline fn getStr() []const u8 {
+ return "bar\n";
+}
+#expect_stdout="bar\n"
diff --git a/test/incremental/move_src b/test/incremental/move_src
new file mode 100644
index 0000000000..8313bdfac2
--- /dev/null
+++ b/test/incremental/move_src
@@ -0,0 +1,29 @@
+#target=x86_64-linux
+#update=initial version
+#file=main.zig
+const std = @import("std");
+pub fn main() !void {
+ try std.io.getStdOut().writer().print("{d} {d}\n", .{ foo(), bar() });
+}
+fn foo() u32 {
+ return @src().line;
+}
+fn bar() u32 {
+ return 123;
+}
+#expect_stdout="6 123\n"
+
+#update=add newline
+#file=main.zig
+const std = @import("std");
+pub fn main() !void {
+ try std.io.getStdOut().writer().print("{d} {d}\n", .{ foo(), bar() });
+}
+
+fn foo() u32 {
+ return @src().line;
+}
+fn bar() u32 {
+ return 123;
+}
+#expect_stdout="7 123\n"
diff --git a/test/link/elf.zig b/test/link/elf.zig
index 5539638ba7..98253811b2 100644
--- a/test/link/elf.zig
+++ b/test/link/elf.zig
@@ -2973,44 +2973,27 @@ fn testStrip(b: *Build, opts: Options) *Step {
fn testThunks(b: *Build, opts: Options) *Step {
const test_step = addTestStep(b, "thunks", opts);
- const src =
- \\#include <stdio.h>
- \\__attribute__((aligned(0x8000000))) int bar() {
- \\ return 42;
- \\}
- \\int foobar();
- \\int foo() {
- \\ return bar() - foobar();
- \\}
- \\__attribute__((aligned(0x8000000))) int foobar() {
- \\ return 42;
- \\}
- \\int main() {
- \\ printf("bar=%d, foo=%d, foobar=%d", bar(), foo(), foobar());
- \\ return foo();
- \\}
- ;
-
- {
- const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = src });
- exe.link_function_sections = true;
- exe.linkLibC();
-
- const run = addRunArtifact(exe);
- run.expectStdOutEqual("bar=42, foo=0, foobar=42");
- run.expectExitCode(0);
- test_step.dependOn(&run.step);
- }
-
- {
- const exe = addExecutable(b, opts, .{ .name = "main2", .c_source_bytes = src });
- exe.linkLibC();
+ const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes =
+ \\void foo();
+ \\__attribute__((section(".bar"))) void bar() {
+ \\ return foo();
+ \\}
+ \\__attribute__((section(".foo"))) void foo() {
+ \\ return bar();
+ \\}
+ \\int main() {
+ \\ foo();
+ \\ bar();
+ \\ return 0;
+ \\}
+ });
- const run = addRunArtifact(exe);
- run.expectStdOutEqual("bar=42, foo=0, foobar=42");
- run.expectExitCode(0);
- test_step.dependOn(&run.step);
- }
+ const check = exe.checkObject();
+ check.checkInSymtab();
+ check.checkContains("foo$thunk");
+ check.checkInSymtab();
+ check.checkContains("bar$thunk");
+ test_step.dependOn(&check.step);
return test_step;
}
diff --git a/test/link/macho.zig b/test/link/macho.zig
index 30982e6ba2..730edcf3a9 100644
--- a/test/link/macho.zig
+++ b/test/link/macho.zig
@@ -2204,25 +2204,28 @@ fn testThunks(b: *Build, opts: Options) *Step {
const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes =
\\#include <stdio.h>
- \\__attribute__((aligned(0x8000000))) int bar() {
- \\ return 42;
+ \\void bar() {
+ \\ printf("bar");
\\}
- \\int foobar();
- \\int foo() {
- \\ return bar() - foobar();
- \\}
- \\__attribute__((aligned(0x8000000))) int foobar() {
- \\ return 42;
+ \\void foo() {
+ \\ fprintf(stdout, "foo");
\\}
\\int main() {
- \\ printf("bar=%d, foo=%d, foobar=%d", bar(), foo(), foobar());
- \\ return foo();
+ \\ foo();
+ \\ bar();
+ \\ return 0;
\\}
});
+ const check = exe.checkObject();
+ check.checkInSymtab();
+ check.checkContains("_printf__thunk");
+ check.checkInSymtab();
+ check.checkContains("_fprintf__thunk");
+ test_step.dependOn(&check.step);
+
const run = addRunArtifact(exe);
- run.expectStdOutEqual("bar=42, foo=0, foobar=42");
- run.expectExitCode(0);
+ run.expectStdOutEqual("foobar");
test_step.dependOn(&run.step);
return test_step;
diff --git a/test/src/Debugger.zig b/test/src/Debugger.zig
index 2ff141dd84..718d89dd1c 100644
--- a/test/src/Debugger.zig
+++ b/test/src/Debugger.zig
@@ -205,26 +205,26 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\ single_volatile: *volatile u32 = @ptrFromInt(0x1018),
\\ single_const_volatile: *const volatile u32 = @ptrFromInt(0x101c),
\\ single_allowzero: *allowzero u32 = @ptrFromInt(0x1020),
- \\ single_const_allowzero: *const allowzero u32 = @ptrFromInt(0x1024),
- \\ single_volatile_allowzero: *volatile allowzero u32 = @ptrFromInt(0x1028),
- \\ single_const_volatile_allowzero: *const volatile allowzero u32 = @ptrFromInt(0x102c),
+ \\ single_allowzero_const: *allowzero const u32 = @ptrFromInt(0x1024),
+ \\ single_allowzero_volatile: *allowzero volatile u32 = @ptrFromInt(0x1028),
+ \\ single_allowzero_const_volatile: *allowzero const volatile u32 = @ptrFromInt(0x102c),
\\
\\ many: [*]u32 = @ptrFromInt(0x2010),
\\ many_const: [*]const u32 = @ptrFromInt(0x2014),
\\ many_volatile: [*]volatile u32 = @ptrFromInt(0x2018),
\\ many_const_volatile: [*]const volatile u32 = @ptrFromInt(0x201c),
\\ many_allowzero: [*]allowzero u32 = @ptrFromInt(0x2020),
- \\ many_const_allowzero: [*]const allowzero u32 = @ptrFromInt(0x2024),
- \\ many_volatile_allowzero: [*]volatile allowzero u32 = @ptrFromInt(0x2028),
- \\ many_const_volatile_allowzero: [*]const volatile allowzero u32 = @ptrFromInt(0x202c),
+ \\ many_allowzero_const: [*]allowzero const u32 = @ptrFromInt(0x2024),
+ \\ many_allowzero_volatile: [*]allowzero volatile u32 = @ptrFromInt(0x2028),
+ \\ many_allowzero_const_volatile: [*]allowzero const volatile u32 = @ptrFromInt(0x202c),
\\ slice: []u32 = array[0..1],
\\ slice_const: []const u32 = array[0..2],
\\ slice_volatile: []volatile u32 = array[0..3],
\\ slice_const_volatile: []const volatile u32 = array[0..4],
\\ slice_allowzero: []allowzero u32 = array[4..4],
- \\ slice_const_allowzero: []const allowzero u32 = array[4..5],
- \\ slice_volatile_allowzero: []volatile allowzero u32 = array[4..6],
- \\ slice_const_volatile_allowzero: []const volatile allowzero u32 = array[4..7],
+ \\ slice_allowzero_const: []allowzero const u32 = array[4..5],
+ \\ slice_allowzero_volatile: []allowzero volatile u32 = array[4..6],
+ \\ slice_allowzero_const_volatile: []allowzero const volatile u32 = array[4..7],
\\
\\ c: [*c]u32 = @ptrFromInt(0x4010),
\\ c_const: [*c]const u32 = @ptrFromInt(0x4014),
@@ -254,17 +254,17 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\ (*volatile u32) single_volatile = 0x0000000000001018
\\ (*const volatile u32) single_const_volatile = 0x000000000000101c
\\ (*allowzero u32) single_allowzero = 0x0000000000001020
- \\ (*const allowzero u32) single_const_allowzero = 0x0000000000001024
- \\ (*volatile allowzero u32) single_volatile_allowzero = 0x0000000000001028
- \\ (*const volatile allowzero u32) single_const_volatile_allowzero = 0x000000000000102c
+ \\ (*allowzero const u32) single_allowzero_const = 0x0000000000001024
+ \\ (*allowzero volatile u32) single_allowzero_volatile = 0x0000000000001028
+ \\ (*allowzero const volatile u32) single_allowzero_const_volatile = 0x000000000000102c
\\ ([*]u32) many = 0x0000000000002010
\\ ([*]const u32) many_const = 0x0000000000002014
\\ ([*]volatile u32) many_volatile = 0x0000000000002018
\\ ([*]const volatile u32) many_const_volatile = 0x000000000000201c
\\ ([*]allowzero u32) many_allowzero = 0x0000000000002020
- \\ ([*]const allowzero u32) many_const_allowzero = 0x0000000000002024
- \\ ([*]volatile allowzero u32) many_volatile_allowzero = 0x0000000000002028
- \\ ([*]const volatile allowzero u32) many_const_volatile_allowzero = 0x000000000000202c
+ \\ ([*]allowzero const u32) many_allowzero_const = 0x0000000000002024
+ \\ ([*]allowzero volatile u32) many_allowzero_volatile = 0x0000000000002028
+ \\ ([*]allowzero const volatile u32) many_allowzero_const_volatile = 0x000000000000202c
\\ ([]u32) slice = len=1 {
\\ (u32) [0] = 3010
\\ }
@@ -284,14 +284,14 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\ (u32) [3] = 3022
\\ }
\\ ([]allowzero u32) slice_allowzero = len=0 {}
- \\ ([]const allowzero u32) slice_const_allowzero = len=1 {
+ \\ ([]allowzero const u32) slice_allowzero_const = len=1 {
\\ (u32) [0] = 3026
\\ }
- \\ ([]volatile allowzero u32) slice_volatile_allowzero = len=2 {
+ \\ ([]allowzero volatile u32) slice_allowzero_volatile = len=2 {
\\ (u32) [0] = 3026
\\ (u32) [1] = 3030
\\ }
- \\ ([]const volatile allowzero u32) slice_const_volatile_allowzero = len=3 {
+ \\ ([]allowzero const volatile u32) slice_allowzero_const_volatile = len=3 {
\\ (u32) [0] = 3026
\\ (u32) [1] = 3030
\\ (u32) [2] = 3034
@@ -587,7 +587,7 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
},
);
db.addLldbTest(
- "cross_module_call",
+ "inline_call",
target,
&.{
.{
@@ -595,8 +595,18 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
.source =
\\const module = @import("module");
\\pub fn main() void {
- \\ module.foo(123);
- \\ module.bar(456);
+ \\ fa(12);
+ \\ fb(34);
+ \\ module.fc(56);
+ \\ module.fd(78);
+ \\}
+ \\fn fa(pa: u32) void {
+ \\ const la = ~pa;
+ \\ _ = la;
+ \\}
+ \\inline fn fb(pb: u32) void {
+ \\ const lb = ~pb;
+ \\ _ = lb;
\\}
\\
,
@@ -605,32 +615,120 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
.import = "module",
.path = "module.zig",
.source =
- \\pub fn foo(x: u32) void {
- \\ _ = x;
+ \\pub fn fc(pc: u32) void {
+ \\ const lc = ~pc;
+ \\ _ = lc;
\\}
- \\pub inline fn bar(y: u32) void {
- \\ _ = y;
+ \\pub inline fn fd(pd: u32) void {
+ \\ const ld = ~pd;
+ \\ _ = ld;
\\}
\\
,
},
},
- \\breakpoint set --file module.zig --source-pattern-regexp '_ = x;'
+ \\settings set frame-format 'frame #${frame.index}:{ ${module.file.basename}{\`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${line.file.basename}:${line.number}{:${line.column}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\n'
+ \\
+ \\breakpoint set --file main.zig --source-pattern-regexp '_ = la;'
+ \\process launch
+ \\frame variable pa la
+ \\thread backtrace --count 2
+ \\breakpoint delete --force 1
+ \\
+ \\breakpoint set --file main.zig --source-pattern-regexp '_ = lb;'
+ \\process continue
+ \\frame variable pb lb
+ \\thread backtrace --count 2
+ \\breakpoint delete --force 2
+ \\
+ \\breakpoint set --file module.zig --source-pattern-regexp '_ = lc;'
+ \\process continue
+ \\frame variable pc lc
+ \\thread backtrace --count 2
+ \\breakpoint delete --force 3
+ \\
+ \\breakpoint set --file module.zig --line 7
+ \\process continue
+ \\frame variable pd ld
+ \\thread backtrace --count 2
+ \\breakpoint delete --force 4
+ ,
+ &.{
+ \\(lldb) frame variable pa la
+ \\(u32) pa = 12
+ \\(u32) la = 4294967283
+ \\(lldb) thread backtrace --count 2
+ \\* thread #1, name = 'inline_call', stop reason = breakpoint 1.1
+ \\ * frame #0: inline_call`main.fa(pa=12) at main.zig:10:5
+ \\ frame #1: inline_call`main.main at main.zig:3:7
+ \\(lldb) breakpoint delete --force 1
+ \\1 breakpoints deleted; 0 breakpoint locations disabled.
+ ,
+ \\(lldb) frame variable pb lb
+ \\(u32) pb = 34
+ \\(u32) lb = 4294967261
+ \\(lldb) thread backtrace --count 2
+ \\* thread #1, name = 'inline_call', stop reason = breakpoint 2.1
+ \\ * frame #0: inline_call`main.main [inlined] fb(pb=34) at main.zig:14:5
+ \\ frame #1: inline_call`main.main at main.zig:4:7
+ \\(lldb) breakpoint delete --force 2
+ \\1 breakpoints deleted; 0 breakpoint locations disabled.
+ ,
+ \\(lldb) frame variable pc lc
+ \\(u32) pc = 56
+ \\(u32) lc = 4294967239
+ \\(lldb) thread backtrace --count 2
+ \\* thread #1, name = 'inline_call', stop reason = breakpoint 3.1
+ \\ * frame #0: inline_call`module.fc(pc=56) at module.zig:3:5
+ \\ frame #1: inline_call`main.main at main.zig:5:14
+ \\(lldb) breakpoint delete --force 3
+ \\1 breakpoints deleted; 0 breakpoint locations disabled.
+ ,
+ \\(lldb) frame variable pd ld
+ \\(u32) pd = 78
+ \\(u32) ld = 4294967217
+ \\(lldb) thread backtrace --count 2
+ \\* thread #1, name = 'inline_call', stop reason = breakpoint 4.1
+ \\ * frame #0: inline_call`main.main [inlined] fd(pd=78) at module.zig:7:5
+ \\ frame #1: inline_call`main.main at main.zig:6:14
+ \\(lldb) breakpoint delete --force 4
+ \\1 breakpoints deleted; 0 breakpoint locations disabled.
+ },
+ );
+ db.addLldbTest(
+ "link_object",
+ target,
+ &.{
+ .{
+ .path = "main.zig",
+ .source =
+ \\extern fn fabsf(f32) f32;
+ \\pub fn main() void {
+ \\ var x: f32 = -1234.5;
+ \\ x = fabsf(x);
+ \\ _ = &x;
+ \\}
+ ,
+ },
+ },
+ \\breakpoint set --file main.zig --source-pattern-regexp 'x = fabsf\(x\);'
\\process launch
- \\source info
+ \\frame variable x
\\breakpoint delete --force 1
\\
- \\breakpoint set --file module.zig --line 5
+ \\breakpoint set --file main.zig --source-pattern-regexp '_ = &x;'
\\process continue
- \\source info
+ \\frame variable x
\\breakpoint delete --force 2
,
&.{
- \\/module.zig:2:5
+ \\(lldb) frame variable x
+ \\(f32) x = -1234.5
\\(lldb) breakpoint delete --force 1
\\1 breakpoints deleted; 0 breakpoint locations disabled.
,
- \\/module.zig:5:5
+ \\(lldb) frame variable x
+ \\(f32) x = 1234.5
\\(lldb) breakpoint delete --force 2
\\1 breakpoints deleted; 0 breakpoint locations disabled.
},
diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon
index 8e4d727642..30ec07823b 100644
--- a/test/standalone/build.zig.zon
+++ b/test/standalone/build.zig.zon
@@ -51,14 +51,15 @@
.install_raw_hex = .{
.path = "install_raw_hex",
},
- // https://github.com/ziglang/zig/issues/17484
- //.emit_asm_and_bin = .{
- // .path = "emit_asm_and_bin",
- //},
- // https://github.com/ziglang/zig/issues/17484
- //.issue_12588 = .{
- // .path = "issue_12588",
- //},
+ .emit_asm_and_bin = .{
+ .path = "emit_asm_and_bin",
+ },
+ .emit_llvm_no_bin = .{
+ .path = "emit_llvm_no_bin",
+ },
+ .emit_asm_no_bin = .{
+ .path = "emit_asm_no_bin",
+ },
.child_process = .{
.path = "child_process",
},
diff --git a/test/standalone/emit_asm_no_bin/build.zig b/test/standalone/emit_asm_no_bin/build.zig
new file mode 100644
index 0000000000..f2f2391bc1
--- /dev/null
+++ b/test/standalone/emit_asm_no_bin/build.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn build(b: *std.Build) void {
+ const test_step = b.step("test", "Test it");
+ b.default_step = test_step;
+
+ const optimize: std.builtin.OptimizeMode = .Debug;
+
+ const obj = b.addObject(.{
+ .name = "main",
+ .root_source_file = b.path("main.zig"),
+ .optimize = optimize,
+ .target = b.graph.host,
+ });
+ _ = obj.getEmittedAsm();
+ b.default_step.dependOn(&obj.step);
+
+ test_step.dependOn(&obj.step);
+}
diff --git a/test/standalone/emit_asm_no_bin/main.zig b/test/standalone/emit_asm_no_bin/main.zig
new file mode 100644
index 0000000000..902b554db0
--- /dev/null
+++ b/test/standalone/emit_asm_no_bin/main.zig
@@ -0,0 +1 @@
+pub fn main() void {}
diff --git a/test/standalone/issue_12588/build.zig b/test/standalone/emit_llvm_no_bin/build.zig
index f82dd51930..f82dd51930 100644
--- a/test/standalone/issue_12588/build.zig
+++ b/test/standalone/emit_llvm_no_bin/build.zig
diff --git a/test/standalone/issue_12588/main.zig b/test/standalone/emit_llvm_no_bin/main.zig
index 47f67515c7..47f67515c7 100644
--- a/test/standalone/issue_12588/main.zig
+++ b/test/standalone/emit_llvm_no_bin/main.zig
diff --git a/test/tests.zig b/test/tests.zig
index 6b044e91ba..73934950db 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -367,6 +367,54 @@ const test_targets = blk: {
.{
.target = .{
+ .cpu_arch = .mips64,
+ .os_tag = .linux,
+ .abi = .none,
+ },
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mips64,
+ .os_tag = .linux,
+ .abi = .musl,
+ },
+ .link_libc = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mips64,
+ .os_tag = .linux,
+ .abi = .gnuabi64,
+ },
+ .link_libc = true,
+ },
+
+ .{
+ .target = .{
+ .cpu_arch = .mips64el,
+ .os_tag = .linux,
+ .abi = .none,
+ },
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mips64el,
+ .os_tag = .linux,
+ .abi = .musl,
+ },
+ .link_libc = true,
+ },
+ .{
+ .target = .{
+ .cpu_arch = .mips64el,
+ .os_tag = .linux,
+ .abi = .gnuabi64,
+ },
+ .link_libc = true,
+ },
+
+ .{
+ .target = .{
.cpu_arch = .powerpc,
.os_tag = .linux,
.abi = .none,
diff --git a/tools/incr-check.zig b/tools/incr-check.zig
index 0386f1a12d..a5c0afc62a 100644
--- a/tools/incr-check.zig
+++ b/tools/incr-check.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const fatal = std.process.fatal;
const Allocator = std.mem.Allocator;
+const Cache = std.Build.Cache;
const usage = "usage: incr-check <zig binary path> <input file> [--zig-lib-dir lib] [--debug-zcu] [--emit none|bin|c] [--zig-cc-binary /path/to/zig]";
@@ -233,30 +234,52 @@ const Eval = struct {
fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data});
}
}
- if (result_error_bundle.errorMessageCount() == 0) {
- // Empty bundle indicates successful update in a `-fno-emit-bin` build.
- try eval.checkSuccessOutcome(update, null, prog_node);
- } else {
+ if (result_error_bundle.errorMessageCount() != 0) {
try eval.checkErrorOutcome(update, result_error_bundle);
}
// This message indicates the end of the update.
stdout.discard(body.len);
return;
},
- .emit_bin_path => {
- const EbpHdr = std.zig.Server.Message.EmitBinPath;
+ .emit_digest => {
+ const EbpHdr = std.zig.Server.Message.EmitDigest;
const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
_ = ebp_hdr;
- const result_binary = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);
if (stderr.readableLength() > 0) {
const stderr_data = try stderr.toOwnedSlice();
if (eval.allow_stderr) {
- std.log.info("emit_bin_path included stderr:\n{s}", .{stderr_data});
+ std.log.info("emit_digest included stderr:\n{s}", .{stderr_data});
} else {
- fatal("emit_bin_path included unexpected stderr:\n{s}", .{stderr_data});
+ fatal("emit_digest included unexpected stderr:\n{s}", .{stderr_data});
}
}
- try eval.checkSuccessOutcome(update, result_binary, prog_node);
+
+ if (eval.emit == .none) {
+ try eval.checkSuccessOutcome(update, null, prog_node);
+ // This message indicates the end of the update.
+ stdout.discard(body.len);
+ return;
+ }
+
+ const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
+ const result_dir = ".local-cache" ++ std.fs.path.sep_str ++ "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*);
+
+ const name = std.fs.path.stem(std.fs.path.basename(eval.case.root_source_file));
+ const bin_name = try std.zig.binNameAlloc(arena, .{
+ .root_name = name,
+ .target = try std.zig.system.resolveTargetQuery(try std.Build.parseTargetQuery(.{
+ .arch_os_abi = eval.case.target_query,
+ .object_format = switch (eval.emit) {
+ .none => unreachable,
+ .bin => null,
+ .c => "c",
+ },
+ })),
+ .output_mode = .Exe,
+ });
+ const bin_path = try std.fs.path.join(arena, &.{ result_dir, bin_name });
+
+ try eval.checkSuccessOutcome(update, bin_path, prog_node);
// This message indicates the end of the update.
stdout.discard(body.len);
return;