-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[flang][debug] Add debug type support for procedure pointers #166764
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
Fixes llvm#161223 Procedure pointers in Fortran were generating incorrect debug type information, showing as 'integer' in GDB instead of the actual procedure signature.
|
@llvm/pr-subscribers-flang-fir-hlfir Author: Abid Qadeer (abidh) ChangesFixes #161223 Procedure pointers in Fortran were generating incorrect debug type information, showing as 'integer' in GDB instead of the actual procedure signature. Full diff: https://github.com/llvm/llvm-project/pull/166764.diff 3 Files Affected:
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index e1e6125fc348b..ed31746bf8dea 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -718,6 +718,30 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr,
return convertRecordType(recTy, fileAttr, scope, declOp);
} else if (auto tupleTy = mlir::dyn_cast_if_present<mlir::TupleType>(Ty)) {
return convertTupleType(tupleTy, fileAttr, scope, declOp);
+ } else if (mlir::isa<mlir::FunctionType>(Ty)) {
+ // Handle function types - these represent procedure pointers after the
+ // BoxedProcedure pass has run and unwrapped the fir.boxproc type
+ llvm::SmallVector<mlir::LLVM::DITypeAttr> types;
+
+ auto funcTy = mlir::cast<mlir::FunctionType>(Ty);
+ // Add return type (or void if no return type)
+ if (funcTy.getNumResults() == 0)
+ types.push_back(mlir::LLVM::DINullTypeAttr::get(context));
+ else
+ types.push_back(
+ convertType(funcTy.getResult(0), fileAttr, scope, declOp));
+
+ for (mlir::Type paramTy : funcTy.getInputs())
+ types.push_back(convertType(paramTy, fileAttr, scope, declOp));
+
+ auto subroutineTy = mlir::LLVM::DISubroutineTypeAttr::get(
+ context, /*callingConvention=*/0, types);
+
+ return mlir::LLVM::DIDerivedTypeAttr::get(
+ context, llvm::dwarf::DW_TAG_pointer_type,
+ mlir::StringAttr::get(context, ""), subroutineTy,
+ /*sizeInBits=*/ptrSize * 8, /*alignInBits=*/0, /*offset=*/0,
+ /*optional<address space>=*/std::nullopt, /*extra data=*/nullptr);
} else if (auto refTy = mlir::dyn_cast_if_present<fir::ReferenceType>(Ty)) {
auto elTy = refTy.getEleTy();
return convertPointerLikeType(elTy, fileAttr, scope, declOp,
diff --git a/flang/test/Transforms/debug-proc-ptr-e2e.f90 b/flang/test/Transforms/debug-proc-ptr-e2e.f90
new file mode 100644
index 0000000000000..aa89160b7c8f9
--- /dev/null
+++ b/flang/test/Transforms/debug-proc-ptr-e2e.f90
@@ -0,0 +1,26 @@
+! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
+
+program test_proc_ptr
+ implicit none
+ procedure(fun1), pointer :: fun_ptr
+
+ fun_ptr => fun1
+ print *, fun_ptr(3)
+
+contains
+ integer function fun1(x)
+ integer :: x
+ fun1 = x + 1
+ end function fun1
+end program test_proc_ptr
+
+! Check that fun_ptr is declared with correct type
+! CHECK-DAG: ![[INT:.*]] = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)
+! CHECK-DAG: ![[PTR_INT:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[INT]], size: 64)
+
+! Check that fun_ptr variable is a pointer to a subroutine type
+! The order is: DILocalVariable -> pointer type -> subroutine type -> {return, params}
+! CHECK-DAG: ![[FUN_PTR_VAR:.*]] = !DILocalVariable(name: "fun_ptr", {{.*}}type: ![[PROC_PTR:[0-9]+]]
+! CHECK-DAG: ![[PROC_PTR]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[SUBR_TYPE:[0-9]+]], size: 64)
+! CHECK-DAG: ![[SUBR_TYPE]] = !DISubroutineType(types: ![[SUBR_TYPES:[0-9]+]])
+! CHECK-DAG: ![[SUBR_TYPES]] = !{![[INT]], ![[PTR_INT]]}
diff --git a/flang/test/Transforms/debug-proc-ptr.fir b/flang/test/Transforms/debug-proc-ptr.fir
new file mode 100644
index 0000000000000..2963557786907
--- /dev/null
+++ b/flang/test/Transforms/debug-proc-ptr.fir
@@ -0,0 +1,41 @@
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
+
+module {
+ func.func @_QQmain() attributes {fir.bindc_name = "test"} {
+ %0 = fir.alloca (!fir.ref<i32>) -> i32 {bindc_name = "fun_ptr", uniq_name = "_QFEfun_ptr"}
+ %1 = fircg.ext_declare %0 {uniq_name = "_QFEfun_ptr"} : (!fir.ref<(!fir.ref<i32>) -> i32>) -> !fir.ref<(!fir.ref<i32>) -> i32> loc(#loc1)
+
+ // Procedure pointer with no return: procedure(sub1), pointer :: sub_ptr
+ %2 = fir.alloca () -> () {bindc_name = "sub_ptr", uniq_name = "_QFEsub_ptr"}
+ %3 = fircg.ext_declare %2 {uniq_name = "_QFEsub_ptr"} : (!fir.ref<() -> ()>) -> !fir.ref<() -> ()> loc(#loc2)
+
+ // Procedure pointer with multiple args: procedure(func2), pointer :: func_ptr
+ %4 = fir.alloca (!fir.ref<i32>, !fir.ref<f64>) -> f32 {bindc_name = "func_ptr", uniq_name = "_QFEfunc_ptr"}
+ %5 = fircg.ext_declare %4 {uniq_name = "_QFEfunc_ptr"} : (!fir.ref<(!fir.ref<i32>, !fir.ref<f64>) -> f32>) -> !fir.ref<(!fir.ref<i32>, !fir.ref<f64>) -> f32> loc(#loc3)
+
+ return
+ } loc(#loc)
+}
+#loc = loc("test.f90":1:1)
+#loc1 = loc("test.f90":2:30)
+#loc2 = loc("test.f90":3:30)
+#loc3 = loc("test.f90":4:30)
+
+// CHECK-DAG: #[[INT:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "integer", sizeInBits = 32, encoding = DW_ATE_signed>
+// CHECK-DAG: #[[REAL32:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "real", sizeInBits = 32, encoding = DW_ATE_float>
+// CHECK-DAG: #[[REAL:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "real(kind=8)", sizeInBits = 64, encoding = DW_ATE_float>
+
+// CHECK-DAG: #[[PTR_INT:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #[[INT]]{{.*}}>
+// CHECK-DAG: #[[PTR_REAL:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #[[REAL]]{{.*}}>
+
+// CHECK-DAG: #[[SUB1:.*]] = #llvm.di_subroutine_type<types = #[[INT]], #[[PTR_INT]]>
+// CHECK-DAG: #[[PTR_SUB1:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #[[SUB1]]{{.*}}>
+// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "fun_ptr"{{.*}}type = #[[PTR_SUB1]]{{.*}}>
+
+// CHECK-DAG: #di_subroutine_type{{.*}} = #llvm.di_subroutine_type<types = #di_null_type>
+// CHECK-DAG: #di_local_variable{{.*}} = #llvm.di_local_variable<{{.*}}name = "sub_ptr"{{.*}}type = #di_derived_type{{.*}}>
+// CHECK-DAG: #di_derived_type{{.*}} = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #di_subroutine_type{{.*}}{{.*}}>
+
+// CHECK-DAG: #[[SUB3:.*]] = #llvm.di_subroutine_type<types = #[[REAL32]], #[[PTR_INT]], #[[PTR_REAL]]>
+// CHECK-DAG: #[[PTR_SUB3:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #[[SUB3]]{{.*}}>
+// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "func_ptr"{{.*}}type = #[[PTR_SUB3]]{{.*}}>
|
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.
Thanks @abidh
| @@ -0,0 +1,26 @@ | |||
| ! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s | |||
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.
Please move this test in the test/Integration folder next to the other debug test using -emit-llvm.
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.
Thanks. I somehow failed to see this. Fixed now.
| } else if (auto tupleTy = mlir::dyn_cast_if_present<mlir::TupleType>(Ty)) { | ||
| return convertTupleType(tupleTy, fileAttr, scope, declOp); | ||
| } else if (mlir::isa<mlir::FunctionType>(Ty)) { | ||
| // Handle function types - these represent procedure pointers after the |
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.
nit: I think dummy procedures will also fall here now when converting function types with dummy procedure arguments (flang only gives them the () -> () type because they are usually implicitly typed, but with your fix they should at least appear as function address in the debug info now).
All that to say I would just add a mention to dummy procedures to this comment (and maybe a test).
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.
I have added a comment. I was trying to add a test but noticed that somehow DeclareOp is not being generated for the dummy procedure. I will investigate that separately.
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.
Yes it is not because as far as lowering is concerned, it is not a variable/entity. But I imagine debug info needs to map the name. I agree this is out of the scope of your PR.
With your change, at least the debug type for the procedure with debug argument should be correct now.
subroutine foo(bar)
external :: bar
end subroutine
was:
!4 = distinct !DISubprogram(name: "foo", linkageName: "foo_", scope: !1, file: !1, line: 1, type: !5, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
!5 = !DISubroutineType(cc: DW_CC_normal, types: !6)
!6 = !{null, !7}
!7 = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)
and I think your patch is fixing !7
|
All the flang tests on windows are passing. The CI is failing on some python issue after that. |
Fixes #161223
Procedure pointers in Fortran were generating incorrect debug type information, showing as 'integer' in GDB instead of the actual procedure signature.