[clang] [dyndbg][Clang] Implement nested-ELF dynamic debugging support (PR #194860)

via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 29 06:35:31 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-driver

Author: Orlando Cazalet-Hyams (OCHyams)

<details>
<summary>Changes</summary>

A clone of the module is compiled without optimisations and embedded into the
to-be-optimised module using `embedBufferInModule`, similarly to how
`-ffat-lto-objects` and `-fembed-offload-object` work.

That unoptimised-code object is embedded in the optimised-code object in a
section called `.debug_llvm_dyndbg`.

The optimised ELF/module may be referred to as the "outer" ELF/module, and the
unoptimized one the "inner" ELF/module.

The outer module holds global data referred to by both modules and all calls in
the inner module are to outer module functions. To facilitate this the outer
module is modified, adding external-linkage aliases for local symbols.

See RFC https://discourse.llvm.org/t/90113 for more detail (including a diagram).

To begin with there's a few incompatible compilation modes/flags:
* LTO
* Sanitizers (currently investigating what this looks like)
* Profiling / code-coverage instrumentation
* Split DWARF (where does the inner object's split DWARF go?)
* Non x86 targets (I've only been testing on x86).

---

Patch is 35.22 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/194860.diff


25 Files Affected:

- (modified) clang/include/clang/Basic/CodeGenOptions.h (+3) 
- (modified) clang/include/clang/Basic/DebugOptions.def (+7) 
- (modified) clang/include/clang/Basic/DiagnosticDriverKinds.td (+4) 
- (modified) clang/include/clang/Basic/DiagnosticFrontendKinds.td (+7) 
- (modified) clang/include/clang/Options/Options.td (+18) 
- (modified) clang/lib/CodeGen/BackendUtil.cpp (+94) 
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+31) 
- (modified) clang/lib/Frontend/CompilerInvocation.cpp (+6) 
- (added) clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/globalopt.c (+24) 
- (added) clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/lit.local.cfg (+4) 
- (added) clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/lit.local.cfg (+3) 
- (added) clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/no-target.c (+14) 
- (added) clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c (+13) 
- (added) clang/test/DebugInfo/DynamicDebugging/attr-outer-no-specialization.c (+7) 
- (added) clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad-unsupported.c (+9) 
- (added) clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad.c (+10) 
- (added) clang/test/DebugInfo/DynamicDebugging/compiler-used.cpp (+37) 
- (added) clang/test/DebugInfo/DynamicDebugging/embed.c (+12) 
- (added) clang/test/DebugInfo/DynamicDebugging/inner-attrs.c (+25) 
- (added) clang/test/DebugInfo/DynamicDebugging/profile-coverage.c (+7) 
- (added) clang/test/DebugInfo/DynamicDebugging/symbols-functions.cpp (+33) 
- (added) clang/test/DebugInfo/DynamicDebugging/symbols-globals.cpp (+72) 
- (added) clang/test/DebugInfo/DynamicDebugging/symbols-internal-comdat.cpp (+27) 
- (added) clang/test/Driver/dynamic-debugging-flags.c (+32) 
- (modified) clang/test/Misc/warning-flags.c (+3-1) 


``````````diff
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 9454f7672b7e1..5afc27beaa923 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -359,6 +359,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// Prefix to use for -save-temps output.
   std::string SaveTempsFilePrefix;
 
+  /// Prefix to use for -save-dynamic-debugging-temps output.
+  std::string SaveDynDbgTempsFilePrefix;
+
   /// Name of file passed with -fcuda-include-gpubinary option to forward to
   /// CUDA runtime back-end for incorporating them into host-side object file.
   std::string CudaGpuBinaryFileName;
diff --git a/clang/include/clang/Basic/DebugOptions.def b/clang/include/clang/Basic/DebugOptions.def
index 604e87e615a69..b2fa50a289da9 100644
--- a/clang/include/clang/Basic/DebugOptions.def
+++ b/clang/include/clang/Basic/DebugOptions.def
@@ -62,6 +62,13 @@ ENUM_DEBUGOPT(AssignmentTrackingMode, AssignmentTrackingOpts, 2,
 /// Whether or not to use Key Instructions to determine breakpoint locations.
 DEBUGOPT(DebugKeyInstructions, 1, 0, Benign)
 
+/// Whether or not to use the Dynamic Debugging feature.
+DEBUGOPT(DynamicDebugging, 1, 0, Benign)
+
+/// Flag for testing: discard the dynamic debugging debug module before codegen
+/// if true.
+DEBUGOPT(DiscardDynamicDebuggingDebugModule, 1, 0, Benign)
+
 DEBUGOPT(DebugColumnInfo, 1, 0, Compatible) ///< Whether or not to use column information
                                            ///< in debug info.
 
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index ed6a9107002af..def5e194053d6 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -390,6 +390,10 @@ def err_drv_optimization_remark_format : Error<
 def err_drv_no_neon_modifier : Error<"[no]neon is not accepted as modifier, please use [no]simd instead">;
 def err_drv_invalid_omp_target : Error<"OpenMP target is invalid: '%0'">;
 def err_drv_incompatible_omp_arch : Error<"OpenMP target architecture '%0' pointer size is incompatible with host '%1'">;
+def err_drv_dyndbg_lto : Error<"'-fdynamic-debugging' incompatible with '-flto'">;
+def err_drv_dyndbg_incompatible : Error<"'-fdynamic-debugging' incompatible with '%0'">;
+def err_drv_dyndbg_ir : Error<"'-fdynamic-debugging' incompatible with IR input">;
+def warn_drv_dyndbg_req_debug : Warning<"'-fdynamic-debugging' ignored: requires debug info">;
 def err_drv_omp_host_target_not_supported : Error<
   "target '%0' is not a supported OpenMP host target">;
 def err_drv_expecting_fopenmp_with_fopenmp_targets : Error<
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 62b74574102e4..d624fcb7179cc 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -508,4 +508,11 @@ def err_cir_to_cir_transform_failed : Error<
 def err_cir_verification_failed_pre_passes : Error<
     "CIR module verification error before running CIR-to-CIR passes">,
     DefaultFatal;
+
+def warn_dyndbg_unable_to_create_target : Warning<
+    "ignoring -fdynamic-debugging: unable to create target: '%0'">;
+
+def err_dyndbg_no_instrumentation : Error<
+    "'-fdynamic-debugging' unsupported with instrumentation (PGO/code coverage)">;
 }
+
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 412683fd968b0..534c9b0542726 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5182,6 +5182,24 @@ defm key_instructions : BoolGOption<"key-instructions",
         " in some debuggers. DWARF only.">,
     BothFlags<[], [ClangOption, CLOption, CC1Option]>>,
   Group<g_flags_Group>;
+defm dynamic_debugging : BoolOption<"f", "dynamic-debugging",
+    CodeGenOpts<"DynamicDebugging">, DefaultFalse,
+    NegFlag<SetFalse>, PosFlag<SetTrue, [], [],
+        "Enable Dynamic Debugging, which allows runtime switching between"
+        " optimized and unoptimized code in debuggers that support it."
+        " Specified optimization level affects only the optimized code."
+        " This flag inhibits interprocedural optimizations.">,
+    BothFlags<[], [ClangOption, CLOption, CC1Option]>>;
+def save_dynamic_debugging_temps : Flag<["--"], "save-dynamic-debugging-temps">,
+    Visibility<[ClangOption, CLOption, CC1Option]>,
+    HelpText<"Compiler-debugging/testing option to save the intermediate"
+             " states of dynamic debugging in the same directory as the final"
+             " output file">;
+def discard_dynamic_debugging_debug_module : Flag<["--"], "discard-dynamic-debugging-debug-module">,
+    MarshallingInfoFlag<CodeGenOpts<"DiscardDynamicDebuggingDebugModule">>,
+    Visibility<[CC1Option]>,
+    HelpText<"Compiler-debugging/testing option to discard the dynamic"
+             " debugging debug module before Clang codegen">;
 def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
 def help : Flag<["-", "--"], "help">,
     Visibility<[ClangOption, CC1Option, CC1AsOption,
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 5b8b4083c2ac0..cf8dbeccdbee1 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -90,6 +90,7 @@
 #include "llvm/Transforms/Scalar/GVN.h"
 #include "llvm/Transforms/Scalar/JumpThreading.h"
 #include "llvm/Transforms/Utils/Debugify.h"
+#include "llvm/Transforms/Utils/DynamicDebugging.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
 #include <limits>
 #include <memory>
@@ -1471,6 +1472,99 @@ void clang::emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts,
     }
   }
 
+
+  bool EnableDynamicDebugging = CGOpts.DynamicDebugging;
+  // Disable dyndbg if the target isn't available as we're compiling to the
+  // inner module to object regardless of other options. (This may change).
+  if (EnableDynamicDebugging) {
+    std::string Error;
+    const llvm::Target *TheTarget =
+        TargetRegistry::lookupTarget(M->getTargetTriple(), Error);
+    if (!TheTarget) {
+      Diags.Report(diag::warn_dyndbg_unable_to_create_target) << Error;
+      EnableDynamicDebugging = false;
+    }
+
+    // Instrumentation causes issues (parts of LLVM expect certain globals to
+    // have initializers). Intrinsics may already have been added to IR by now,
+    // so we can't just turn it off for the inner module (we'd have to strip
+    // them out / not clone them). TODO: Support instrumentation.
+    if (CGOpts.getProfileInstr() != driver::ProfileInstrKind::ProfileNone) {
+      Diags.Report(diag::err_dyndbg_no_instrumentation);
+      EnableDynamicDebugging = false;
+    }
+  }
+
+  if (EnableDynamicDebugging) {
+    /// Helper for saving the module(s) at various dyndbg stages.
+    auto SaveModule = [&](StringRef Name, llvm::Module &M) {
+      if (CGOpts.SaveDynDbgTempsFilePrefix == "")
+        return;
+      std::error_code EC;
+      std::string Path =
+          Twine(CGOpts.SaveDynDbgTempsFilePrefix + "." + Name + ".ll").str();
+      raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::OF_None);
+      if (EC) {
+        // Copy -save-temps behaviour: this is a debugging option so we simply
+        // exit if there's an issue.
+        errs() << "failed to open " << Path << ": " << EC.message() << '\n';
+        errs().flush();
+        exit(1);
+      }
+      M.print(OS, nullptr);
+    };
+
+    // Compute a hash suffix for promoting static globals (once per TU).
+    std::string PromotionSuffix;
+    {
+      // LLVM's hash/hash_combine is not guaranteed to be stable.
+      MD5 Hash;
+      // Include args in the hash else preprocessor definitions used to alter
+      // the same source file compiled twice won't generate unique hashes.
+      Hash.update(CGOpts.CmdArgs);
+      for (auto *CU : M->debug_compile_units()) {
+        Hash.update(CU->getDirectory());
+        Hash.update(CU->getFilename());
+      }
+
+      MD5::MD5Result Result;
+      Hash.final(Result);
+      PromotionSuffix = ".dyndbg." + utohexstr(Result.low());
+    }
+
+    SaveModule("dyndbg.0.input", *M);
+    // Modify M as needed and create an "unoptimized" clone.
+    auto UnoptM = prepareForDynamicDebugging(M, PromotionSuffix);
+    SaveModule("dyndbg.1.inner", *UnoptM);
+
+    if (!CGOpts.DiscardDynamicDebuggingDebugModule) {
+      CodeGenOptions UnoptOpts = CGOpts;
+      UnoptOpts.OptimizationLevel = 0;
+      UnoptOpts.OptimizeSize = 0;
+      EmitAssemblyHelper AsmHelper(CI, UnoptOpts, UnoptM.get(), VFS);
+
+      // Create a buffer and ostream for the inner ELF.
+      SmallVector<char, 0> UnoptBuf;
+      std::unique_ptr<llvm::raw_pwrite_stream> UnoptOS =
+          std::make_unique<llvm::raw_svector_ostream>(UnoptBuf);
+
+      // Always run the full codegen pipeline (Backend_EmitObj). This causes
+      // assertion failures if there's no registered backend which is why we
+      // disable the feature if that's the case (see
+      // warn_dyndbg_unable_to_create_target above).
+      AsmHelper.emitAssembly(Backend_EmitObj, std::move(UnoptOS), BC);
+      assert(!UnoptBuf.empty() && "Expected emitAssembly to fill UnoptBuf");
+
+      // Inject the inner ELF into the outer module.
+      StringRef SR(UnoptBuf.data(), UnoptBuf.size());
+      std::unique_ptr<MemoryBuffer> Buf =
+          MemoryBuffer::getMemBuffer(SR, "", false);
+
+      llvm::embedBufferInModule(*M, *Buf, ".debug_llvm_dyndbg");
+    }
+    SaveModule("dyndbg.2.outer", *M);
+  }
+
   EmitAssemblyHelper AsmHelper(CI, CGOpts, M, VFS);
   AsmHelper.emitAssembly(Action, std::move(OS), BC);
 
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 6b3654d4b2526..962c5ea923990 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4665,6 +4665,34 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
                     options::OPT_gno_structor_decl_linkage_names, true))
     CmdArgs.push_back("-gno-structor-decl-linkage-names");
 
+  if (Args.hasFlag(options::OPT_fdynamic_debugging,
+                   options::OPT_fno_dynamic_debugging, false)) {
+    // As this is an experimental feature we can afford to be strict about
+    // supported configurations.
+    if (!TC.getTriple().isX86())
+      D.Diag(diag::err_drv_unsupported_opt_for_target)
+          << Args.getLastArg(options::OPT_fdynamic_debugging)->getAsString(Args)
+          << T.getTriple();
+    if (D.isUsingLTO())
+      D.Diag(diag::err_drv_dyndbg_lto);
+    if (DwarfFission != DwarfFissionKind::None)
+      D.Diag(diag::err_drv_dyndbg_incompatible)
+          << Args.getLastArg(options::OPT_gsplit_dwarf)->getAsString(Args);
+    // There's no fundamental reason why IR input should be incompatible, but
+    // it would add some complexity, and reducing the test matrix is valuable.
+    if (IRInput)
+      D.Diag(diag::err_drv_dyndbg_ir);
+
+    // Disable composition with sanitizers for now.
+    if (auto *San = Args.getLastArg(options::OPT_fsanitize_EQ))
+      D.Diag(diag::err_drv_dyndbg_incompatible) << San->getAsString(Args);
+
+    if (!EmitDwarf)
+      D.Diag(diag::warn_drv_dyndbg_req_debug);
+    else
+      CmdArgs.push_back("-fdynamic-debugging");
+  }
+
   if (EmitCodeView) {
     CmdArgs.push_back("-gcodeview");
 
@@ -5358,6 +5386,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (Args.getLastArg(options::OPT_save_temps_EQ))
     Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
 
+  if (Args.getLastArg(options::OPT_save_dynamic_debugging_temps))
+    Args.AddLastArg(CmdArgs, options::OPT_save_dynamic_debugging_temps);
+
   auto *MemProfArg = Args.getLastArg(options::OPT_fmemory_profile,
                                      options::OPT_fmemory_profile_EQ,
                                      options::OPT_fno_memory_profile);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 748c36efefaed..2dc70798f1ff3 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1670,6 +1670,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
   if (Opts.SaveTempsFilePrefix == OutputFile)
     GenerateArg(Consumer, OPT_save_temps_EQ, "obj");
 
+  if (!Opts.SaveDynDbgTempsFilePrefix.empty())
+    GenerateArg(Consumer, OPT_save_dynamic_debugging_temps);
+
   StringRef MemProfileBasename("memprof.profraw");
   if (!Opts.MemoryProfileOutput.empty()) {
     if (Opts.MemoryProfileOutput == MemProfileBasename) {
@@ -2004,6 +2007,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
             .Case("obj", OutputFile)
             .Default(llvm::sys::path::filename(OutputFile).str());
 
+  if (Arg *A = Args.getLastArg(OPT_save_dynamic_debugging_temps))
+    Opts.SaveDynDbgTempsFilePrefix = OutputFile;
+
   // The memory profile runtime appends the pid to make this name more unique.
   const char *MemProfileBasename = "memprof.profraw";
   if (Args.hasArg(OPT_fmemory_profile_EQ)) {
diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/globalopt.c b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/globalopt.c
new file mode 100644
index 0000000000000..4450bd8aae5e2
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/globalopt.c
@@ -0,0 +1,24 @@
+// Check `a` and `d` have aliases while keeping their original symbols.
+// GlobalOpt would usually replace these internal-linkage functions with
+// their external-linkage aliases. That's currently prevented as a side effect
+// of adding discardable functions to the compiler-used global.
+
+// RUN: %clang -cc1 %s -emit-obj -O3 -debug-info-kind=limited -fdynamic-debugging -o - -triple x86_64-unknown-unknown | llvm-nm - | FileCheck %s
+// CHECK: t a
+// CHECK: T a.dyndbg.[[hash:[A-Z0-9]+]]
+// CHECK: T b
+// CHECK: U c
+// CHECK: t d
+// CHECK: T d.dyndbg.[[hash]]
+// CHECK: B g
+
+int g;
+int c();
+
+__attribute__((always_inline))
+static inline int d() { return c(); }
+
+__attribute__((always_inline))
+static int a() { return g; }
+
+int b() { return a() + d() ;}
diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/lit.local.cfg b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/lit.local.cfg
new file mode 100644
index 0000000000000..bf8bd32700a9d
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/lit.local.cfg
@@ -0,0 +1,4 @@
+# These tests require x86 in order to inspect the inner object.
+# FIXME: These tests are quite broad.
+if "x86-registered-target" not in config.available_features:
+    config.unsupported = True
diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/lit.local.cfg b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/lit.local.cfg
new file mode 100644
index 0000000000000..d36760917851d
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/lit.local.cfg
@@ -0,0 +1,3 @@
+# This test wants X86 support without aarch64 support.
+if "x86-registered-target" not in config.available_features or "aarch64-registered-target" in config.available_features:
+    config.unsupported = True
diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/no-target.c b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/no-target.c
new file mode 100644
index 0000000000000..b5af3a3b7ac9c
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/no-target.c
@@ -0,0 +1,14 @@
+// Check we get a warning if -fdynamic-debugging is specified for an
+// unsupported target. Dynamic debugging currently emits the inner module as
+// an object regardless of output flags (e.g. -emit-llvm).
+
+// RUN: %clang -cc1 %s -emit-llvm -debug-info-kind=limited -fdynamic-debugging -o - -triple aarch64-unknown-unknown 2>&1  | FileCheck %s --check-prefix=WITHOUT_TARGET
+// WITHOUT_TARGET: warning: ignoring -fdynamic-debugging: unable to create target: 'No available targets are compatible with triple "aarch64-unknown-unknown"'
+// WITHOUT_TARGET-NOT: .debug_llvm_dyndbg
+
+// Prevent rotten green test by checking we do see .debug_llvm_dyndbg otherwise.
+// RUN: %clang -cc1 %s -emit-obj -debug-info-kind=limited -fdynamic-debugging -o - -triple x86_64-unknown-unknown 2>&1 | FileCheck %s --check-prefix=WITH_TARGET
+// WITH_TARGET-NOT: ignoring -fdynamic-debugging:
+// WITH_TARGET: .debug_llvm_dyndbg
+
+int g;
diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c
new file mode 100644
index 0000000000000..2f0f9a95c199a
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c
@@ -0,0 +1,13 @@
+// By default LLVM gives this section SHF_EXCLUDE, which we don't want.
+
+// RUN: %clang -cc1 %s -emit-obj -debug-info-kind=limited -fdynamic-debugging -o - -triple x86_64-unknown-unknown | llvm-readelf --section-details - \
+// RUN: | FileCheck %s
+//             [Nr] Name
+// CHECK:      .debug_llvm_dyndbg
+//             Type     Address          Off           Size          ES Lk Inf Al
+// CHECK-NEXT: PROGBITS 0000000000000000 {{[0-9a-z]+}} {{[0-9a-z]+}} 00 0  0   1
+//             Flags
+// CHECK-NEXT: [0000000000000000]: {{$}}
+
+int g;
+int b() { return g; }
diff --git a/clang/test/DebugInfo/DynamicDebugging/attr-outer-no-specialization.c b/clang/test/DebugInfo/DynamicDebugging/attr-outer-no-specialization.c
new file mode 100644
index 0000000000000..94fe0b7499df0
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/attr-outer-no-specialization.c
@@ -0,0 +1,7 @@
+// RUN: %clang -cc1 -triple %itanium_abi_triple %s -debug-info-kind=limited -fdynamic-debugging -o - \
+// RUN:   -emit-llvm --discard-dynamic-debugging-debug-module \
+// RUN: | FileCheck %s
+
+// CHECK: define dso_local i32 @f() #0
+// CHECK: attributes #0 = {{{.*}}"no-func-spec"{{.*}}}
+int f() { return 0; }
diff --git a/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad-unsupported.c b/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad-unsupported.c
new file mode 100644
index 0000000000000..5d03e43109725
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad-unsupported.c
@@ -0,0 +1,9 @@
+// REQUIRES: !x86-registered-target
+// This test should trip to remind that tail-padding support should be added
+// for targets as dynamic debugging support is expanded.
+// RUN: %clang -cc1 %s -triple %itanium_abi_triple -debug-info-kind=constructor -fdynamic-debugging -o - \
+// RUN:    -emit-llvm --discard-dynamic-debugging-debug-module \
+// RUN: | FileCheck %s
+
+// CHECK: "tail-pad-to-size"
+int f() { return 0; }
diff --git a/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad.c b/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad.c
new file mode 100644
index 0000000000000..045374a34b936
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad.c
@@ -0,0 +1,10 @@
+// RUN: %clang -cc1 %s -triple %itanium_abi_triple -debug-info-kind=constructor -fdynamic-debugging -o - \
+// RUN:    -emit-llvm --discard-dynamic-debugging-debug-module \
+// RUN: | FileCheck %s --check-prefix=X86
+
+/// FIXME: Add negative tests for other targets (if in doubt, don't tail-pad).
+
+/// Pad functions to minimum of 5 bytes for insertion of 32 rel jump.
+// X86: define dso_local i32 @f() #0
+// X86: attributes #0 = {{{.*}}"tail-pad-to-size"="5"{{.*}}"tail-pad-value"="144"{{.*}}}
+int f() { return 0; }
diff --git a/clang/test/DebugInfo/DynamicDebugging/compiler-used.cpp b/clang/test/DebugInfo/DynamicDebugging/compiler-used.cpp
new file mode 100644
index 0000000000000..25e1eec4bd84f
--- /dev/null
+++ b/clang/test/DebugInfo/DynamicDebugging/compiler-used.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang -cc1 -triple %itanium_abi_triple %s -debug-info-kind=limited -fdynamic-debugging -o %t \
+// RUN:    -emit-llvm --save-dynamic-debugging-temps --discard-dynamic-debugging-debug-module
+// RUN: FileCheck %s --check-prefix=OUTER < %t.dyndbg.2.outer.ll
+
+// Test discardable symbols are added to the @llvm.compiler.used global,
+// which prevents them being discarded (including b...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/194860


More information about the cfe-commits mailing list