Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flang][debug] Set scope of internal functions correctly. #99531

Merged
merged 3 commits into from
Jul 25, 2024
Merged

Conversation

abidh
Copy link
Contributor

@abidh abidh commented Jul 18, 2024

The functions internal to subroutine should have the scope set to the parent function. This allows a user to evaluate local variables of parent function when control is stopped in the child.

Fixes #96314

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Jul 18, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 18, 2024

@llvm/pr-subscribers-flang-fir-hlfir

Author: Abid Qadeer (abidh)

Changes

The functions internal to subroutine should have the scope set to the parent function. This allows a user to evaluate local variables of parent function when control is stopped in the child.

Fixes #96314


Full diff: https://github.com/llvm/llvm-project/pull/99531.diff

2 Files Affected:

  • (modified) flang/lib/Optimizer/Transforms/AddDebugInfo.cpp (+21-1)
  • (added) flang/test/Transforms/debug-96314.fir (+26)
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 8bb24fb6c8078..7c9555dd737ab 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -299,9 +299,29 @@ void AddDebugInfoPass::runOnOperation() {
           subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
     }
     unsigned line = getLineFromLoc(l);
-    if (!result.second.modules.empty())
+    if (fir::isInternalProcedure(funcOp)) {
+      // For contained functions, the scope is the parent subroutine.
+      mlir::SymbolRefAttr sym = mlir::cast<mlir::SymbolRefAttr>(
+          funcOp->getAttr(fir::getHostSymbolAttrName()));
+      if (sym) {
+        if (auto func = symbolTable.lookup<mlir::func::FuncOp>(
+                sym.getLeafReference())) {
+          // FIXME: Can there be situation where we process contained function
+          // before the parent?
+          if (debugInfoIsAlreadySet(func.getLoc())) {
+            if (auto fusedLoc = mlir::cast<mlir::FusedLoc>(func.getLoc())) {
+              if (auto spAttr =
+                      mlir::dyn_cast_if_present<mlir::LLVM::DISubprogramAttr>(
+                          fusedLoc.getMetadata()))
+                Scope = spAttr;
+            }
+          }
+        }
+      }
+    } else if (!result.second.modules.empty()) {
       Scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, cuAttr,
                                     line - 1, false);
+    }
 
     auto spAttr = mlir::LLVM::DISubprogramAttr::get(
         context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
diff --git a/flang/test/Transforms/debug-96314.fir b/flang/test/Transforms/debug-96314.fir
new file mode 100644
index 0000000000000..e2d0f24a1105c
--- /dev/null
+++ b/flang/test/Transforms/debug-96314.fir
@@ -0,0 +1,26 @@
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s -o - | FileCheck %s
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
+  func.func @_QMhelperPmod_sub(%arg0: !fir.ref<i32> {fir.bindc_name = "a"} ) {
+    return
+  } loc(#loc1)
+  func.func private @_QMhelperFmod_subPchild1(%arg0: !fir.ref<i32> {fir.bindc_name = "b"} ) attributes {fir.host_symbol = @_QMhelperPmod_sub, llvm.linkage = #llvm.linkage<internal>} {
+    return
+  } loc(#loc2)
+  func.func @global_sub_(%arg0: !fir.ref<i32> {fir.bindc_name = "n"} ) attributes {fir.internal_name = "_QPglobal_sub"} {
+    return
+  } loc(#loc3)
+  func.func private @_QFglobal_subPchild2(%arg0: !fir.ref<i32> {fir.bindc_name = "c"}) attributes {fir.host_symbol = @global_sub_, llvm.linkage = #llvm.linkage<internal>} {
+    return
+  } loc(#loc4)
+}
+
+#loc1 = loc("test.f90":5:1)
+#loc2 = loc("test.f90":15:1)
+#loc3 = loc("test.f90":25:1)
+#loc4 = loc("test.f90":35:1)
+
+// CHECK-DAG: #[[SP1:.*]] = #llvm.di_subprogram<{{.*}}name = "mod_sub"{{.*}}>
+// CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[SP1]], name = "child1"{{.*}}>
+// CHECK-DAG: #[[SP2:.*]] = #llvm.di_subprogram<{{.*}}linkageName = "global_sub_"{{.*}}>
+// CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[SP2]], name = "child2"{{.*}}>

if (sym) {
if (auto func = symbolTable.lookup<mlir::func::FuncOp>(
sym.getLeafReference())) {
// FIXME: Can there be situation where we process contained function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that the current lowering implementation visits (and creates a function declaration) for the parent before the contained function:

// Declare internal procedures

In MLIR, the module is just an operation with a nested region like any other operation. So I presume the order of functions inside of a module is stable (in the same way that the order of operations nested inside of a function is well defined).

However, I wonder if some current or future pass might erase and re-create functions (thereby possibly shuffling their order). Perhaps all of this could be abstracted out into a function which calls itself recursively if the parent is not yet processed. The recursion will be bounded by the level of function nesting and for the reasons outlined above won't happen at all in most cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review. I have moved the function processing in a separate function and now we can make sure that parent is processed before contained subroutine.

abidh added 3 commits July 24, 2024 12:43
The functions internal to subroutine should have the scope set to the
parent function. This allows to evaluate variable in parent when control
is stopped in the child.

Fixes llvm#96314
Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the update!

@abidh abidh merged commit bf76290 into llvm:main Jul 25, 2024
7 checks passed
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
Summary:
The functions internal to subroutine should have the scope set to the
parent function. This allows a user to evaluate local variables of
parent function when control is stopped in the child.

Fixes #96314

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60250527
@pawosm-arm pawosm-arm added this to the LLVM 19.X Release milestone Jul 26, 2024
@pawosm-arm
Copy link
Contributor

/cherry-pick 626022b

llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Jul 26, 2024
Summary:
The functions internal to subroutine should have the scope set to the
parent function. This allows a user to evaluate local variables of
parent function when control is stopped in the child.

Fixes llvm#96314

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:

Differential Revision: https://phabricator.intern.facebook.com/D60250527

(cherry picked from commit 626022b)
@llvmbot
Copy link
Member

llvmbot commented Jul 26, 2024

/pull-request #100727

tru pushed a commit to llvmbot/llvm-project that referenced this pull request Jul 26, 2024
Summary:
The functions internal to subroutine should have the scope set to the
parent function. This allows a user to evaluate local variables of
parent function when control is stopped in the child.

Fixes llvm#96314

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:

Differential Revision: https://phabricator.intern.facebook.com/D60250527

(cherry picked from commit 626022b)
@abidh abidh deleted the 96314 branch August 27, 2024 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang Flang issues not falling into any other category
Projects
Development

Successfully merging this pull request may close these issues.

[flang][debug] Scope of the contained subroutine is not correct.
4 participants