From cfcd6698cd9385938df27a2052c2309229171e4f Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 16 Mar 2023 01:32:43 -0400 Subject: [PATCH] main: add debug option to dump unoptimized llvm ir --- lib/build_runner.zig | 9 +++++++-- lib/std/Build.zig | 7 +++++-- lib/std/Build/CompileStep.zig | 3 ++- src/Compilation.zig | 9 +++++++-- src/Module.zig | 4 ++-- src/codegen/llvm.zig | 31 +++++++++++++++++++++++++++++-- src/codegen/llvm/bindings.zig | 3 +++ src/glibc.zig | 1 + src/libcxx.zig | 2 ++ src/libtsan.zig | 1 + src/libunwind.zig | 1 + src/main.zig | 23 +++++++++++++++-------- 12 files changed, 75 insertions(+), 19 deletions(-) diff --git a/lib/build_runner.zig b/lib/build_runner.zig index 5f5601a68d..56dcf43155 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -204,7 +204,11 @@ pub fn main() !void { } else if (mem.eql(u8, arg, "--verbose-air")) { builder.verbose_air = true; } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { - builder.verbose_llvm_ir = true; + builder.verbose_llvm_ir = "-"; + } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { + builder.verbose_llvm_ir = arg["--verbose-llvm-ir=".len..]; + } else if (mem.eql(u8, arg, "--verbose-llvm-bc=")) { + builder.verbose_llvm_bc = arg["--verbose-llvm-bc=".len..]; } else if (mem.eql(u8, arg, "--verbose-cimport")) { builder.verbose_cimport = true; } else if (mem.eql(u8, arg, "--verbose-cc")) { @@ -990,7 +994,8 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi \\ --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-llvm-ir[=file] Enable compiler debug output for LLVM IR + \\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC \\ --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 diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 279dd765b5..632a45cf23 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -54,7 +54,8 @@ verbose: bool, verbose_link: bool, verbose_cc: bool, verbose_air: bool, -verbose_llvm_ir: bool, +verbose_llvm_ir: ?[]const u8, +verbose_llvm_bc: ?[]const u8, verbose_cimport: bool, verbose_llvm_cpu_features: bool, reference_trace: ?u32 = null, @@ -204,7 +205,8 @@ pub fn create( .verbose_link = false, .verbose_cc = false, .verbose_air = false, - .verbose_llvm_ir = false, + .verbose_llvm_ir = null, + .verbose_llvm_bc = null, .verbose_cimport = false, .verbose_llvm_cpu_features = false, .invalid_user_input = false, @@ -292,6 +294,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc .verbose_cc = parent.verbose_cc, .verbose_air = parent.verbose_air, .verbose_llvm_ir = parent.verbose_llvm_ir, + .verbose_llvm_bc = parent.verbose_llvm_bc, .verbose_cimport = parent.verbose_cimport, .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features, .reference_trace = parent.reference_trace, diff --git a/lib/std/Build/CompileStep.zig b/lib/std/Build/CompileStep.zig index d73e5d3b41..72855f360e 100644 --- a/lib/std/Build/CompileStep.zig +++ b/lib/std/Build/CompileStep.zig @@ -1438,7 +1438,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { if (b.verbose_cimport) try zig_args.append("--verbose-cimport"); if (b.verbose_air) try zig_args.append("--verbose-air"); - if (b.verbose_llvm_ir) try zig_args.append("--verbose-llvm-ir"); + if (b.verbose_llvm_ir) |path| try zig_args.append(b.fmt("--verbose-llvm-ir={s}", .{path})); + if (b.verbose_llvm_bc) |path| try zig_args.append(b.fmt("--verbose-llvm-bc={s}", .{path})); if (b.verbose_link or self.verbose_link) try zig_args.append("--verbose-link"); if (b.verbose_cc or self.verbose_cc) try zig_args.append("--verbose-cc"); if (b.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features"); diff --git a/src/Compilation.zig b/src/Compilation.zig index 89512ce744..858afb6ca3 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -86,7 +86,8 @@ clang_preprocessor_mode: ClangPreprocessorMode, /// Whether to print clang argvs to stdout. verbose_cc: bool, verbose_air: bool, -verbose_llvm_ir: bool, +verbose_llvm_ir: ?[]const u8, +verbose_llvm_bc: ?[]const u8, verbose_cimport: bool, verbose_llvm_cpu_features: bool, disable_c_depfile: bool, @@ -585,7 +586,8 @@ pub const InitOptions = struct { verbose_cc: bool = false, verbose_link: bool = false, verbose_air: bool = false, - verbose_llvm_ir: bool = false, + verbose_llvm_ir: ?[]const u8 = null, + verbose_llvm_bc: ?[]const u8 = null, verbose_cimport: bool = false, verbose_llvm_cpu_features: bool = false, is_test: bool = false, @@ -1559,6 +1561,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .verbose_cc = options.verbose_cc, .verbose_air = options.verbose_air, .verbose_llvm_ir = options.verbose_llvm_ir, + .verbose_llvm_bc = options.verbose_llvm_bc, .verbose_cimport = options.verbose_cimport, .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features, .disable_c_depfile = options.disable_c_depfile, @@ -5342,6 +5345,7 @@ fn buildOutputFromZig( .verbose_link = comp.bin_file.options.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, @@ -5419,6 +5423,7 @@ pub fn build_crt_file( .verbose_link = comp.bin_file.options.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, diff --git a/src/Module.zig b/src/Module.zig index c47e4fc234..17016865d1 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4263,7 +4263,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { comp.emit_llvm_bc == null); const dump_air = builtin.mode == .Debug and comp.verbose_air; - const dump_llvm_ir = builtin.mode == .Debug and comp.verbose_llvm_ir; + const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); if (no_bin_file and !dump_air and !dump_llvm_ir) return; @@ -6395,7 +6395,7 @@ pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { comp.emit_llvm_ir == null and comp.emit_llvm_bc == null); - const dump_llvm_ir = builtin.mode == .Debug and comp.verbose_llvm_ir; + const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); if (no_bin_file and !dump_llvm_ir) return; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 85a82f4eda..11fc44747e 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -751,8 +751,35 @@ pub const Object = struct { dib.finalize(); } - if (comp.verbose_llvm_ir) { - self.llvm_module.dump(); + if (comp.verbose_llvm_ir) |path| { + if (std.mem.eql(u8, path, "-")) { + self.llvm_module.dump(); + } else { + const path_z = try comp.gpa.dupeZ(u8, path); + defer comp.gpa.free(path_z); + + var error_message: [*:0]const u8 = undefined; + + if (self.llvm_module.printModuleToFile(path_z, &error_message).toBool()) { + defer llvm.disposeMessage(error_message); + + log.err("dump LLVM module failed ir={s}: {s}", .{ + path, error_message, + }); + } + } + } + + if (comp.verbose_llvm_bc) |path| { + const path_z = try comp.gpa.dupeZ(u8, path); + defer comp.gpa.free(path_z); + + const error_code = self.llvm_module.writeBitcodeToFile(path_z); + if (error_code != 0) { + log.err("dump LLVM module failed bc={s}: {d}", .{ + path, error_code, + }); + } } var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index e16da29335..c759c7874b 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -422,6 +422,9 @@ pub const Module = opaque { pub const printModuleToFile = LLVMPrintModuleToFile; extern fn LLVMPrintModuleToFile(M: *Module, Filename: [*:0]const u8, ErrorMessage: *[*:0]const u8) Bool; + + pub const writeBitcodeToFile = LLVMWriteBitcodeToFile; + extern fn LLVMWriteBitcodeToFile(M: *Module, Path: [*:0]const u8) c_int; }; pub const lookupIntrinsicID = LLVMLookupIntrinsicID; diff --git a/src/glibc.zig b/src/glibc.zig index b37398bffd..327e4f4bb9 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -1097,6 +1097,7 @@ fn buildSharedLib( .verbose_link = comp.bin_file.options.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, diff --git a/src/libcxx.zig b/src/libcxx.zig index 9c5dc9426f..07e3473338 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -250,6 +250,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void { .verbose_link = comp.bin_file.options.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, @@ -410,6 +411,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { .verbose_link = comp.bin_file.options.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, diff --git a/src/libtsan.zig b/src/libtsan.zig index 54bf00e4b6..90d2537876 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -226,6 +226,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { .verbose_link = comp.bin_file.options.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, diff --git a/src/libunwind.zig b/src/libunwind.zig index aefbfb457d..6c46b6bb28 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -122,6 +122,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { .verbose_link = comp.bin_file.options.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, diff --git a/src/main.zig b/src/main.zig index e7d5c647b5..e28bdf34cf 100644 --- a/src/main.zig +++ b/src/main.zig @@ -370,10 +370,10 @@ const usage_build_generic = \\ -fno-emit-bin Do not output machine code \\ -femit-asm[=path] Output .s (assembly code) \\ -fno-emit-asm (default) Do not output .s (assembly code) - \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions) - \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR - \\ -femit-llvm-bc[=path] Produce a LLVM module as a .bc file (requires LLVM extensions) - \\ -fno-emit-llvm-bc (default) Do not produce a LLVM module as a .bc file + \\ -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions) + \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with optimized LLVM IR + \\ -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions) + \\ -fno-emit-llvm-bc (default) Do not produce an optimized LLVM module as a .bc file \\ -femit-h[=path] Generate a C header file (.h) \\ -fno-emit-h (default) Do not generate a C header file (.h) \\ -femit-docs[=path] Create a docs/ dir with html documentation @@ -555,13 +555,14 @@ const usage_build_generic = \\ --test-runner [path] Specify a custom test runner \\ \\Debug Options (Zig Compiler Development): - \\ -fopt-bisect-limit [limit] Only run [limit] first LLVM optimization passes + \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes \\ -ftime-report Print timing diagnostics \\ -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-llvm-ir Enable compiler debug output for LLVM IR + \\ --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 @@ -704,7 +705,8 @@ fn buildOutputType( var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK"); var verbose_cc = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_CC"); var verbose_air = false; - var verbose_llvm_ir = false; + var verbose_llvm_ir: ?[]const u8 = null; + var verbose_llvm_bc: ?[]const u8 = null; var verbose_cimport = false; var verbose_llvm_cpu_features = false; var time_report = false; @@ -1441,7 +1443,11 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "--verbose-air")) { verbose_air = true; } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { - verbose_llvm_ir = true; + verbose_llvm_ir = "-"; + } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { + verbose_llvm_ir = arg["--verbose-llvm-ir=".len..]; + } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) { + verbose_llvm_bc = arg["--verbose-llvm-bc=".len..]; } else if (mem.eql(u8, arg, "--verbose-cimport")) { verbose_cimport = true; } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { @@ -3226,6 +3232,7 @@ fn buildOutputType( .verbose_link = verbose_link, .verbose_air = verbose_air, .verbose_llvm_ir = verbose_llvm_ir, + .verbose_llvm_bc = verbose_llvm_bc, .verbose_cimport = verbose_cimport, .verbose_llvm_cpu_features = verbose_llvm_cpu_features, .machine_code_model = machine_code_model,