Skip to content

Commit 70f5fd4

Browse files
authored
[flang][debug] Add debug type support for procedure pointers (#166764)
Fixes #161223 Procedure pointers in Fortran were generating incorrect debug type information, showing as 'integer' in GDB instead of the actual procedure signature.
1 parent 210b9a5 commit 70f5fd4

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,31 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr,
718718
return convertRecordType(recTy, fileAttr, scope, declOp);
719719
} else if (auto tupleTy = mlir::dyn_cast_if_present<mlir::TupleType>(Ty)) {
720720
return convertTupleType(tupleTy, fileAttr, scope, declOp);
721+
} else if (mlir::isa<mlir::FunctionType>(Ty)) {
722+
// Handle function types - these represent procedure pointers after the
723+
// BoxedProcedure pass has run and unwrapped the fir.boxproc type, as well
724+
// as dummy procedures (which are represented as function types in FIR)
725+
llvm::SmallVector<mlir::LLVM::DITypeAttr> types;
726+
727+
auto funcTy = mlir::cast<mlir::FunctionType>(Ty);
728+
// Add return type (or void if no return type)
729+
if (funcTy.getNumResults() == 0)
730+
types.push_back(mlir::LLVM::DINullTypeAttr::get(context));
731+
else
732+
types.push_back(
733+
convertType(funcTy.getResult(0), fileAttr, scope, declOp));
734+
735+
for (mlir::Type paramTy : funcTy.getInputs())
736+
types.push_back(convertType(paramTy, fileAttr, scope, declOp));
737+
738+
auto subroutineTy = mlir::LLVM::DISubroutineTypeAttr::get(
739+
context, /*callingConvention=*/0, types);
740+
741+
return mlir::LLVM::DIDerivedTypeAttr::get(
742+
context, llvm::dwarf::DW_TAG_pointer_type,
743+
mlir::StringAttr::get(context, ""), subroutineTy,
744+
/*sizeInBits=*/ptrSize * 8, /*alignInBits=*/0, /*offset=*/0,
745+
/*optional<address space>=*/std::nullopt, /*extra data=*/nullptr);
721746
} else if (auto refTy = mlir::dyn_cast_if_present<fir::ReferenceType>(Ty)) {
722747
auto elTy = refTy.getEleTy();
723748
return convertPointerLikeType(elTy, fileAttr, scope, declOp,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
2+
3+
program test_proc_ptr
4+
implicit none
5+
procedure(fun1), pointer :: fun_ptr
6+
7+
fun_ptr => fun1
8+
print *, fun_ptr(3)
9+
10+
contains
11+
integer function fun1(x)
12+
integer :: x
13+
fun1 = x + 1
14+
end function fun1
15+
end program test_proc_ptr
16+
17+
! Check that fun_ptr is declared with correct type
18+
! CHECK-DAG: ![[INT:.*]] = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)
19+
! CHECK-DAG: ![[PTR_INT:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[INT]], size: 64)
20+
21+
! Check that fun_ptr variable is a pointer to a subroutine type
22+
! The order is: DILocalVariable -> pointer type -> subroutine type -> {return, params}
23+
! CHECK-DAG: ![[FUN_PTR_VAR:.*]] = !DILocalVariable(name: "fun_ptr", {{.*}}type: ![[PROC_PTR:[0-9]+]]
24+
! CHECK-DAG: ![[PROC_PTR]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[SUBR_TYPE:[0-9]+]], size: 64)
25+
! CHECK-DAG: ![[SUBR_TYPE]] = !DISubroutineType(types: ![[SUBR_TYPES:[0-9]+]])
26+
! CHECK-DAG: ![[SUBR_TYPES]] = !{![[INT]], ![[PTR_INT]]}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
2+
3+
module {
4+
func.func @_QQmain() attributes {fir.bindc_name = "test"} {
5+
%0 = fir.alloca (!fir.ref<i32>) -> i32 {bindc_name = "fun_ptr", uniq_name = "_QFEfun_ptr"}
6+
%1 = fircg.ext_declare %0 {uniq_name = "_QFEfun_ptr"} : (!fir.ref<(!fir.ref<i32>) -> i32>) -> !fir.ref<(!fir.ref<i32>) -> i32> loc(#loc1)
7+
8+
// Procedure pointer with no return: procedure(sub1), pointer :: sub_ptr
9+
%2 = fir.alloca () -> () {bindc_name = "sub_ptr", uniq_name = "_QFEsub_ptr"}
10+
%3 = fircg.ext_declare %2 {uniq_name = "_QFEsub_ptr"} : (!fir.ref<() -> ()>) -> !fir.ref<() -> ()> loc(#loc2)
11+
12+
// Procedure pointer with multiple args: procedure(func2), pointer :: func_ptr
13+
%4 = fir.alloca (!fir.ref<i32>, !fir.ref<f64>) -> f32 {bindc_name = "func_ptr", uniq_name = "_QFEfunc_ptr"}
14+
%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)
15+
16+
return
17+
} loc(#loc)
18+
}
19+
#loc = loc("test.f90":1:1)
20+
#loc1 = loc("test.f90":2:30)
21+
#loc2 = loc("test.f90":3:30)
22+
#loc3 = loc("test.f90":4:30)
23+
24+
// CHECK-DAG: #[[INT:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "integer", sizeInBits = 32, encoding = DW_ATE_signed>
25+
// CHECK-DAG: #[[REAL32:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "real", sizeInBits = 32, encoding = DW_ATE_float>
26+
// CHECK-DAG: #[[REAL:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "real(kind=8)", sizeInBits = 64, encoding = DW_ATE_float>
27+
28+
// CHECK-DAG: #[[PTR_INT:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #[[INT]]{{.*}}>
29+
// CHECK-DAG: #[[PTR_REAL:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #[[REAL]]{{.*}}>
30+
31+
// CHECK-DAG: #[[SUB1:.*]] = #llvm.di_subroutine_type<types = #[[INT]], #[[PTR_INT]]>
32+
// CHECK-DAG: #[[PTR_SUB1:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #[[SUB1]]{{.*}}>
33+
// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "fun_ptr"{{.*}}type = #[[PTR_SUB1]]{{.*}}>
34+
35+
// CHECK-DAG: #di_subroutine_type{{.*}} = #llvm.di_subroutine_type<types = #di_null_type>
36+
// CHECK-DAG: #di_local_variable{{.*}} = #llvm.di_local_variable<{{.*}}name = "sub_ptr"{{.*}}type = #di_derived_type{{.*}}>
37+
// CHECK-DAG: #di_derived_type{{.*}} = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #di_subroutine_type{{.*}}{{.*}}>
38+
39+
// CHECK-DAG: #[[SUB3:.*]] = #llvm.di_subroutine_type<types = #[[REAL32]], #[[PTR_INT]], #[[PTR_REAL]]>
40+
// CHECK-DAG: #[[PTR_SUB3:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type{{.*}}baseType = #[[SUB3]]{{.*}}>
41+
// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "func_ptr"{{.*}}type = #[[PTR_SUB3]]{{.*}}>

0 commit comments

Comments
 (0)