[flang-commits] [flang] [flang][debug] Only import debug info for specified renamed variables (PR #194926)

via flang-commits flang-commits at lists.llvm.org
Thu May 7 09:32:48 PDT 2026


https://github.com/timsmith78 updated https://github.com/llvm/llvm-project/pull/194926

>From 07623b498311cac4fc062c0a0da5f190bec26eb1 Mon Sep 17 00:00:00 2001
From: Timothy Smith <timothy.smith at hpe.com>
Date: Thu, 23 Apr 2026 11:58:41 -0500
Subject: [PATCH 1/4] Only import debug info for specified renamed variables

Given the following:

USE mod, ONLY : alias => var

Currently, flang will create a DW_TAG_imported_module tag for mod when
it should only be creating a list of DW_TAG_imported_declaration tags
for each imported variable.  This causes erroneous variables from mod to be
visible in the debugger with undefined information.

Fixes #180836
---
 flang/lib/Lower/PFTBuilder.cpp                  | 1 +
 flang/lib/Optimizer/Transforms/AddDebugInfo.cpp | 8 ++++++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index afabb6b29f4f1..367b516bdcdac 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -253,6 +253,7 @@ class PFTBuilder {
                             std::string localName{
                                 std::get<0>(names.t).source.ToString()};
                             stmt.renames.push_back(localName);
+                            stmt.onlyNames.push_back(localName);
                           },
                           [&](const parser::Rename::Operators &) {
                             // Operator renames - not commonly needed for debug
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 65c8508de9c9f..167ce0c5f0acd 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -823,8 +823,12 @@ void AddDebugInfoPass::handleOnlyClause(
     fir::UseStmtOp useOp, mlir::LLVM::DISubprogramAttr spAttr,
     mlir::LLVM::DIFileAttr fileAttr, mlir::SymbolTable *symbolTable,
     llvm::DenseSet<mlir::LLVM::DIImportedEntityAttr> &importedModules) {
+
+  auto onlySymbols = useOp.getOnlySymbols();
+  auto renames = useOp.getRenames();
+
   // Process ONLY symbols (without renames)
-  if (auto onlySymbols = useOp.getOnlySymbols()) {
+  if (onlySymbols && !renames) {
     for (mlir::Attribute attr : *onlySymbols) {
       auto symbolRef = mlir::cast<mlir::FlatSymbolRefAttr>(attr);
       if (auto importedDecl = createImportedDeclForGlobal(
@@ -835,7 +839,7 @@ void AddDebugInfoPass::handleOnlyClause(
   }
 
   // Process renames within ONLY clause
-  if (auto renames = useOp.getRenames()) {
+  if (renames) {
     for (auto attr : *renames) {
       auto renameAttr = mlir::cast<fir::UseRenameAttr>(attr);
       if (auto importedDecl = createImportedDeclForGlobal(

>From 6943088b3f8b7a4fa1caaa2dc3953216f0786bc7 Mon Sep 17 00:00:00 2001
From: Timothy Smith <timothy.smith at hpe.com>
Date: Fri, 1 May 2026 15:01:26 -0500
Subject: [PATCH 2/4] Fix cases where USE, ONLY clause contains mix of renames
 and non-renames

---
 .../lib/Optimizer/Transforms/AddDebugInfo.cpp | 20 +++++++++++++++++--
 flang/test/Integration/debug-use-stmt.f90     |  2 ++
 flang/test/Lower/debug-use-stmt.f90           |  4 ++--
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 167ce0c5f0acd..09efc27f93368 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -828,10 +828,26 @@ void AddDebugInfoPass::handleOnlyClause(
   auto renames = useOp.getRenames();
 
   // Process ONLY symbols (without renames)
-  if (onlySymbols && !renames) {
+  if (onlySymbols) {
     for (mlir::Attribute attr : *onlySymbols) {
       auto symbolRef = mlir::cast<mlir::FlatSymbolRefAttr>(attr);
-      if (auto importedDecl = createImportedDeclForGlobal(
+
+      // Check if this symbol is also in renames, if so skip it
+      bool isInRenames = false;
+      if (renames) {
+        for (auto renameAttr : *renames) {
+          auto rename = mlir::cast<fir::UseRenameAttr>(renameAttr);
+          if (rename.getSymbol().getValue() == symbolRef.getValue()) {
+            isInRenames = true;
+            break;
+          }
+        }
+      }
+
+    if (isInRenames)
+      continue;
+
+    if (auto importedDecl = createImportedDeclForGlobal(
               symbolRef.getValue(), spAttr, fileAttr, mlir::StringAttr(),
               symbolTable))
         importedModules.insert(*importedDecl);
diff --git a/flang/test/Integration/debug-use-stmt.f90 b/flang/test/Integration/debug-use-stmt.f90
index db20dd94e85d1..50a70da3941f8 100644
--- a/flang/test/Integration/debug-use-stmt.f90
+++ b/flang/test/Integration/debug-use-stmt.f90
@@ -26,6 +26,8 @@ program test_use
 
 ! CHECK-DAG: [[SP:![0-9]+]] = distinct !DISubprogram(name: "TEST_USE", linkageName: "_QQmain"{{.*}}retainedNodes:
 
+! Check that the full testmod module is not imported
+! CHECK-NOT: !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[SP]], entity: [[TESTMOD]]
 ! Check testmod imports: var_b directly (no rename), var_d as rename of var_c
 ! CHECK-DAG: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[SP]], entity: [[VAR_B]],{{.*}}file:{{.*}}line:
 ! CHECK-DAG: !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "var_d", scope: [[SP]], entity: [[VAR_C]],{{.*}}file:{{.*}}line:
diff --git a/flang/test/Lower/debug-use-stmt.f90 b/flang/test/Lower/debug-use-stmt.f90
index 293b38c78e17a..7404f7da932ea 100644
--- a/flang/test/Lower/debug-use-stmt.f90
+++ b/flang/test/Lower/debug-use-stmt.f90
@@ -73,8 +73,8 @@ subroutine test_only_rename()
 ! NO_DEBUG-NOT: fir.use_stmt
 
 ! WITH_DEBUG-LABEL: func.func @_QPtest_only_rename()
-! WITH_DEBUG-DAG: fir.use_stmt "mod1" only_symbols{{\[}}[@_QMmod1Ec]] renames{{\[}}[#fir.use_rename<"local_b", @_QMmod1Eb>, #fir.use_rename<"local_a", @_QMmod1Ea>]]
-! WITH_DEBUG-DAG: fir.use_stmt "mod2" renames{{\[}}[#fir.use_rename<"local_x", @_QMmod2Ex>, #fir.use_rename<"local_y", @_QMmod2Ey>]]
+! WITH_DEBUG-DAG: fir.use_stmt "mod1" only_symbols{{\[}}[@_QMmod1Eb, @_QMmod1Ec, @_QMmod1Ea]] renames{{\[}}[#fir.use_rename<"local_b", @_QMmod1Eb>, #fir.use_rename<"local_a", @_QMmod1Ea>]]
+! WITH_DEBUG-DAG: fir.use_stmt "mod2" only_symbols{{\[}}[@_QMmod2Ex, @_QMmod2Ey]] renames{{\[}}[#fir.use_rename<"local_x", @_QMmod2Ex>, #fir.use_rename<"local_y", @_QMmod2Ey>]]
 
 ! NO_DEBUG-LABEL: func.func @_QPtest_only_rename()
 ! NO_DEBUG-NOT: fir.use_stmt

>From abba9362c3ebca64be6a604d3179ef09e67040c6 Mon Sep 17 00:00:00 2001
From: Timothy Smith <timothy.smith at hpe.com>
Date: Fri, 1 May 2026 16:18:03 -0500
Subject: [PATCH 3/4] Fix formatting

---
 flang/lib/Optimizer/Transforms/AddDebugInfo.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 09efc27f93368..e0f572560932f 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -844,10 +844,10 @@ void AddDebugInfoPass::handleOnlyClause(
         }
       }
 
-    if (isInRenames)
-      continue;
+      if (isInRenames)
+        continue;
 
-    if (auto importedDecl = createImportedDeclForGlobal(
+      if (auto importedDecl = createImportedDeclForGlobal(
               symbolRef.getValue(), spAttr, fileAttr, mlir::StringAttr(),
               symbolTable))
         importedModules.insert(*importedDecl);

>From ba077b8caa13fd77b83807844eeaf445c56efe8b Mon Sep 17 00:00:00 2001
From: Timothy Smith <timothy.smith at hpe.com>
Date: Thu, 7 May 2026 11:31:01 -0500
Subject: [PATCH 4/4] Replace quadratic algorithm with more efficient
 flag-based algorithm

---
 flang/include/flang/Optimizer/Dialect/FIROps.td |  7 ++++++-
 flang/include/flang/Semantics/scope.h           |  1 +
 flang/lib/Lower/Bridge.cpp                      |  4 +++-
 flang/lib/Lower/PFTBuilder.cpp                  |  2 +-
 flang/lib/Optimizer/Transforms/AddDebugInfo.cpp | 17 +----------------
 flang/test/Lower/debug-use-stmt.f90             |  4 ++--
 6 files changed, 14 insertions(+), 21 deletions(-)

diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 453379b010075..14dabbd123dd9 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -3314,12 +3314,14 @@ def fir_UseStmtOp
   }];
 
   let arguments = (ins StrAttr:$module_name,
-      OptionalAttr<ArrayAttr>:$only_symbols, OptionalAttr<ArrayAttr>:$renames);
+      OptionalAttr<ArrayAttr>:$only_symbols, OptionalAttr<ArrayAttr>:$renames,
+      DefaultValuedAttr<BoolAttr, "false">:$hasOnlyWithRenames);
 
   let assemblyFormat = [{
     $module_name
     (`only_symbols` `[` $only_symbols^ `]`)?
     (`renames` `[` $renames^ `]`)?
+    (`hasOnlyWithRenames` $hasOnlyWithRenames^)?
     attr-dict
   }];
 
@@ -3332,6 +3334,9 @@ def fir_UseStmtOp
 
     /// Returns true if this imports the entire module (no ONLY clause)
     bool importsAll() { return !hasOnlyClause(); }
+
+    /// Returns true if this USE statement has both ONLY clause and renames
+    bool hasOnlyWithRenames() { return getHasOnlyWithRenames(); }
   }];
 }
 
diff --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h
index 16553fe692e79..7cab6e2122319 100644
--- a/flang/include/flang/Semantics/scope.h
+++ b/flang/include/flang/Semantics/scope.h
@@ -60,6 +60,7 @@ struct PreservedUseStmt {
   std::string moduleName;
   std::vector<std::string> onlyNames; // For USE ONLY
   std::vector<std::string> renames; // local_name (resolved via GetUltimate)
+  bool hasOnlyWithRenames{false}; // true if there are renames in an ONLY clause
 
   PreservedUseStmt(std::string modName) : moduleName(std::move(modName)) {}
 };
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index cf9da627c19f1..36b9842c831a8 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -283,9 +283,11 @@ static void emitUseStmtOp(Fortran::lower::AbstractConverter &converter,
   mlir::ArrayAttr renamesAttr =
       renameAttrs.empty() ? mlir::ArrayAttr()
                           : mlir::ArrayAttr::get(context, renameAttrs);
+  mlir::BoolAttr hasOnlyWithRenamesAttr =
+      mlir::BoolAttr::get(context, stmt.hasOnlyWithRenames);
 
   fir::UseStmtOp::create(builder, loc, moduleNameAttr, onlySymbolsAttr,
-                         renamesAttr);
+                         renamesAttr, hasOnlyWithRenamesAttr);
 }
 
 /// Emit fir.module_debug_imports for USE statements in a module.
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 367b516bdcdac..a7cf64ccb583b 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -253,7 +253,7 @@ class PFTBuilder {
                             std::string localName{
                                 std::get<0>(names.t).source.ToString()};
                             stmt.renames.push_back(localName);
-                            stmt.onlyNames.push_back(localName);
+                            stmt.hasOnlyWithRenames = true;
                           },
                           [&](const parser::Rename::Operators &) {
                             // Operator renames - not commonly needed for debug
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index e0f572560932f..ceb79dc110d0a 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -832,21 +832,6 @@ void AddDebugInfoPass::handleOnlyClause(
     for (mlir::Attribute attr : *onlySymbols) {
       auto symbolRef = mlir::cast<mlir::FlatSymbolRefAttr>(attr);
 
-      // Check if this symbol is also in renames, if so skip it
-      bool isInRenames = false;
-      if (renames) {
-        for (auto renameAttr : *renames) {
-          auto rename = mlir::cast<fir::UseRenameAttr>(renameAttr);
-          if (rename.getSymbol().getValue() == symbolRef.getValue()) {
-            isInRenames = true;
-            break;
-          }
-        }
-      }
-
-      if (isInRenames)
-        continue;
-
       if (auto importedDecl = createImportedDeclForGlobal(
               symbolRef.getValue(), spAttr, fileAttr, mlir::StringAttr(),
               symbolTable))
@@ -928,7 +913,7 @@ void AddDebugInfoPass::expandUseStmtForDebug(
                             /*decl=*/true);
 
   llvm::DenseSet<mlir::LLVM::DIImportedEntityAttr> importedModules;
-  if (useOp.hasOnlyClause())
+  if (useOp.hasOnlyClause() || useOp.getHasOnlyWithRenames())
     handleOnlyClause(useOp, spAttr, fileAttr, symbolTable, importedModules);
   else if (useOp.hasRenames())
     handleRenamesWithoutOnly(useOp, spAttr, modAttr, fileAttr, symbolTable,
diff --git a/flang/test/Lower/debug-use-stmt.f90 b/flang/test/Lower/debug-use-stmt.f90
index 7404f7da932ea..9701d938b5f0b 100644
--- a/flang/test/Lower/debug-use-stmt.f90
+++ b/flang/test/Lower/debug-use-stmt.f90
@@ -73,8 +73,8 @@ subroutine test_only_rename()
 ! NO_DEBUG-NOT: fir.use_stmt
 
 ! WITH_DEBUG-LABEL: func.func @_QPtest_only_rename()
-! WITH_DEBUG-DAG: fir.use_stmt "mod1" only_symbols{{\[}}[@_QMmod1Eb, @_QMmod1Ec, @_QMmod1Ea]] renames{{\[}}[#fir.use_rename<"local_b", @_QMmod1Eb>, #fir.use_rename<"local_a", @_QMmod1Ea>]]
-! WITH_DEBUG-DAG: fir.use_stmt "mod2" only_symbols{{\[}}[@_QMmod2Ex, @_QMmod2Ey]] renames{{\[}}[#fir.use_rename<"local_x", @_QMmod2Ex>, #fir.use_rename<"local_y", @_QMmod2Ey>]]
+! WITH_DEBUG-DAG: fir.use_stmt "mod1" only_symbols{{\[}}[@_QMmod1Ec]] renames{{\[}}[#fir.use_rename<"local_b", @_QMmod1Eb>, #fir.use_rename<"local_a", @_QMmod1Ea>]] hasOnlyWithRenames true
+! WITH_DEBUG-DAG: fir.use_stmt "mod2" renames{{\[}}[#fir.use_rename<"local_x", @_QMmod2Ex>, #fir.use_rename<"local_y", @_QMmod2Ey>]] hasOnlyWithRenames true
 
 ! NO_DEBUG-LABEL: func.func @_QPtest_only_rename()
 ! NO_DEBUG-NOT: fir.use_stmt



More information about the flang-commits mailing list