-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[flang][debug] handle inlined dummy_scope after #167489 #168039
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
Conversation
|
@llvm/pr-subscribers-flang-fir-hlfir Author: None (jeanPerier) Changes#167489 did not work properly when MLIR inlining is enabled (experimental in flang, enabled with The reason is that inlining will cause several After #167489, the debug info pass creates argument debug info for all fir.declare with a fir.dummy_scope. This causes arguments from inlined calls to appear as argument of the procedure where the call was inlined. To avoid this, only consider that fir.declare are arguments of the current function if their fir.dummy_scope is the first one created in the function (fir.dummy_scope cannot be reorder because they have write effects to the debug memory ressource, and the fir.dummy_scope of the current functions is always emitted before any calls are lowered, so before any fir.dummy_scope are inlined). Here is an example that was broken with Full diff: https://github.com/llvm/llvm-project/pull/168039.diff 2 Files Affected:
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 00633b4104b6c..b21cb85e1256b 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -53,7 +53,7 @@ class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scopeAttr,
fir::DebugTypeGenerator &typeGen,
- mlir::SymbolTable *symbolTable);
+ mlir::SymbolTable *symbolTable, mlir::Value dummyScope);
public:
AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
@@ -206,7 +206,8 @@ void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scopeAttr,
fir::DebugTypeGenerator &typeGen,
- mlir::SymbolTable *symbolTable) {
+ mlir::SymbolTable *symbolTable,
+ mlir::Value dummyScope) {
mlir::MLIRContext *context = &getContext();
mlir::OpBuilder builder(context);
auto result = fir::NameUniquer::deconstruct(declOp.getUniqName());
@@ -230,7 +231,7 @@ void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
// Get the dummy argument position from the explicit attribute.
unsigned argNo = 0;
- if (declOp.getDummyScope()) {
+ if (dummyScope && declOp.getDummyScope() == dummyScope) {
if (auto argNoOpt = declOp.getDummyArgNo())
argNo = *argNoOpt;
}
@@ -610,6 +611,21 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
addTargetOpDISP(/*lineTableOnly=*/false, entities);
+ // Find the first dummy_scope definition. This is the one of the current
+ // function. The other ones may come from inlined calls. The variables inside
+ // those inlined calls should not be identified as arguments of the current
+ // function.
+ mlir::Value dummyScope;
+ funcOp.walk([&](fir::UndefOp undef) -> mlir::WalkResult {
+ // TODO: delay fir.dummy_scope translation to undefined until
+ // codegeneration. This is nicer and safer to match.
+ if (llvm::isa<fir::DummyScopeType>(undef.getType())) {
+ dummyScope = undef;
+ return mlir::WalkResult::interrupt();
+ }
+ return mlir::WalkResult::advance();
+ });
+
funcOp.walk([&](fir::cg::XDeclareOp declOp) {
mlir::LLVM::DISubprogramAttr spTy = spAttr;
if (auto tOp = declOp->getParentOfType<mlir::omp::TargetOp>()) {
@@ -619,7 +635,7 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
spTy = sp;
}
}
- handleDeclareOp(declOp, fileAttr, spTy, typeGen, symbolTable);
+ handleDeclareOp(declOp, fileAttr, spTy, typeGen, symbolTable, dummyScope);
});
// commonBlockMap ensures that we don't create multiple DICommonBlockAttr of
// the same name in one function. But it is ok (rather required) to create
diff --git a/flang/test/Transforms/debug-dummy-argument-inline.fir b/flang/test/Transforms/debug-dummy-argument-inline.fir
new file mode 100644
index 0000000000000..6b3a0ee4a7c18
--- /dev/null
+++ b/flang/test/Transforms/debug-dummy-argument-inline.fir
@@ -0,0 +1,36 @@
+// Tests that inlined calls arguments are not mistaken for the arguments of the
+// procedure where the calls were inlined.
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s -o - | FileCheck %s
+
+!CHECK: #di_local_variable = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file, line = 6, arg = 1, type = #di_basic_type>
+!CHECK: #di_local_variable1 = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file, line = 1, type = #di_basic_type>
+
+func.func @foo_(%arg0: !fir.ref<i32> {fir.bindc_name = "i"} loc("debug-dummy-argument-inline.f90":5:1)) attributes {fir.internal_name = "_QPfoo"} {
+ %0 = fir.undefined !fir.dscope loc(#loc5)
+ %1 = fircg.ext_declare %arg0 dummy_scope %0 arg 1 {uniq_name = "_QFfooEi"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc6)
+ %2 = fir.undefined !fir.dscope loc(#loc11)
+ %3 = fircg.ext_declare %1 dummy_scope %2 arg 1 {uniq_name = "_QFbarEi"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc12)
+ fir.call @buzz_(%3) fastmath<contract> : (!fir.ref<i32>) -> () loc(#loc13)
+ %4 = fir.undefined !fir.dscope loc(#loc14)
+ %5 = fircg.ext_declare %1 dummy_scope %4 arg 1 {uniq_name = "_QFbarEi"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc15)
+ fir.call @buzz_(%5) fastmath<contract> : (!fir.ref<i32>) -> () loc(#loc16)
+ return loc(#loc9)
+} loc(#loc5)
+func.func private @buzz_(!fir.ref<i32>) attributes {fir.internal_name = "_QPbuzz"} loc(#loc10)
+#loc = loc("debug-dummy-argument-inline.f90":0:0)
+#loc1 = loc("debug-dummy-argument-inline.f90":1:1)
+#loc2 = loc("debug-dummy-argument-inline.f90":2:14)
+#loc3 = loc("debug-dummy-argument-inline.f90":3:3)
+#loc4 = loc("debug-dummy-argument-inline.f90":4:1)
+#loc5 = loc("debug-dummy-argument-inline.f90":5:1)
+#loc6 = loc("debug-dummy-argument-inline.f90":6:14)
+#loc7 = loc("debug-dummy-argument-inline.f90":7:3)
+#loc8 = loc("debug-dummy-argument-inline.f90":8:3)
+#loc9 = loc("debug-dummy-argument-inline.f90":9:1)
+#loc10 = loc("debug-dummy-argument-inline.f90":3:8)
+#loc11 = loc(callsite(#loc1 at #loc7))
+#loc12 = loc(callsite(#loc2 at #loc7))
+#loc13 = loc(callsite(#loc3 at #loc7))
+#loc14 = loc(callsite(#loc1 at #loc8))
+#loc15 = loc(callsite(#loc2 at #loc8))
+#loc16 = loc(callsite(#loc3 at #loc8))
|
tblah
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. LGTM
#167489 did not work properly when MLIR inlining is enabled (experimental in flang, enabled with
-mllvm -inline-all).The reason is that inlining will cause several
fir.dummy_scopeto coexist inside a samefunc.func(fir.dummy_scopeof inlinedfunc.funcare preserved in order to preserve the relationship between arguments of the inlined call for better aliasing deductions).After #167489, the debug info pass creates argument debug info for all fir.declare with a fir.dummy_scope. This causes arguments from inlined calls to appear as argument of the procedure where the call was inlined.
To avoid this, only consider that fir.declare are arguments of the current function if their fir.dummy_scope is the first one created in the function (fir.dummy_scope cannot be reorder because they have write effects to the debug memory ressource, and the fir.dummy_scope of the current functions is always emitted before any calls are lowered, so before any fir.dummy_scope are inlined).
Here is an example that was broken with
flang -mllvm -inline-all -g