main: reimplement compiler debug flags

* Add `.llvmbc`/`.llvmir` to `ObjectFormat` for emitting unoptimized IR
* Replace `--verbose-air`, `--verbose-intern-pool`,
  `--verbose-generic-instances`, `--verbose-llvm-ir`, and
  `--verbose-llvm-bc` with various `--debug-log` scopes
  * `--debug-log illegal-air`: pre-legalized Air
  * `--debug-log legal-air`: post-legalized Air
  * `--debug-log air`: final Air with liveness
  * `--debug-log ip-stats`: InternPool statistics
  * `--debug-log ip-values`: InternPool values
  * `--debug-log ip-generic-instances`: InternPool generic instances
  * `--debug-log llvm-ir`: pre-optimized LLVM IR
  * `--debug-log opt-llvm-ir`: post-optimized LLVM IR
* Delete `--verbose-cimport` which does nothing
* Delete `--verbose-llvm-cpu-features` which is equivalent to looking at
  the outputs of `--show-builtin` and `--debug-log llvm-ir`
This commit is contained in:
Jacob Young authored and Andrew Kelley committed 2026-10-21 10:04:01 -07:00
1 parent 77576c9603
commit f08a8f0fc2
48 files changed
+335 -407

No files matched your search

+1 -1
View File
@@ -330,7 +330,7 @@ set(ZIG_STAGE2_SOURCES
src/Air/Legalize.zig
src/Air/Liveness.zig
src/Air/Liveness/Verify.zig
src/Air/print.zig
src/Air/Print.zig
src/Builtin.zig
src/Compilation.zig
src/Compilation/Config.zig
+1 -1
View File
@@ -179,7 +179,7 @@ int main(int argc, char **argv) {
"pub const version: [:0]const u8 = \"%s\";\n"
"pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n"
"pub const enable_debug_extensions = false;\n"
"pub const enable_logging = false;\n"
"pub const log_level: @import(\"std\").log.Level = .err;\n"
"pub const enable_link_snapshots = false;\n"
"pub const enable_tracy = false;\n"
"pub const value_tracing = false;\n"
+17 -7
View File
@@ -25,6 +25,10 @@ pub fn build(b: *std.Build) !void {
},
});
const optimize = b.standardOptimizeOption(.{});
const is_debug = switch (optimize) {
.debug => true,
.safe, .fast, .small => false,
};
const flat = b.option(bool, "flat", "Put files into the installation prefix in a manner suited for upstream distribution rather than a posix file system hierarchy standard") orelse false;
const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");
@@ -205,9 +209,9 @@ pub fn build(b: *std.Build) !void {
const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;
const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {
if (strip == true) break :blk @as(u32, 0);
if (optimize != .debug) break :blk 0;
break :blk 4;
if (strip == true) break :blk 0;
if (is_debug) break :blk 4;
break :blk 0;
};
const exe = addCompilerStep(b, .{
@@ -255,9 +259,15 @@ pub fn build(b: *std.Build) !void {
exe.root_module.link_libc = true;
}
const is_debug = optimize == .debug;
const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug;
const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug;
const log_level: std.log.Level = b.option(std.log.Level, "log", "Enable logs of the given or higher severity. Passing 'debug' still requires passing '--debug-log' to actually see any debug logs.") orelse switch (enable_debug_extensions) {
true => .debug,
false => switch (optimize) {
.debug => .debug,
.safe, .fast => .info,
.small => .err,
},
};
const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
const version_slice = if (opt_version_string) |version| version else v: {
@@ -398,7 +408,7 @@ pub fn build(b: *std.Build) !void {
exe_options.addOption(std.SemanticVersion, "semver", semver);
exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions);
exe_options.addOption(bool, "enable_logging", enable_logging);
exe_options.addOption(std.log.Level, "log_level", log_level);
exe_options.addOption(bool, "enable_tracy", tracy != null);
exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
@@ -837,7 +847,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
exe_options.addOption([:0]const u8, "version", version);
exe_options.addOption(std.SemanticVersion, "semver", semver);
exe_options.addOption(bool, "enable_debug_extensions", false);
exe_options.addOption(bool, "enable_logging", false);
exe_options.addOption(std.log.Level, "log_level", .err);
exe_options.addOption(bool, "enable_tracy", false);
exe_options.addOption(bool, "enable_tracy_callstack", false);
exe_options.addOption(bool, "enable_tracy_allocation", false);
-4
View File
@@ -509,14 +509,10 @@ pub fn main(init: process.Init.Minimal) !void {
} else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) {
// --glibc-runtimes was the old name of the flag; kept for compatibility for now.
graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i);
} else if (mem.eql(u8, arg, "--verbose-air")) {
graph.verbose_air = true;
} else if (mem.eql(u8, arg, "--verbose-cc")) {
graph.verbose_cc = true;
} else if (mem.eql(u8, arg, "--verbose-link")) {
graph.verbose_link = true;
} else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
graph.verbose_llvm_ir = true;
} else if (mem.eql(u8, arg, "--watch")) {
watch_flag = true;
} else if (mem.eql(u8, arg, "--time-report")) {
-3
View File
@@ -32,11 +32,8 @@ debug_compile_errors: bool = false,
debug_incremental: bool = false,
fuzzing: bool = false,
verbose: bool = false,
verbose_air: bool = false,
verbose_cc: bool = false,
verbose_link: bool = false,
verbose_llvm_cpu_features: bool = false,
verbose_llvm_ir: bool = false,
libc_file: ?[]const u8 = null,
/// What does this do? Nobody bothered to document it, and I think it's a
/// smelly option. So unless somebody deletes these passive aggressive comments
+2 -6
View File
@@ -351,6 +351,8 @@ const general_usage =
\\ preferred optimization mode: fast, safe, small
\\
\\ --verbose Print commands before executing them
\\ --verbose-cc Print C compiler commands before executing them
\\ --verbose-link Print linker commands before executing them
\\ --color [auto|off|on] Enable or disable colored error messages
\\ --error-style [style] Control how build errors are printed
\\ verbose (Default) Report errors with full context
@@ -417,11 +419,5 @@ const general_usage =
\\ none (default) No build ID
\\ --debug-log [scope] Enable debugging the compiler
\\ --debug-pkg-config Fail if unknown pkg-config flags encountered
\\ --verbose-link Enable compiler debug output for linking
\\ --verbose-air Enable compiler debug output for Zig AIR
\\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
\\ --verbose-cimport Enable compiler debug output for C imports
\\ --verbose-cc Enable compiler debug output for C compilation
\\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
\\
;
+1 -4
View File
@@ -608,11 +608,8 @@ fn lowerZigArgs(
try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors);
try addBool(gpa, zig_args, "--debug-incremental", graph.debug_incremental);
try addBool(gpa, zig_args, "--verbose-air", graph.verbose_air);
try addBool(gpa, zig_args, "--verbose-llvm-ir", graph.verbose_llvm_ir);
try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or conf_comp.flags.verbose_link);
try addBool(gpa, zig_args, "--verbose-cc", graph.verbose_cc or conf_comp.flags.verbose_cc);
try addBool(gpa, zig_args, "--verbose-llvm-cpu-features", graph.verbose_llvm_cpu_features);
try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or conf_comp.flags.verbose_link);
try addBool(gpa, zig_args, "--time-report", graph.time_report);
if (conf_comp.generated_bin.value == null) try zig_args.append(gpa, "-fno-emit-bin");
+1 -1
View File
@@ -927,7 +927,7 @@ pub fn parseArgs(
break :debug switch (d.comp.target.ofmt) {
.elf, .macho, .wasm => .{ .dwarf = .@"32" },
.coff => .code_view,
.c => switch (d.comp.target.os.tag) {
.c, .llvmbc, .llvmir => switch (d.comp.target.os.tag) {
.windows, .uefi => .code_view,
else => .{ .dwarf = .@"32" },
},
+2
View File
@@ -2519,6 +2519,8 @@ pub const TargetQuery = struct {
coff,
elf,
hex,
llvmbc,
llvmir,
macho,
plan9,
raw,
+6
View File
@@ -1043,6 +1043,10 @@ pub const ObjectFormat = enum {
elf,
/// The Intel HEX format for storing binary code in ASCII text.
hex,
/// LLVM binary intermediate representation.
llvmbc,
/// LLVM text intermediate representation.
llvmir,
/// The Mach object format used by macOS and other Apple platforms.
macho,
/// The a.out format used by Plan 9 from Bell Labs.
@@ -1060,6 +1064,8 @@ pub const ObjectFormat = enum {
.coff => ".obj",
.elf, .macho, .wasm => ".o",
.hex => ".ihex",
.llvmbc => ".bc",
.llvmir => ".ll",
.plan9 => arch.plan9Ext(),
.raw => ".bin",
.spirv => ".spv",
+1 -1
View File
@@ -76,7 +76,7 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type {
},
.macho => @import("debug/SelfInfo/MachO.zig"),
.plan9, .spirv, .wasm, .raw, .hex => void,
.c => unreachable,
.c, .llvmbc, .llvmir => unreachable,
};
}
+7 -1
View File
@@ -285,7 +285,13 @@ pub fn Alt(
pub fn alt(
context: anytype,
comptime func_name: @EnumLiteral(),
) Alt(@TypeOf(context), @field(@TypeOf(context), @tagName(func_name))) {
) Alt(@TypeOf(context), @field(switch (@typeInfo(@TypeOf(context))) {
else => @TypeOf(context),
.pointer => |pointer| switch (pointer.size) {
else => @TypeOf(context),
.one => pointer.child,
},
}, @tagName(func_name))) {
return .{ .data = context };
}
+2
View File
@@ -218,6 +218,8 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
},
.Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
},
.llvmbc => return std.fmt.allocPrint(allocator, "{s}.bc", .{root_name}),
.llvmir => return std.fmt.allocPrint(allocator, "{s}.ll", .{root_name}),
.macho => switch (options.output_mode) {
.Exe => return allocator.dupe(u8, root_name),
.Lib => {
+15 -4
View File
@@ -10855,11 +10855,22 @@ pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, va
b.alignment_forward_references.items[index] = value;
}
pub fn dump(b: *Builder, io: Io) void {
var buffer: [4000]u8 = undefined;
const stderr: Io.File = .stderr();
b.printToFile(io, stderr, &buffer) catch {};
pub const Print = struct {
name: []const u8,
builder: *Builder,
err: ?Allocator.Error,
pub fn format(p: *Print, w: *Writer) Writer.Error!void {
try w.print("{q}", .{p.name});
p.builder.print(w) catch |err| switch (err) {
error.WriteFailed => |e| return e,
error.OutOfMemory => |e| {
p.err = e;
return error.WriteFailed;
},
};
}
};
pub fn printToFilePath(b: *Builder, io: Io, dir: Io.Dir, path: []const u8) !void {
var buffer: [4000]u8 = undefined;
+5 -5
View File
@@ -13,10 +13,10 @@ const InternPool = @import("InternPool.zig");
const Type = @import("Type.zig");
const Value = @import("Value.zig");
const Zcu = @import("Zcu.zig");
const print = @import("Air/print.zig");
pub const Legalize = @import("Air/Legalize.zig");
pub const Liveness = @import("Air/Liveness.zig");
pub const Print = @import("Air/Print.zig");
pub const Verify = @import("Air/Verify.zig");
instructions: std.MultiArrayList(Inst).Slice,
@@ -2517,10 +2517,10 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index
}
pub const legalize = Legalize.legalize;
pub const write = print.write;
pub const writeInst = print.writeInst;
pub const dump = print.dump;
pub const dumpInst = print.dumpInst;
pub const write = Print.write;
pub const writeInst = Print.writeInst;
pub const dump = Print.dump;
pub const dumpInst = Print.dumpInst;
pub const CoveragePoint = enum(u1) {
/// Indicates the block is not a place of interest corresponding to
+13 -2
View File
@@ -8,9 +8,20 @@ const Value = @import("../Value.zig");
const Type = @import("../Type.zig");
const Air = @import("../Air.zig");
const InternPool = @import("../InternPool.zig");
const Printer = @This();
zcu: *Zcu,
fqn: InternPool.NullTerminatedString,
air: *const Air,
liveness: *const ?Air.Liveness,
pub fn format(p: *const Printer, w: *std.Io.Writer) std.Io.Writer.Error!void {
try w.print("{qf}:\n", .{p.fqn.fmt(&p.zcu.intern_pool)});
try p.air.write(w, p.zcu, p.liveness.*);
}
pub fn write(air: Air, stream: *std.Io.Writer, zcu: *Zcu, liveness: ?Air.Liveness) !void {
comptime assert(build_options.enable_debug_extensions);
comptime assert(build_options.log_level == .debug);
const instruction_bytes = air.instructions.len *
// Here we don't use @sizeOf(Air.Inst.Data) because it would include
// the debug safety tag but we want to measure release size.
@@ -60,7 +71,7 @@ pub fn writeInst(
zcu: *Zcu,
liveness: ?Air.Liveness,
) void {
comptime assert(build_options.enable_debug_extensions);
comptime assert(build_options.log_level == .debug);
var writer: Writer = .{
.zcu = zcu,
.gpa = zcu.comp.gpa,
+28 -84
View File
@@ -20,6 +20,7 @@ const link = @import("link.zig");
const tracy = @import("tracy.zig");
const trace = tracy.trace;
const build_options = @import("build_options");
const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled;
const LibCInstallation = std.zig.LibCInstallation;
const glibc = @import("libs/glibc.zig");
const musl = @import("libs/musl.zig");
@@ -161,12 +162,6 @@ clang_passthrough_mode: bool,
clang_preprocessor_mode: ClangPreprocessorMode,
/// Whether to print clang argvs to stdout.
verbose_cc: bool,
verbose_air: bool,
verbose_intern_pool: bool,
verbose_generic_instances: bool,
verbose_llvm_ir: ?[]const u8,
verbose_llvm_bc: ?[]const u8,
verbose_llvm_cpu_features: bool,
verbose_link: bool,
link_depfile: ?[]const u8,
disable_c_depfile: bool,
@@ -1544,13 +1539,7 @@ pub const CreateOptions = struct {
clang_passthrough_mode: bool = false,
verbose_cc: bool = false,
verbose_link: bool = false,
verbose_air: bool = false,
verbose_intern_pool: bool = false,
verbose_generic_instances: bool = false,
verbose_llvm_ir: ?[]const u8 = null,
verbose_llvm_bc: ?[]const u8 = null,
link_depfile: ?[]const u8 = null,
verbose_llvm_cpu_features: bool = false,
debug_compiler_runtime_libs: ?std.lang.Optimize = null,
debug_compile_errors: bool = false,
debug_incremental: bool = false,
@@ -1932,21 +1921,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod);
}
if (options.verbose_llvm_cpu_features) {
if (options.root_mod.resolved_target.llvm_cpu_features) |cf| {
const stderr = try io.lockStderr(&.{}, null);
defer io.unlockStderr();
const w = &stderr.file_writer.interface;
printVerboseLlvmCpuFeatures(w, arena, options.root_name, target, cf) catch |err| switch (err) {
error.WriteFailed => switch (stderr.file_writer.err.?) {
error.Canceled => |e| return e,
else => {},
},
error.OutOfMemory => |e| return e,
};
}
}
const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
const main_mod = options.main_mod orelse options.root_mod;
@@ -2111,14 +2085,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
.clang_passthrough_mode = options.clang_passthrough_mode,
.clang_preprocessor_mode = options.clang_preprocessor_mode,
.verbose_cc = options.verbose_cc,
.verbose_air = options.verbose_air,
.verbose_intern_pool = options.verbose_intern_pool,
.verbose_generic_instances = options.verbose_generic_instances,
.verbose_llvm_ir = options.verbose_llvm_ir,
.verbose_llvm_bc = options.verbose_llvm_bc,
.link_depfile = options.link_depfile,
.verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
.verbose_link = options.verbose_link,
.link_depfile = options.link_depfile,
.disable_c_depfile = options.disable_c_depfile,
.reference_trace = options.reference_trace,
.time_report = if (options.time_report) .init else null,
@@ -2353,8 +2321,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
comp.emit_asm != null or
comp.emit_llvm_ir != null or
comp.emit_llvm_bc != null or
comp.verbose_llvm_ir != null or
comp.verbose_llvm_bc != null))
log_llvm_ir: {
break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir");
}))
{
if (opt_zcu) |zcu| {
dev.check(.llvm_backend);
@@ -2566,19 +2535,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
return comp;
}
fn printVerboseLlvmCpuFeatures(
w: *Writer,
arena: Allocator,
root_name: []const u8,
target: *const std.Target,
cf: [*:0]const u8,
) (Writer.Error || Allocator.Error)!void {
try w.print("compilation: {s}\n", .{root_name});
try w.print(" target: {s}\n", .{try target.zigTriple(arena)});
try w.print(" cpu: {s}\n", .{target.cpu.model.name});
try w.print(" features: {s}\n", .{cf});
}
pub fn destroy(comp: *Compilation) void {
const gpa = comp.gpa;
const io = comp.io;
@@ -2991,14 +2947,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
try pt.processExports();
}
if (build_options.enable_debug_extensions and comp.verbose_intern_pool) {
std.debug.print("intern pool stats for {q}:\n", .{comp.root_name});
zcu.intern_pool.dump();
}
if (build_options.enable_debug_extensions and comp.verbose_generic_instances) {
std.debug.print("generic instances for '{s}:0x{x}':\n", .{ comp.root_name, @intFromPtr(zcu) });
zcu.intern_pool.dumpGenericInstances(gpa);
{
var d: InternPool.Dump = .{
.name = comp.root_name,
.arena = arena,
.ip = &zcu.intern_pool,
.err = null,
};
std.log.scoped(.@"ip-stats").debug("{f}", .{&d});
if (d.err) |err| return err;
std.log.scoped(.@"ip-values").debug("{f}", .{std.fmt.alt(&d, .formatAll)});
if (d.err) |err| return err;
std.log.scoped(.@"ip-generic-instances").debug("{f}", .{std.fmt.alt(&d, .formatGenericInstances)});
if (d.err) |err| return err;
}
}
@@ -3220,28 +3181,29 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
comp.time_report.?.stats.real_ns_llvm_emit = ns;
};
const zcu_obj_path: ?Cache.Path = if (comp.bin_file != null) p: {
break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename);
} else null;
const zcu_obj_path: ?Cache.Path = switch (comp.getTarget().ofmt) {
.llvmbc, .llvmir => null,
else => if (comp.bin_file != null)
try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename)
else
null,
};
const active = zcu.activate(tid);
defer active.deactivate();
llvm_object.emit(active.pt, .{
.pre_ir_path = comp.verbose_llvm_ir,
.pre_bc_path = comp.verbose_llvm_bc,
.bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null,
.asm_path = p: {
const raw = comp.emit_asm orelse break :p null;
const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
break :p try p.toStringZ(arena);
},
.post_ir_path = p: {
.opt_ir_path = p: {
const raw = comp.emit_llvm_ir orelse break :p null;
const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
break :p try p.toStringZ(arena);
},
.post_bc_path = p: {
.opt_bc_path = p: {
const raw = comp.emit_llvm_bc orelse break :p null;
const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
break :p try p.toStringZ(arena);
@@ -3267,7 +3229,7 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
error.Canceled, error.OutOfMemory => |e| return e,
error.AlreadyReported => return,
};
}
} else return;
}
}
if (comp.bin_file) |lf| {
@@ -4903,12 +4865,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
.emit_bin = .yes_cache,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_intern_pool = comp.verbose_intern_pool,
.verbose_generic_instances = comp.verbose_intern_pool,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.environ_map = comp.environ_map,
}) catch |err| switch (err) {
error.CreateFail => {
@@ -7415,12 +7371,6 @@ fn buildOutputFromZig(
.data_sections = true,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_intern_pool = comp.verbose_intern_pool,
.verbose_generic_instances = comp.verbose_intern_pool,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
.environ_map = comp.environ_map,
@@ -7552,12 +7502,6 @@ pub fn build_crt_file(
.c_source_files = c_source_files,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_intern_pool = comp.verbose_intern_pool,
.verbose_generic_instances = comp.verbose_generic_instances,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
.environ_map = comp.environ_map,
+4 -4
View File
@@ -190,7 +190,7 @@ pub fn resolve(options: Options) ResolveError!Config {
// *If* the LLVM backend were to be selected, should Zig use the LLVM
// library to build the LLVM module?
const use_lib_llvm = b: {
if (!build_options.have_llvm) {
if (!build_options.have_llvm or target.ofmt == .llvmbc or target.ofmt == .llvmir) {
if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;
break :b false;
}
@@ -324,7 +324,7 @@ pub fn resolve(options: Options) ResolveError!Config {
if (!options.have_zcu) break :b false;
// If emitting to LLVM bitcode object format, must use LLVM backend.
if (options.emit_llvm_ir or options.emit_llvm_bc) {
if (target.ofmt == .llvmbc or target.ofmt == .llvmir or options.emit_llvm_bc or options.emit_llvm_ir) {
if (options.use_llvm == false)
return error.EmittingLlvmModuleRequiresLlvmBackend;
if (!target_util.hasLlvmSupport(target, target.ofmt))
@@ -379,7 +379,7 @@ pub fn resolve(options: Options) ResolveError!Config {
const backend = target_util.zigBackend(target, use_llvm);
if (options.emit_bin and options.have_zcu) {
if (!use_lib_llvm and use_llvm) {
if (target.ofmt != .llvmbc and target.ofmt != .llvmir and !use_lib_llvm and use_llvm) {
// Explicit request to use LLVM to produce an object file, but without
// using LLVM libraries. Impossible.
return error.EmittingBinaryRequiresLlvmLibrary;
@@ -513,7 +513,7 @@ pub fn resolve(options: Options) ResolveError!Config {
break :b switch (target.ofmt) {
.elf, .macho, .wasm => .{ .dwarf = .@"32" },
.coff => .code_view,
.c => switch (target.os.tag) {
.c, .llvmbc, .llvmir => switch (target.os.tag) {
.windows, .uefi => .code_view,
else => .{ .dwarf = .@"32" },
},
+32 -24
View File
@@ -10591,17 +10591,36 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index {
return ip.indexToKey(ty).error_union_type.payload_type;
}
pub fn dump(ip: *const InternPool) void {
var buffer: [4096]u8 = undefined;
const stderr = std.debug.lockStderr(&buffer);
defer std.debug.unlockStderr();
const w = &stderr.file_writer.interface;
dumpDependencyStatsFallible(ip, w) catch return;
dumpStatsFallible(ip, w, std.heap.page_allocator) catch return;
dumpAllFallible(ip, w) catch return;
pub const Dump = struct {
name: []const u8,
arena: std.mem.Allocator,
ip: *const InternPool,
err: ?Allocator.Error,
pub fn format(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
try w.print("{q}:\n", .{d.name});
try d.ip.dumpDependencyStatsFallible(w);
d.ip.dumpStatsFallible(d.arena, w) catch |err| switch (err) {
error.WriteFailed => |e| return e,
error.OutOfMemory => |e| {
d.err = e;
return error.WriteFailed;
},
};
}
fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {
pub fn formatAll(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
try w.print("{q}:\n", .{d.name});
try d.ip.dumpAllFallible(w);
}
pub fn formatGenericInstances(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
try w.print("{q}:\n", .{d.name});
d.ip.dumpGenericInstancesFallible(d.arena, w) catch return;
}
};
fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void {
const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len;
const src_hash_deps_len = ip.src_hash_deps.count();
const nav_val_deps_len = ip.nav_val_deps.count();
@@ -10668,7 +10687,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {
});
}
fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void {
fn dumpStatsFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) (Allocator.Error || Io.Writer.Error)!void {
var items_len: usize = 0;
var extra_len: usize = 0;
var limbs_len: usize = 0;
@@ -10968,7 +10987,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
}
}
fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void {
for (ip.locals, 0..) |*local, tid| {
// Early check for length 0, because `view()` is invalid if capacity is 0
if (local.mutate.items.len == 0) continue;
@@ -11071,21 +11090,10 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
}
}
pub fn dumpGenericInstances(ip: *const InternPool, allocator: Allocator) void {
var buffer: [4096]u8 = undefined;
const stderr = std.debug.lockStderr(&buffer);
defer std.debug.unlockStderr();
const w = &stderr.file_writer.interface;
ip.dumpGenericInstancesFallible(allocator, w) catch return;
}
pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator, w: *Io.Writer) !void {
var arena_allocator = std.heap.ArenaAllocator.init(allocator);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
pub fn dumpGenericInstancesFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) !void {
var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty;
for (ip.locals, 0..) |*local, tid| {
if (local.mutate.items.len == 0) continue;
const items = local.shared.items.view().slice();
const extra_list = local.shared.extra;
for (
+9 -12
View File
@@ -26,6 +26,7 @@ fully_qualified_name: []const u8,
deps: Deps = .{},
resolved_target: ResolvedTarget,
llvm_cpu_features: ?[:0]const u8,
optimize_mode: std.lang.Optimize,
code_model: std.lang.CodeModel,
single_threaded: bool,
@@ -94,7 +95,6 @@ pub const ResolvedTarget = struct {
is_native_os: bool,
is_native_abi: bool,
is_explicit_dynamic_linker: bool,
llvm_cpu_features: ?[*:0]const u8 = null,
};
pub const CreateError = error{
@@ -362,15 +362,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
break :b 0;
};
const llvm_cpu_features: ?[*:0]const u8 = b: {
if (resolved_target.llvm_cpu_features) |x| break :b x;
const llvm_cpu_features: ?[:0]const u8 = b: {
if (!options.global.use_llvm) break :b null;
var buf = std.array_list.Managed(u8).init(arena);
var disabled_features = std.array_list.Managed(u8).init(arena);
defer disabled_features.deinit();
if (options.inherited.resolved_target == null) break :b options.parent.?.llvm_cpu_features;
// Append disabled features after enabled ones, so that their effects aren't overwritten.
var buf = std.array_list.Managed(u8).init(arena);
var disabled_features = std.array_list.Managed(u8).init(arena);
for (target.cpu.arch.allFeaturesList()) |feature| {
if (feature.llvm_name) |llvm_name| {
// Ignore these until we figure out how to handle the concept of omitting features.
@@ -401,10 +399,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
try buf.appendSlice(disabled_features.items);
if (buf.items.len == 0) break :b "";
assert(std.mem.endsWith(u8, buf.items, ","));
assert(buf.items[buf.items.len - 1] == ',');
buf.items[buf.items.len - 1] = 0;
buf.shrinkAndFree(buf.items.len);
break :b buf.items[0 .. buf.items.len - 1 :0].ptr;
break :b buf.items[0 .. buf.items.len - 1 :0];
};
const mod = try arena.create(Module);
@@ -417,8 +414,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
.is_native_os = resolved_target.is_native_os,
.is_native_abi = resolved_target.is_native_abi,
.is_explicit_dynamic_linker = resolved_target.is_explicit_dynamic_linker,
.llvm_cpu_features = llvm_cpu_features,
},
.llvm_cpu_features = llvm_cpu_features,
.optimize_mode = optimize_mode,
.single_threaded = single_threaded,
.error_tracing = error_tracing,
@@ -494,8 +491,8 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories)
.is_native_os = false,
.is_native_abi = false,
.is_explicit_dynamic_linker = false,
.llvm_cpu_features = null,
},
.llvm_cpu_features = null,
.optimize_mode = opts.optimize_mode,
.single_threaded = opts.single_threaded,
.error_tracing = opts.error_tracing,
+2 -4
View File
@@ -1126,6 +1126,8 @@ fn analyzeBodyInner(
crash_info.push(sema, block, body);
defer crash_info.pop();
const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path;
// We use a while (true) loop here to avoid a redundant way of breaking out of
// the loop. The only way to break out of the loop is with a `noreturn`
// instruction.
@@ -1134,11 +1136,7 @@ fn analyzeBodyInner(
crash_info.setBodyIndex(i);
const inst = body[i];
// This log is a bit expensive, and LLVM fails to optimize it away.
if (build_options.enable_logging) {
const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path;
std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst });
}
const air_ref: Air.Inst.Ref = inst: switch (tags[@backingInt(inst)]) {
// zig fmt: off
+21 -39
View File
@@ -25,6 +25,7 @@ const InternPool = @import("../InternPool.zig");
const AnalUnit = InternPool.AnalUnit;
const Module = @import("../Module.zig");
const Sema = @import("../Sema.zig");
const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled;
const target_util = @import("../target.zig");
const tracy = @import("../tracy.zig");
const trace = tracy.trace;
@@ -2303,10 +2304,9 @@ fn analyzeFuncBody(
const comp = zcu.comp;
const dump_air = build_options.enable_debug_extensions and comp.verbose_air;
const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
if (comp.bin_file != null or zcu.llvm_object != null or dump_air or dump_llvm_ir) {
if (comp.bin_file != null or zcu.llvm_object != null or log_air: {
break :log_air debugLogScopeEnabled("illegal-air") or debugLogScopeEnabled("legal-air") or debugLogScopeEnabled("air");
}) {
zcu.codegen_prog_node.increaseEstimatedTotalItems(1);
comp.link_prog_node.increaseEstimatedTotalItems(1);
@@ -4522,32 +4522,28 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
tracy_trace.addText(fqn.toSlice(ip));
tracy_trace.addTextFmt("func_ip_index={d}", .{func_index});
Air.Verify.run(pt, func_index, air);
if (codegen.legalizeFeatures(pt, nav)) |features| {
try air.legalize(pt, features);
// Verify the AIR again post-legalization.
Air.Verify.run(pt, func_index, air);
}
var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav))
try .analyze(zcu, air.*, ip)
else
null;
var liveness: ?Air.Liveness = null;
defer if (liveness) |*l| l.deinit(gpa);
if (build_options.enable_debug_extensions and comp.verbose_air) p: {
const io = comp.io;
const stderr = try io.lockStderr(&.{}, null);
defer io.unlockStderr();
printVerboseAir(pt, liveness, fqn, air, &stderr.file_writer.interface) catch |err| switch (err) {
error.WriteFailed => switch (stderr.file_writer.err.?) {
error.Canceled => |e| return e,
else => break :p,
},
const ap: Air.Print = .{
.zcu = zcu,
.fqn = fqn,
.air = air,
.liveness = &liveness,
};
std.log.scoped(.@"illegal-air").debug("{f}", .{&ap});
if (codegen.legalizeFeatures(pt, nav)) |features| {
// Verify the AIR again pre-legalization.
Air.Verify.run(pt, func_index, air);
try air.legalize(pt, features);
}
std.log.scoped(.@"legal-air").debug("{f}", .{&ap});
Air.Verify.run(pt, func_index, air);
if (codegen.wantsLiveness(pt, nav)) liveness = try .analyze(zcu, air.*, ip);
std.log.scoped(.air).debug("{f}", .{&ap});
if (std.debug.runtime_safety) verify_liveness: {
var verify: Air.Liveness.Verify = .{
.gpa = gpa,
@@ -4577,17 +4573,3 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
return codegen.generateFunction(lf, pt, func_index, air, &liveness);
}
fn printVerboseAir(
pt: Zcu.PerThread,
liveness: ?Air.Liveness,
fqn: InternPool.NullTerminatedString,
air: *const Air,
w: *Io.Writer,
) Io.Writer.Error!void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
try w.print("# Begin Function AIR: {f}:\n", .{fqn.fmt(ip)});
try air.write(w, zcu, liveness);
try w.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)});
}
+65 -58
View File
@@ -10,6 +10,7 @@ const build_options = @import("build_options");
const Air = @import("../Air.zig");
const codegen = @import("../codegen.zig");
const Compilation = @import("../Compilation.zig");
const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled;
const InternPool = @import("../InternPool.zig");
const link = @import("../link.zig");
const Module = @import("../Module.zig");
@@ -331,12 +332,10 @@ pub const Object = struct {
}
pub const EmitOptions = struct {
pre_ir_path: ?[]const u8,
pre_bc_path: ?[]const u8,
bin_path: ?[:0]const u8,
asm_path: ?[:0]const u8,
post_ir_path: ?[:0]const u8,
post_bc_path: ?[:0]const u8,
opt_ir_path: ?[:0]const u8,
opt_bc_path: ?[:0]const u8,
is_debug: bool,
is_small: bool,
@@ -351,6 +350,7 @@ pub const Object = struct {
const comp = zcu.comp;
const io = comp.io;
const diags = &comp.link_diags;
const target = &comp.root_mod.resolved_target.result;
{
if (o.errors_len_variable != .none) {
@@ -403,7 +403,7 @@ pub const Object = struct {
const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7));
const behavior_min = try o.builder.metadataConstant(try o.builder.intConst(.i32, 8));
if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |abi| {
if (target_util.llvmMachineAbi(target)) |abi| {
module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
behavior_error,
(try o.builder.metadataString("target-abi")).toMetadata(),
@@ -411,7 +411,7 @@ pub const Object = struct {
}));
}
const pic_level = target_util.picLevel(&comp.root_mod.resolved_target.result);
const pic_level = target_util.picLevel(target);
if (comp.root_mod.pic) {
module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
behavior_min,
@@ -434,7 +434,7 @@ pub const Object = struct {
(try o.builder.metadataString("Code Model")).toMetadata(),
try o.builder.metadataConstant(try o.builder.intConst(.i32, @as(
i32,
switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {
switch (codeModel(comp.root_mod.code_model, target)) {
.default => unreachable,
.tiny => 0,
.small => 1,
@@ -480,7 +480,6 @@ pub const Object = struct {
}
}
const target = &comp.root_mod.resolved_target.result;
if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) {
// Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall
// v4, which is essentially a requirement on Windows. See corresponding logic in
@@ -515,21 +514,26 @@ pub const Object = struct {
const emit_asm_msg = options.asm_path orelse "(none)";
const emit_bin_msg = options.bin_path orelse "(none)";
const post_llvm_ir_msg = options.post_ir_path orelse "(none)";
const post_llvm_bc_msg = options.post_bc_path orelse "(none)";
const opt_llvm_ir_msg = options.opt_ir_path orelse "(none)";
const opt_llvm_bc_msg = options.opt_bc_path orelse "(none)";
log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{
emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg,
emit_asm_msg, emit_bin_msg, opt_llvm_ir_msg, opt_llvm_bc_msg,
});
const log_opt_llvm_ir = debugLogScopeEnabled("opt-llvm-ir");
const context, const module = emit: {
if (options.pre_ir_path) |path| {
if (std.mem.eql(u8, path, "-")) {
o.builder.dump(io);
} else {
o.builder.printToFilePath(io, Io.Dir.cwd(), path) catch |err| {
log.err("failed printing LLVM module to \"{s}\": {t}", .{ path, err });
};
{
var p: Builder.Print = .{ .name = comp.root_name, .builder = &o.builder, .err = null };
std.log.scoped(.@"llvm-ir").debug("{f}", .{&p});
if (p.err) |err| return err;
}
if (target.ofmt == .llvmir) {
const path = comp.bin_file.?.emit;
o.builder.printToFilePath(io, path.root_dir.handle, path.sub_path) catch |err| {
return diags.fail("failed emitting LLVM module to {qf}: {t}", .{ path, err });
};
return;
}
const bitcode = try o.builder.toBitcode(o.gpa, .{
@@ -538,23 +542,26 @@ pub const Object = struct {
});
defer o.gpa.free(bitcode);
if (options.pre_bc_path) |path| {
var file = Io.Dir.cwd().createFile(io, path, .{}) catch |err|
return diags.fail("failed to create '{s}': {t}", .{ path, err });
if (target.ofmt == .llvmbc) {
const path = comp.bin_file.?.emit;
var file = path.root_dir.handle.createFile(io, path.sub_path, .{}) catch |err|
return diags.fail("failed to create {qf}: {t}", .{ path, err });
defer file.close(io);
file.writeStreamingAll(io, @ptrCast(bitcode)) catch |err|
return diags.fail("failed to write to '{s}': {t}", .{ path, err });
return diags.fail("failed to write to {qf}: {t}", .{ path, err });
return;
}
if (options.asm_path == null and options.bin_path == null and
options.post_ir_path == null and options.post_bc_path == null) return;
options.opt_ir_path == null and options.opt_bc_path == null and
!log_opt_llvm_ir) return;
if (!build_options.have_llvm or !comp.config.use_lib_llvm) {
return diags.fail("emitting without libllvm not implemented", .{});
}
initializeLLVMTarget(io, comp.root_mod.resolved_target.result.cpu.arch);
initializeLLVMTarget(io, target.cpu.arch);
const context: *bindings.Context = .create();
errdefer context.dispose();
@@ -577,9 +584,9 @@ pub const Object = struct {
};
defer context.dispose();
var target: *bindings.Target = undefined;
var llvm_target: *bindings.Target = undefined;
var error_message: [*:0]const u8 = undefined;
if (bindings.Target.getFromTriple(target_triple_sentinel, &target, &error_message).toBool()) {
if (bindings.Target.getFromTriple(target_triple_sentinel, &llvm_target, &error_message).toBool()) {
defer bindings.disposeMessage(error_message);
return diags.fail("LLVM failed to parse '{s}': {s}", .{ target_triple_sentinel, error_message });
}
@@ -598,7 +605,7 @@ pub const Object = struct {
else
.Static;
const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {
const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, target)) {
.default => .Default,
.tiny => .Tiny,
.small => .Small,
@@ -607,24 +614,22 @@ pub const Object = struct {
.large => .Large,
};
const float_abi: bindings.TargetMachine.FloatABI = if (comp.root_mod.resolved_target.result.abi.float() == .hard)
.Hard
else
.Soft;
var target_machine = bindings.TargetMachine.create(
target,
llvm_target,
target_triple_sentinel,
if (comp.root_mod.resolved_target.result.cpu.model.llvm_name) |s| s.ptr else null,
comp.root_mod.resolved_target.llvm_cpu_features.?,
if (target.cpu.model.llvm_name) |s| s.ptr else null,
comp.root_mod.llvm_cpu_features.?,
opt_level,
reloc_mode,
code_model,
comp.function_sections,
comp.data_sections,
float_abi,
if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |s| s.ptr else null,
target_util.useEmulatedTls(&comp.root_mod.resolved_target.result),
switch (target.abi.float()) {
.hard => .Hard,
.soft => .Soft,
},
if (target_util.llvmMachineAbi(target)) |s| s.ptr else null,
target_util.useEmulatedTls(target),
);
errdefer target_machine.dispose();
@@ -634,7 +639,10 @@ pub const Object = struct {
// Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
// So we call the entire pipeline multiple times if this is requested.
// var error_message: [*:0]const u8 = undefined;
var time_report_c_str: ?[*:0]u8 = null;
defer if (time_report_c_str) |time_report| bindings.disposeMessage(time_report);
var llvm_ir_c_str: ?[*:0]u8 = null;
defer if (llvm_ir_c_str) |llvm_ir| bindings.disposeMessage(llvm_ir);
var lowered_options: bindings.TargetMachine.EmitOptions = .{
.is_debug = options.is_debug,
.is_small = options.is_small,
@@ -648,11 +656,12 @@ pub const Object = struct {
.allow_fast_isel = true,
// LLVM's RISC-V backend for some reason enables the machine outliner by default even
// though it's clearly not ready and produces multiple miscompilations in our std tests.
.allow_machine_outliner = !comp.root_mod.resolved_target.result.cpu.arch.isRISCV(),
.allow_machine_outliner = !target.cpu.arch.isRISCV(),
.asm_filename = null,
.bin_filename = if (options.bin_path) |x| x.ptr else null,
.llvm_ir_filename = if (options.post_ir_path) |x| x.ptr else null,
.bitcode_filename = if (options.post_bc_path) |x| x.ptr else null,
.llvm_ir_filename = if (options.opt_ir_path) |x| x.ptr else null,
.bitcode_filename = if (options.opt_bc_path) |x| x.ptr else null,
.llvm_ir_out = if (log_opt_llvm_ir) &llvm_ir_c_str else null,
// `.coverage` value is only used when `.sancov` is enabled.
.sancov = options.fuzz or comp.config.san_cov_trace_pc_guard,
@@ -684,33 +693,31 @@ pub const Object = struct {
};
if (options.asm_path != null and options.bin_path != null) {
if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
defer bindings.disposeMessage(error_message);
return diags.fail("LLVM failed to emit bin={s} ir={s}: {s}", .{
emit_bin_msg, post_llvm_ir_msg, error_message,
emit_bin_msg, opt_llvm_ir_msg, error_message,
});
}
lowered_options.bin_filename = null;
lowered_options.llvm_ir_filename = null;
lowered_options.bitcode_filename = null;
lowered_options.llvm_ir_out = null;
}
var time_report_c_str: [*:0]u8 = undefined;
if (options.time_report != null) {
lowered_options.time_report_out = &time_report_c_str;
}
if (options.time_report) |_| lowered_options.time_report_out = &time_report_c_str;
lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null;
if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
defer bindings.disposeMessage(error_message);
return diags.fail("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{
emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg, error_message,
emit_asm_msg, emit_bin_msg, opt_llvm_ir_msg, opt_llvm_bc_msg, error_message,
});
}
if (options.time_report) |tr| {
defer std.c.free(time_report_c_str);
const time_report_data = std.mem.span(time_report_c_str);
assert(tr.llvm_pass_timings.len == 0);
tr.llvm_pass_timings = try comp.gpa.dupe(u8, time_report_data);
if (log_opt_llvm_ir) std.log.scoped(.@"opt-llvm-ir").debug("{s}", .{
llvm_ir_c_str orelse return error.OutOfMemory,
});
if (options.time_report) |time_report| {
assert(time_report.llvm_pass_timings.len == 0);
time_report.llvm_pass_timings = try comp.gpa.dupe(u8, std.mem.span(
time_report_c_str orelse return error.OutOfMemory,
));
}
}
@@ -2184,10 +2191,10 @@ pub const Object = struct {
.value = try o.builder.string(s),
} }, &o.builder);
}
if (owner_mod.resolved_target.llvm_cpu_features) |s| {
if (owner_mod.llvm_cpu_features) |s| {
try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("target-features"),
.value = try o.builder.string(std.mem.span(s)),
.value = try o.builder.string(s),
} }, &o.builder);
}
+3 -2
View File
@@ -51,7 +51,7 @@ pub const Module = opaque {
};
pub const disposeMessage = LLVMDisposeMessage;
extern fn LLVMDisposeMessage(Message: [*:0]const u8) void;
extern fn LLVMDisposeMessage(Message: ?[*:0]const u8) void;
pub const TargetMachine = opaque {
pub const FloatABI = enum(c_int) {
@@ -85,7 +85,7 @@ pub const TargetMachine = opaque {
pub const EmitOptions = extern struct {
is_debug: bool,
is_small: bool,
time_report_out: ?*[*:0]u8,
time_report_out: ?*?[*:0]u8,
tsan: bool,
sancov: bool,
lto: LtoPhase,
@@ -95,6 +95,7 @@ pub const TargetMachine = opaque {
bin_filename: ?[*:0]const u8,
llvm_ir_filename: ?[*:0]const u8,
bitcode_filename: ?[*:0]const u8,
llvm_ir_out: ?*?[*:0]u8,
coverage: Coverage,
pub const LtoPhase = enum(c_int) {
+1 -1
View File
@@ -27,7 +27,7 @@ const Target = std.Target;
const log = std.log.scoped(.riscv_codegen);
const tracking_log = std.log.scoped(.tracking);
const verbose_tracking_log = std.log.scoped(.verbose_tracking);
const wip_mir_log = std.log.scoped(.wip_mir);
const wip_mir_log = std.log.scoped(.@"wip-mir");
const Alignment = InternPool.Alignment;
const bits = @import("bits.zig");
+1 -1
View File
@@ -5,7 +5,7 @@ const link = @import("../../link.zig");
const log = std.log.scoped(.codegen);
const tracking_log = std.log.scoped(.tracking);
const verbose_tracking_log = std.log.scoped(.verbose_tracking);
const wip_mir_log = std.log.scoped(.wip_mir);
const wip_mir_log = std.log.scoped(.@"wip-mir");
const Writer = std.Io.Writer;
const Air = @import("../../Air.zig");
+2
View File
@@ -112,6 +112,7 @@ pub const Env = enum {
.loongarch_backend,
.spork8_backend,
.lld_linker,
.llvm_linker,
.coff_linker,
.elf_linker,
.elf2_linker,
@@ -333,6 +334,7 @@ pub const Feature = enum {
spork8_backend,
lld_linker,
llvm_linker,
coff_linker,
elf_linker,
elf2_linker,
-4
View File
@@ -1120,10 +1120,6 @@ fn buildSharedLib(
.emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.version = version,
.version_script = .{
-4
View File
@@ -1268,10 +1268,6 @@ fn buildSharedLib(
.emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.version = version,
.version_script = .{
-8
View File
@@ -260,10 +260,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
.c_source_files = c_source_files.items,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
.environ_map = comp.environ_map,
@@ -445,10 +441,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
.c_source_files = c_source_files.items,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
.environ_map = comp.environ_map,
-4
View File
@@ -295,10 +295,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
.c_source_files = c_source_files.items,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = skip_linker_dependencies,
.linker_allow_shlib_undefined = linker_allow_shlib_undefined,
-4
View File
@@ -157,10 +157,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
.c_source_files = &c_source_files,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
.environ_map = comp.environ_map,
-3
View File
@@ -246,9 +246,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
.emit_bin = .yes_cache,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.c_source_files = &.{
.{
-4
View File
@@ -771,10 +771,6 @@ fn buildSharedLib(
.emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.version = version,
.soname = soname,
-4
View File
@@ -691,10 +691,6 @@ fn buildSharedLib(
.emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.verbose_link,
.verbose_air = comp.verbose_air,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.soname = soname,
.c_source_files = &c_source_files,
+35 -4
View File
@@ -550,6 +550,7 @@ pub const File = struct {
return &ptr.base;
},
.lld => unreachable, // not known from ofmt
.llvm => |tag| return createDummy(arena, tag, comp, emit),
}
}
@@ -573,9 +574,26 @@ pub const File = struct {
return &ptr.base;
},
.lld => unreachable, // not known from ofmt
.llvm => |tag| return createDummy(arena, tag, comp, emit),
}
}
fn createDummy(arena: Allocator, tag: Tag, comp: *Compilation, path: Path) Allocator.Error!*File {
const base = try arena.create(File);
base.* = .{
.tag = tag,
.comp = comp,
.emit = path,
.file = null,
.gc_sections = false,
.print_gc_sections = false,
.build_id = .none,
.allow_shlib_undefined = false,
.stack_size = 0,
};
return base;
}
pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn {
return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;
}
@@ -606,7 +624,7 @@ pub const File = struct {
const gpa = comp.gpa;
const io = comp.io;
switch (base.tag) {
.lld => assert(base.file == null),
.lld, .llvm => assert(base.file == null),
.elf, .macho, .wasm => {
dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });
if (base.file != null) return;
@@ -706,7 +724,7 @@ pub const File = struct {
if (!base.canMakeExecutable())
return;
switch (base.tag) {
.lld => assert(base.file == null),
.lld, .llvm => assert(base.file == null),
.elf => if (base.file) |f| {
dev.check(.elf_linker);
f.close(io);
@@ -827,6 +845,7 @@ pub const File = struct {
switch (base.tag) {
.lld => unreachable,
.llvm => unreachable,
.plan9 => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
@@ -862,6 +881,7 @@ pub const File = struct {
assert(pt.zcu.llvm_object == null);
switch (base.tag) {
.lld => unreachable,
.llvm => unreachable,
.plan9 => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
@@ -897,6 +917,7 @@ pub const File = struct {
}
switch (base.tag) {
.lld => unreachable,
.llvm => unreachable,
.plan9 => unreachable,
.spirv => {},
.coff => {},
@@ -941,6 +962,7 @@ pub const File = struct {
base.releaseLock();
if (base.file) |f| f.close(io);
switch (base.tag) {
.llvm => {},
.plan9 => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
@@ -1003,6 +1025,7 @@ pub const File = struct {
}
assert(base.post_prelink);
switch (base.tag) {
.llvm => {},
.plan9 => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
@@ -1030,6 +1053,7 @@ pub const File = struct {
switch (base.tag) {
.lld => unreachable,
.llvm => unreachable,
.plan9 => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
@@ -1056,6 +1080,7 @@ pub const File = struct {
assert(base.comp.zcu.?.llvm_object == null);
switch (base.tag) {
.lld => unreachable,
.llvm => unreachable,
.c => unreachable,
.spirv => unreachable,
.wasm => unreachable,
@@ -1078,6 +1103,7 @@ pub const File = struct {
assert(pt.zcu.llvm_object == null);
switch (base.tag) {
.lld => unreachable,
.llvm => unreachable,
.c => unreachable,
.spirv => unreachable,
.wasm => unreachable,
@@ -1095,6 +1121,7 @@ pub const File = struct {
assert(base.comp.zcu.?.llvm_object == null);
switch (base.tag) {
.lld => unreachable,
.llvm => unreachable,
.c => unreachable,
.spirv => unreachable,
.wasm => unreachable,
@@ -1124,6 +1151,7 @@ pub const File = struct {
.spirv,
.plan9,
.lld,
.llvm,
.spork8,
=> return .unimplemented,
inline else => |tag| {
@@ -1240,7 +1268,7 @@ pub const File = struct {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
},
.c, .spork8, .plan9, .lld => {},
.c, .spork8, .plan9, .lld, .llvm => {},
}
}
@@ -1352,6 +1380,7 @@ pub const File = struct {
coff,
elf,
elf2,
llvm,
macho,
macho2,
c,
@@ -1366,13 +1395,14 @@ pub const File = struct {
.coff => Coff,
.elf => Elf,
.elf2 => Elf2,
.llvm => File,
.macho => MachO,
.macho2 => MachO2,
.c => C,
.wasm => Wasm,
.spirv => Spirv,
.lld => Lld,
.plan9 => comptime unreachable,
.plan9 => unreachable,
.spork8 => Spork8,
};
}
@@ -1381,6 +1411,7 @@ pub const File = struct {
return switch (ofmt) {
.coff => .coff,
.elf => if (use_new_linker) .elf2 else .elf,
.llvmbc, .llvmir => .llvm,
.macho => if (use_new_linker) .macho2 else .macho,
.wasm => .wasm,
.plan9 => .plan9,
-2
View File
@@ -860,9 +860,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
// Dump the state for easy debugging.
// State can be dumped via `--debug-log link_state`.
if (build_options.enable_logging) {
state_log.debug("{f}", .{self.dumpState()});
}
// Beyond this point, everything has been allocated a virtual address and we can resolve
// the relocations, and commit objects to file.
+1 -1
View File
@@ -291,7 +291,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
}
if (build_options.enable_logging) {
if (build_options.enable_debug_extensions) {
const active = elf_file.base.comp.zcu.?.activate(tid);
defer active.deactivate();
for (self.navs.keys(), self.navs.values()) |nav_index, meta| {
+1 -1
View File
@@ -98,7 +98,7 @@ fn markAtom(atom: *Atom) bool {
}
fn markLive(atom: *Atom, elf_file: *Elf) void {
if (@import("build_options").enable_logging) track_live_level.incr();
if (@import("build_options").enable_debug_extensions) track_live_level.incr();
assert(atom.visited);
const file = atom.file(elf_file).?;
-6
View File
@@ -51,9 +51,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
try allocateAllocSections(elf_file);
try elf_file.allocateNonAllocSections();
if (build_options.enable_logging) {
state_log.debug("{f}", .{elf_file.dumpState()});
}
try elf_file.writeMergeSections();
try writeSyntheticSections(elf_file);
@@ -117,10 +115,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
break :blk pos;
};
if (build_options.enable_logging) {
state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)});
state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
}
const buffer = try gpa.alloc(u8, total_size);
defer gpa.free(buffer);
@@ -193,9 +189,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void {
try allocateAllocSections(elf_file);
try elf_file.allocateNonAllocSections();
if (build_options.enable_logging) {
state_log.debug("{f}", .{elf_file.dumpState()});
}
try writeAtoms(elf_file);
try elf_file.writeMergeSections();
-2
View File
@@ -456,9 +456,7 @@ pub fn flush(
self.allocateSegments();
self.allocateSyntheticSymbols();
if (build_options.enable_logging) {
state_log.debug("{f}", .{self.dumpState()});
}
// Beyond this point, everything has been allocated a virtual address and we can resolve
// the relocations, and commit objects to file.
+2 -1
View File
@@ -123,8 +123,9 @@ fn markLive(atom: *Atom, macho_file: *MachO) void {
atom.getName(macho_file),
});
if (build_options.enable_logging)
if (build_options.enable_debug_extensions) {
track_live_level.incr();
}
for (atom.getRelocs(macho_file)) |rel| {
const target_atom = switch (rel.tag) {
-6
View File
@@ -61,9 +61,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation) link.Error!void {
};
allocateSegment(macho_file);
if (build_options.enable_logging) {
state_log.debug("{f}", .{macho_file.dumpState()});
}
try writeSections(macho_file);
sortRelocs(macho_file);
@@ -107,9 +105,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
return diags.fail("failed to allocate sections: {s}", .{@errorName(err)});
allocateSegment(macho_file);
if (build_options.enable_logging) {
state_log.debug("{f}", .{macho_file.dumpState()});
}
try writeSections(macho_file);
sortRelocs(macho_file);
@@ -185,9 +181,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
break :blk pos;
};
if (build_options.enable_logging) {
state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
}
const buffer = try gpa.alloc(u8, total_size);
defer gpa.free(buffer);
+40 -74
View File
@@ -42,11 +42,8 @@ const thread_stack_size = 60 << 20;
pub const std_options: std.Options = .{
.logFn = log,
.log_level = switch (builtin.mode) {
.debug => .debug,
.safe, .fast => .info,
.small => .err,
.log_level = switch (build_options.log_level) {
inline else => |log_level| @field(std.log.Level, @tagName(log_level)),
},
};
pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;
@@ -104,7 +101,7 @@ const normal_usage =
\\ help Print this help and exit
\\ cache-cat Print a zig-cache manifest file as zon
\\ std View standard library documentation in a browser
\\ libc Display native libc paths file or validate one
\\ libc Print native libc paths file or validate one
\\ targets List available compilation targets
\\ version Print version number and exit
\\ zen Print Zen of Zig and exit
@@ -126,7 +123,15 @@ const debug_usage = normal_usage ++
const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage;
var log_scopes: std.ArrayList([]const u8) = .empty;
var log_scopes: std.array_hash_map.String(void) = .empty;
pub fn debugLogScopeEnabled(scope: []const u8) bool {
switch (build_options.log_level) {
else => {},
.debug => if (log_scopes.contains(scope)) return true,
}
return false;
}
pub fn log(
comptime level: std.log.Level,
@@ -135,18 +140,11 @@ pub fn log(
args: anytype,
) void {
// Hide debug messages unless:
// * logging enabled with `-Dlog`.
// * logging enabled with `-Ddebug-extensions` or `-Dlog=debug`.
// * the --debug-log arg for the scope has been provided
if (@backingInt(level) > @backingInt(std.options.log_level) or
@backingInt(level) > @backingInt(std.log.Level.info))
{
if (!build_options.enable_logging) return;
const scope_name = @tagName(scope);
for (log_scopes.items) |log_scope| {
if (mem.eql(u8, log_scope, scope_name))
break;
} else return;
switch (level) {
else => {},
.debug => if (!debugLogScopeEnabled(@tagName(scope))) return,
}
// Otherwise, use the default implementation.
@@ -557,11 +555,14 @@ const compile_usage =
\\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation
\\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
\\ -fno-emit-implib Do not produce an import .lib when building a Windows DLL
\\ --show-builtin Output the source of @import("builtin") then exit
\\ --cache-dir [path] Override the local cache directory
\\ --global-cache-dir [path] Override the global cache directory
\\ --zig-lib-dir [path] Override path to Zig installation lib directory
\\ --build-root [path] Override path to project source files
\\ --show-builtin Output the source of @import("builtin") then exit
\\ --time-report Send timing diagnostics to '--listen' clients
\\ --verbose-cc Print C compiler commands before executing them
\\ --verbose-link Print linker commands before executing them
\\
\\Global Compile Options:
\\ --name [name] Compilation unit name (not a file path)
@@ -593,7 +594,6 @@ const compile_usage =
\\ -fpatchable-function-entry=[num] Add num NOPs of padding in function prologues
\\ -mexec-model=[value] (WASI) Execution model
\\ -municode (Windows) Use wmain/wWinMain as entry point
\\ --time-report Send timing diagnostics to '--listen' clients
\\
\\Per-Module Compile Options:
\\ --dep [[import=]name] Add an entry to the next module's import table
@@ -604,13 +604,15 @@ const compile_usage =
\\ safe Enable both safety checks and machine code optimizations
\\ small Prioritize small binary size. Safety checks off.
\\ -ofmt=[fmt] Override target object format
\\ elf Executable and Linking Format
\\ c C source code
\\ wasm WebAssembly
\\ coff Common Object File Format (Windows)
\\ elf Executable and Linking Format
\\ llvmir LLVM text intermediate representation
\\ llvmbc LLVM binary intermediate representation
\\ macho macOS relocatables
\\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
\\ plan9 Plan 9 from Bell Labs object format
\\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
\\ wasm WebAssembly
\\ hex (planned feature) Intel IHEX
\\ raw (planned feature) Dump machine code directly
\\ -mcpu [cpu] Specify target CPU and feature set
@@ -791,15 +793,6 @@ const compile_usage =
\\Debug Options (Zig Compiler Development):
\\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes
\\ -fstack-report Print stack size diagnostics
\\ --verbose-link Display linker invocations
\\ --verbose-cc Display C compiler invocations
\\ --verbose-air Enable compiler debug output for Zig AIR
\\ --verbose-intern-pool Enable compiler debug output for InternPool
\\ --verbose-generic-instances Enable compiler debug output for generic instance generation
\\ --verbose-llvm-ir[=path] Enable compiler debug output for unoptimized LLVM IR
\\ --verbose-llvm-bc=[path] Enable compiler debug output for unoptimized LLVM BC
\\ --verbose-cimport Enable compiler debug output for C imports
\\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
\\ --debug-log [scope] Enable printing debug/info log messages for scope
\\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
\\ --debug-link-snapshot Dump linker state and output file information for troubleshooting
@@ -933,17 +926,11 @@ fn buildOutputType(
var listen: Listen = .none;
var debug_compile_errors = false;
var debug_incremental = false;
var verbose_link = (native_os != .wasi or builtin.link_libc) and
EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
var verbose_cc = (native_os != .wasi or builtin.link_libc) and
EnvVar.ZIG_VERBOSE_CC.isSet(environ_map);
var verbose_air = false;
var verbose_intern_pool = false;
var verbose_generic_instances = false;
var verbose_llvm_ir: ?[]const u8 = null;
var verbose_llvm_bc: ?[]const u8 = null;
var verbose_link = (native_os != .wasi or builtin.link_libc) and
EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
var link_depfile: ?[]const u8 = null;
var verbose_llvm_cpu_features = false;
var time_report = false;
var stack_report = false;
var show_builtin = false;
@@ -1809,24 +1796,10 @@ fn buildOutputType(
} else {
warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});
}
} else if (mem.eql(u8, arg, "--verbose-link")) {
verbose_link = true;
} else if (mem.eql(u8, arg, "--verbose-cc")) {
verbose_cc = true;
} else if (mem.eql(u8, arg, "--verbose-air")) {
verbose_air = true;
} else if (mem.eql(u8, arg, "--verbose-intern-pool")) {
verbose_intern_pool = true;
} else if (mem.eql(u8, arg, "--verbose-generic-instances")) {
verbose_generic_instances = true;
} else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
verbose_llvm_ir = "-";
} else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
verbose_llvm_ir = rest;
} else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
verbose_llvm_bc = rest;
} else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
verbose_llvm_cpu_features = true;
} else if (mem.eql(u8, arg, "--verbose-link")) {
verbose_link = true;
} else if (mem.cutPrefix(u8, arg, "-T")) |rest| {
linker_script = rest;
} else if (mem.cutPrefix(u8, arg, "-L")) |rest| {
@@ -3729,13 +3702,7 @@ fn buildOutputType(
.libc_installation = if (create_module.libc_installation) |*lci| lci else null,
.verbose_cc = verbose_cc,
.verbose_link = verbose_link,
.verbose_air = verbose_air,
.verbose_intern_pool = verbose_intern_pool,
.verbose_generic_instances = verbose_generic_instances,
.verbose_llvm_ir = verbose_llvm_ir,
.verbose_llvm_bc = verbose_llvm_bc,
.link_depfile = link_depfile,
.verbose_llvm_cpu_features = verbose_llvm_cpu_features,
.time_report = time_report,
.stack_report = stack_report,
.build_id = build_id,
@@ -3956,10 +3923,10 @@ fn buildOutputType(
});
}
try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc));
for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });
if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.count() + @intFromBool(verbose_link) + @intFromBool(verbose_cc));
for (log_scopes.keys()) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });
if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc");
if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
}
try runOrTest(
@@ -5627,17 +5594,17 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
}
}
const display_path = zig_source_path orelse "<stdin>";
const print_path = zig_source_path orelse "<stdin>";
const source: [:0]const u8 = s: {
var f = if (zig_source_path) |p| file: {
break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| {
fatal("unable to open file {q} for ast-check: {t}", .{ display_path, err });
fatal("unable to open file {q} for ast-check: {t}", .{ print_path, err });
};
} else Io.File.stdin();
defer if (zig_source_path != null) f.close(io);
var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
fatal("unable to load file {q} for ast-check: {t}", .{ display_path, err });
fatal("unable to load file {q} for ast-check: {t}", .{ print_path, err });
};
};
@@ -5661,7 +5628,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
if (zir.hasCompileErrors()) {
var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);
try wip_errors.addZirErrorMessages(zir, tree, source, display_path);
try wip_errors.addZirErrorMessages(zir, tree, source, print_path);
var error_bundle = try wip_errors.toOwnedBundle("");
try error_bundle.renderToStderr(io, .{}, color);
if (zir.loweringFailed()) {
@@ -5731,7 +5698,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
const zoir = try ZonGen.generate(arena, tree, .{});
if (zoir.hasCompileErrors()) {
var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);
try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path);
try wip_errors.addZoirErrorMessages(zoir, tree, source, print_path);
var error_bundle = try wip_errors.toOwnedBundle("");
error_bundle.renderToStderr(io, .{}, color) catch {};
process.exit(1);
@@ -6254,9 +6221,8 @@ fn randInt(io: Io, comptime T: type) T {
}
fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void {
if (!build_options.enable_logging) {
warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
} else {
try log_scopes.append(arena, scope_name);
switch (build_options.log_level) {
else => warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}),
.debug => try log_scopes.put(arena, try arena.dupe(u8, scope_name), {}),
}
}
+2
View File
@@ -193,6 +193,8 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
.coff,
.elf,
.hex,
.llvmbc,
.llvmir,
.macho,
.spirv,
.raw,
+5 -3
View File
@@ -410,6 +410,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
// Code generation phase
codegen_pm.run(llvm_module);
if (options->llvm_ir_out != nullptr) {
*options->llvm_ir_out = LLVMPrintModuleToString(module_ref);
}
if (options->llvm_ir_filename) {
if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) {
return true;
@@ -430,9 +434,7 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
auto os = raw_string_ostream(out_str);
TimerGroup::printAll(os);
TimerGroup::clearAll();
auto c_str = (char *)malloc(out_str.length() + 1);
strcpy(c_str, out_str.c_str());
*options->time_report_out = c_str;
*options->time_report_out = LLVMCreateMessage(out_str.c_str());
}
return false;
}
+6 -2
View File
@@ -67,8 +67,8 @@ struct ZigLLVMEmitOptions {
bool is_debug;
bool is_small;
// If not null, and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this
// `char *` will be populated with a `malloc`-allocated string containing the serialized (as
// JSON) time report data. The caller is responsible for freeing that memory.
// `char *` will be populated with the serialized (as JSON) time report data. The caller is
// responsible for freeing that memory with `disposeMessage`.
char **time_report_out;
bool tsan;
bool sancov;
@@ -79,6 +79,10 @@ struct ZigLLVMEmitOptions {
const char *bin_filename;
const char *llvm_ir_filename;
const char *bitcode_filename;
// If not null and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this
// `char *` will be populated with the optimized LLVM IR. The caller is responsible for freeing
// this memory with `disposeMessage`.
char **llvm_ir_out;
ZigLLVMCoverageOptions coverage;
};
+1 -1
View File
@@ -6,7 +6,7 @@ pub const llvm_has_xtensa = false;
pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@";
pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable;
pub const enable_debug_extensions = false;
pub const enable_logging = false;
pub const log_level: @import("std").log.Level = .err;
pub const enable_link_snapshots = false;
pub const enable_tracy = false;
pub const value_tracing = false;