[clang] [flang] [flang][debug] Add compressed DWARF support in Flang (PR #212584)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 28 11:53:48 PDT 2026


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 <timothy.smith at hpe.com>
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



More information about the cfe-commits mailing list