https://github.com/timsmith78 created https://github.com/llvm/llvm-project/pull/212584
Re-use most of the clang implementation for compressed DWARF support in flang. AI attribution: Co-developed with Claude Opus 4.6 >From b3d51382bd8fe6ef5842fb581747494f9ade87fd Mon Sep 17 00:00:00 2001 From: Timothy Smith <[email protected]> Date: Tue, 14 Jul 2026 15:23:40 -0500 Subject: [PATCH] [flang][debug] Add compressed DWARF support in Flang Re-use most of the clang implementation for compressed DWARF support in flang. AI attribution: Co-developed with Claude Opus 4.6 --- clang/include/clang/Driver/CommonArgs.h | 4 +++ clang/include/clang/Options/Options.td | 17 ++++++++- clang/lib/Driver/ToolChains/Clang.cpp | 36 ++----------------- clang/lib/Driver/ToolChains/CommonArgs.cpp | 32 +++++++++++++++++ clang/lib/Driver/ToolChains/Flang.cpp | 5 +++ flang/docs/ReleaseNotes.md | 7 ++++ .../include/flang/Frontend/CodeGenOptions.def | 2 ++ flang/include/flang/Frontend/CodeGenOptions.h | 1 + flang/lib/Frontend/CompilerInvocation.cpp | 17 +++++++++ flang/lib/Frontend/FrontendActions.cpp | 2 ++ .../Driver/compress-debug-sections-zstd.f90 | 9 +++++ flang/test/Driver/compress-debug-sections.f90 | 20 +++++++++++ .../Integration/debug-compressed-sections.f90 | 25 +++++++++++++ 13 files changed, 142 insertions(+), 35 deletions(-) create mode 100644 flang/test/Driver/compress-debug-sections-zstd.f90 create mode 100644 flang/test/Driver/compress-debug-sections.f90 create mode 100644 flang/test/Integration/debug-compressed-sections.f90 diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index 8c861df793311..01e358a1d0717 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -50,6 +50,10 @@ void addLinkerCompressDebugSectionsOption(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); +void renderDebugInfoCompressionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const Driver &D, const ToolChain &TC); + void claimNoWarnArgs(const llvm::opt::ArgList &Args); bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args, diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 1478624265f79..d0a11115e7e05 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5307,8 +5307,10 @@ def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>, " or precompiled headers">; def gno_modules : Flag <["-"], "gno-modules">, Group<g_flags_Group>; def gz_EQ : Joined<["-"], "gz=">, Group<g_flags_Group>, + Visibility<[ClangOption, FlangOption]>, HelpText<"DWARF debug sections compression type">; -def gz : Flag<["-"], "gz">, Alias<gz_EQ>, AliasArgs<["zlib"]>, Group<g_flags_Group>; +def gz : Flag<["-"], "gz">, Alias<gz_EQ>, AliasArgs<["zlib"]>, + Visibility<[ClangOption, FlangOption]>, Group<g_flags_Group>; def gembed_source : Flag<["-"], "gembed-source">, Group<g_flags_Group>, Visibility<[ClangOption, CC1Option]>, HelpText<"Embed source text in DWARF debug sections">, @@ -7969,12 +7971,25 @@ def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">, Values<"gdb,lldb,sce,dbx">, NormalizedValuesScope<"llvm::DebuggerKind">, NormalizedValues<["GDB", "LLDB", "SCE", "DBX"]>, MarshallingInfoEnum<CodeGenOpts<"DebuggerTuning">, "Default">; +} // let Visibility = [CC1Option, CC1AsOption] + +// FC1Option: flang accepts --compress-debug-sections= but does not use +// MarshallingInfoEnum for parsing. Flang hand-parses this option in +// flang/lib/Frontend/CompilerInvocation.cpp (parseDebugArgs). The marshalling +// metadata below is only used by clang's cc1 auto-generated parsing. +let Visibility = [CC1Option, CC1AsOption, FC1Option] in { + def compress_debug_sections_EQ : Joined<["-", "--"], "compress-debug-sections=">, HelpText<"DWARF debug sections compression type">, Values<"none,zlib,zstd">, NormalizedValuesScope<"llvm::DebugCompressionType">, NormalizedValues<["None", "Zlib", "Zstd"]>, MarshallingInfoEnum<CodeGenOpts<"CompressDebugSections">, "None">; def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">, Alias<compress_debug_sections_EQ>, AliasArgs<["zlib"]>; + +} // let Visibility = [CC1Option, CC1AsOption, FC1Option] + +let Visibility = [CC1Option, CC1AsOption] in { + def mno_exec_stack : Flag<["-"], "mnoexecstack">, HelpText<"Mark the file as not needing an executable stack">, MarshallingInfoFlag<CodeGenOpts<"NoExecStack">>; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 94f9a26aac39f..c4a07940981b8 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -731,38 +731,6 @@ RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, } } -static void RenderDebugInfoCompressionArgs(const ArgList &Args, - ArgStringList &CmdArgs, - const Driver &D, - const ToolChain &TC) { - const Arg *A = Args.getLastArg(options::OPT_gz_EQ); - if (!A) - return; - if (checkDebugInfoOption(A, Args, D, TC)) { - StringRef Value = A->getValue(); - if (Value == "none") { - CmdArgs.push_back("--compress-debug-sections=none"); - } else if (Value == "zlib") { - if (llvm::compression::zlib::isAvailable()) { - CmdArgs.push_back( - Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); - } else { - D.Diag(diag::warn_debug_compression_unavailable) << "zlib"; - } - } else if (Value == "zstd") { - if (llvm::compression::zstd::isAvailable()) { - CmdArgs.push_back( - Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); - } else { - D.Diag(diag::warn_debug_compression_unavailable) << "zstd"; - } - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getSpelling() << Value; - } - } -} - static void handleAMDGPUCodeObjectVersionOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -5034,7 +5002,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, CmdArgs.push_back("-dwarf-explicit-import"); renderDwarfFormat(D, T, Args, CmdArgs, EffectiveDWARFVersion); - RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); + renderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); // This controls whether or not we perform JustMyCode instrumentation. if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) { @@ -9353,7 +9321,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, llvm::DebuggerKind::Default); renderDwarfFormat(D, Triple, Args, CmdArgs, DwarfVersion); - RenderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain()); + renderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain()); // Handle -fPIC et al -- the relocation-model affects the assembler // for some targets. diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 08c06951cf220..a8b905bbe48c9 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -684,6 +684,38 @@ void tools::addLinkerCompressDebugSectionsOption( } } +void tools::renderDebugInfoCompressionArgs(const ArgList &Args, + ArgStringList &CmdArgs, + const Driver &D, + const ToolChain &TC) { + const Arg *A = Args.getLastArg(options::OPT_gz_EQ); + if (!A) + return; + if (checkDebugInfoOption(A, Args, D, TC)) { + StringRef Value = A->getValue(); + if (Value == "none") { + CmdArgs.push_back("--compress-debug-sections=none"); + } else if (Value == "zlib") { + if (llvm::compression::zlib::isAvailable()) { + CmdArgs.push_back( + Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::warn_debug_compression_unavailable) << "zlib"; + } + } else if (Value == "zstd") { + if (llvm::compression::zstd::isAvailable()) { + CmdArgs.push_back( + Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::warn_debug_compression_unavailable) << "zstd"; + } + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Value; + } + } +} + void tools::AddTargetFeature(const ArgList &Args, std::vector<StringRef> &Features, OptSpecifier OnOpt, OptSpecifier OffOpt, diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 650148de1374a..aadc626d1c1ec 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -15,6 +15,7 @@ #include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/Frontend/Debug/Options.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Path.h" #include "llvm/TargetParser/Host.h" #include "llvm/TargetParser/RISCVISAInfo.h" @@ -199,6 +200,10 @@ void Flang::addDebugOptions(const llvm::opt::ArgList &Args, const JobAction &JA, CmdArgs.push_back(SplitDWARFOut); } } + + // Handle compressed debug sections (-gz). + renderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); + addDebugInfoForProfilingArgs(D, TC, Args, CmdArgs); } diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md index 888da4d58b868..a2417b508f715 100644 --- a/flang/docs/ReleaseNotes.md +++ b/flang/docs/ReleaseNotes.md @@ -33,8 +33,15 @@ page](https://llvm.org/releases/). ## Non-comprehensive list of changes in this release +- Added support for compressed DWARF debug sections. Flang now supports + compressing DWARF debug info in ELF object files using zlib or zstd, + reducing debug information size in compiled binaries. + ## New Compiler Flags +- Added `-gz` and `-gz=<format>` flags to enable compression of DWARF debug + sections. Supported formats are `zlib`, `zstd`, and `none`. + ## Windows Support ## Fortran Language Changes in Flang diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index 53ddc20a6e810..d49a7f3647eec 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -71,5 +71,7 @@ ENUM_CODEGENOPT(ComplexRange, ComplexRangeKind, 3, ComplexRangeKind::CX_Full) // ENUM_CODEGENOPT(DoConcurrentMapping, DoConcurrentMappingKind, 2, DoConcurrentMappingKind::DCMK_None) ///< Map `do concurrent` to OpenMP +ENUM_CODEGENOPT(CompressDebugSections, llvm::DebugCompressionType, 2, llvm::DebugCompressionType::None) ///< DWARF debug sections compression type + #undef CODEGENOPT #undef ENUM_CODEGENOPT diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h index 257d7ca9c407d..68aa2b1810abf 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -20,6 +20,7 @@ #include "llvm/Frontend/Debug/Options.h" #include "llvm/Frontend/Driver/CodeGenOptions.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Regex.h" #include "llvm/Target/TargetOptions.h" #include <memory> diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 79ad08353b64c..a925ef696133a 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -174,6 +174,23 @@ static bool parseDebugArgs(Fortran::frontend::CodeGenOptions &opts, opts.DebugInfoForProfiling = args.hasArg(clang::options::OPT_fdebug_info_for_profiling); + if (const llvm::opt::Arg *a = + args.getLastArg(clang::options::OPT_compress_debug_sections_EQ)) { + auto type = llvm::StringSwitch<std::optional<llvm::DebugCompressionType>>( + a->getValue()) + .Case("none", llvm::DebugCompressionType::None) + .Case("zlib", llvm::DebugCompressionType::Zlib) + .Case("zstd", llvm::DebugCompressionType::Zstd) + .Default(std::nullopt); + if (type) { + opts.setCompressDebugSections(*type); + } else { + diags.Report(clang::diag::err_drv_invalid_value) + << a->getAsString(args) << a->getValue(); + return false; + } + } + return true; } diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 428002f68578b..8955a8f61e513 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -1422,6 +1422,8 @@ void CodeGenAction::executeAction() { targetMachine.Options.MCOptions.AsmVerbose = targetOpts.asmVerbose; targetMachine.Options.MCOptions.SplitDwarfFile = codeGenOpts.SplitDwarfFile; + targetMachine.Options.MCOptions.CompressDebugSections = + codeGenOpts.getCompressDebugSections(); const llvm::Triple &theTriple = targetMachine.getTargetTriple(); diff --git a/flang/test/Driver/compress-debug-sections-zstd.f90 b/flang/test/Driver/compress-debug-sections-zstd.f90 new file mode 100644 index 0000000000000..530319a97ae23 --- /dev/null +++ b/flang/test/Driver/compress-debug-sections-zstd.f90 @@ -0,0 +1,9 @@ +! Test -gz=zstd (compressed debug sections with zstd) option handling. + +! REQUIRES: zstd + +! RUN: %flang -### -c -target x86_64-unknown-linux-gnu -gz=zstd %s 2>&1 | FileCheck %s --check-prefix=GZ-ZSTD +! GZ-ZSTD: "--compress-debug-sections=zstd" + +program test +end program test diff --git a/flang/test/Driver/compress-debug-sections.f90 b/flang/test/Driver/compress-debug-sections.f90 new file mode 100644 index 0000000000000..bce2001084ba2 --- /dev/null +++ b/flang/test/Driver/compress-debug-sections.f90 @@ -0,0 +1,20 @@ +! Test -gz (compressed debug sections) option handling. + +! REQUIRES: zlib + +! RUN: %flang -### -c -target x86_64-unknown-linux-gnu -gz %s 2>&1 | FileCheck %s --check-prefix=GZ +! RUN: %flang -### -c -target x86_64-unknown-linux-gnu -gz=zlib %s 2>&1 | FileCheck %s --check-prefix=GZ +! GZ: "--compress-debug-sections=zlib" + +! RUN: %flang -### -c -target x86_64-unknown-linux-gnu -gz=none %s 2>&1 | FileCheck %s --check-prefix=GZ-NONE +! GZ-NONE: "--compress-debug-sections=none" + +! RUN: not %flang -### -c -target x86_64-unknown-linux-gnu -gz=invalid %s 2>&1 | FileCheck %s --check-prefix=GZ-INVALID +! GZ-INVALID: error: unsupported argument 'invalid' to option '-gz=' + +! Test that -gz without -g still passes --compress-debug-sections to fc1. +! RUN: %flang -### -c -target x86_64-unknown-linux-gnu -gz=zlib %s 2>&1 | FileCheck %s --check-prefix=GZ-NO-G +! GZ-NO-G: "--compress-debug-sections=zlib" + +program test +end program test diff --git a/flang/test/Integration/debug-compressed-sections.f90 b/flang/test/Integration/debug-compressed-sections.f90 new file mode 100644 index 0000000000000..aac86f46df0f8 --- /dev/null +++ b/flang/test/Integration/debug-compressed-sections.f90 @@ -0,0 +1,25 @@ +! REQUIRES: x86-registered-target, zlib + +! Test that --compress-debug-sections=zlib compresses debug sections in the +! output object file. +! RUN: %flang_fc1 -debug-info-kind=standalone -triple x86_64-unknown-linux \ +! RUN: --compress-debug-sections=zlib -emit-obj -o %t.o %s +! RUN: llvm-readobj -S %t.o | FileCheck --check-prefix=ZLIB %s + +! ZLIB: Name: .debug_info +! ZLIB: SHF_COMPRESSED + +! Test that --compress-debug-sections=none does not compress debug sections. +! RUN: %flang_fc1 -debug-info-kind=standalone -triple x86_64-unknown-linux \ +! RUN: --compress-debug-sections=none -emit-obj -o %t_none.o %s +! RUN: llvm-readobj -S %t_none.o | FileCheck --check-prefix=NONE %s + +! NONE: Name: .debug_info +! NONE: Flags [ +! NONE-NOT: SHF_COMPRESSED + +program test + implicit none + integer :: x + x = 1 +end program test _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
