From 548bcf4bb4e7a2a4331ea5bf7962150f3cff43a4 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Mon, 28 Oct 2024 17:52:56 +0000 Subject: [PATCH 1/3] [flang][debug] Support ClassType. This PR adds the handling of ClassType. It is treated as pointer to the underlying type. Note that ClassType when passed to the function have double indirection so it is represented as pointer to type (and not type as a RecordType will be for example). If ClassType wraps a pointer or allocatable then we take care to avoid double indirection. This is how it looks like in the debugger. subroutine test_proc (this) class(test_type), intent (inout) :: this allocate (this%b (3, 2)) call fill_array_2d (this%b) print *, this%a end (gdb) p this $6 = (PTR TO -> ( Type test_type )) 0x2052a0 (gdb) p this%a $7 = 0 (gdb) p this%b $8 = ((1, 2, 3) (4, 5, 6)) (gdb) --- .../Transforms/DebugTypeGenerator.cpp | 14 ++++++++++ flang/test/Transforms/debug-class-type.fir | 27 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 flang/test/Transforms/debug-class-type.fir diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp index 0187524d76cdd..093c7c897376c 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp @@ -668,6 +668,20 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, return convertRecordType(recTy, fileAttr, scope, declOp); } else if (auto tupleTy = mlir::dyn_cast_if_present(Ty)) { return convertTupleType(tupleTy, fileAttr, scope, declOp); + } else if (auto classTy = mlir::dyn_cast_if_present(Ty)) { + // ClassType when passed to the function have double indirection so it + // is represented as pointer to type (and not type as a RecordType will be + // for example). If ClassType wraps a pointer or allocatable then we get + // the real underlying type to avoid translating the Ty to + // Ptr -> Ptr -> type. + mlir::Type elTy = classTy.getEleTy(); + if (auto ptrTy = mlir::dyn_cast_if_present(elTy)) + elTy = ptrTy.getElementType(); + else if (auto heapTy = mlir::dyn_cast_if_present(elTy)) + elTy = heapTy.getElementType(); + return convertPointerLikeType(elTy, fileAttr, scope, declOp, + /*genAllocated=*/false, + /*genAssociated=*/false); } else if (auto refTy = mlir::dyn_cast_if_present(Ty)) { auto elTy = refTy.getEleTy(); return convertPointerLikeType(elTy, fileAttr, scope, declOp, diff --git a/flang/test/Transforms/debug-class-type.fir b/flang/test/Transforms/debug-class-type.fir new file mode 100644 index 0000000000000..e11dc7b2a2086 --- /dev/null +++ b/flang/test/Transforms/debug-class-type.fir @@ -0,0 +1,27 @@ +// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s + +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { + fir.type_info @_QTtest_type nofinal : !fir.type<_QTtest_type{a:i32,b:!fir.box>>}> dispatch_table { + fir.dt_entry "test_proc", @_QPtest_proc + } loc(#loc1) + func.func private @_QPtest_proc(%arg0: !fir.class>>}>>) + + func.func @test() { + %0 = fir.address_of(@_QFEx) : !fir.ref>>}>>>> + %1 = fircg.ext_declare %0 {uniq_name = "_QFEx"} : (!fir.ref>>}>>>>) -> !fir.ref>>}>>>> loc(#loc3) + %2 = fir.address_of(@_QFEy) : !fir.ref>>}>>>> + %3 = fircg.ext_declare %2 {uniq_name = "_QFEy"} : (!fir.ref>>}>>>>) -> !fir.ref>>}>>>> loc(#loc4) + return + } loc(#loc2) +} + +#loc1 = loc("./simple.f90":2:1) +#loc2 = loc("./simple.f90":10:1) +#loc3 = loc("./simple.f90":15:1) +#loc4 = loc("./simple.f90":22:1) + +// CHECK-DAG: #[[TY1:.*]] = #llvm.di_composite_type<{{.*}}name = "test_type"{{.*}}> +// CHECK-DAG: #[[TY2:.*]] = #llvm.di_derived_type +// CHECK-DAG: #llvm.di_subroutine_type +// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "x"{{.*}}type = #[[TY2]]> +// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "y"{{.*}}type = #[[TY2]]> From b8c1012a596e7ceed3d8136ce4e3f5d8ffe5c44d Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Tue, 5 Nov 2024 19:46:24 +0000 Subject: [PATCH 2/3] Handle review comments. Merged handling of ClassType with BoxType. Used boxTy.unwrapInnerType() to avoid special casing for pointer or allocatable. Also improved convertPointerLikeType to better handle if underlying type in null or none. --- .../Transforms/DebugTypeGenerator.cpp | 30 ++++++++----------- flang/test/Transforms/debug-class-type.fir | 7 +++++ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp index 093c7c897376c..a9f2782a8e9a5 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp @@ -629,7 +629,12 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertPointerLikeType( return convertCharacterType(charTy, fileAttr, scope, declOp, /*hasDescriptor=*/true); - mlir::LLVM::DITypeAttr elTyAttr = convertType(elTy, fileAttr, scope, declOp); + // If elTy is null or none then generate a void* + mlir::LLVM::DITypeAttr elTyAttr; + if (!elTy || mlir::isa(elTy)) + elTyAttr = mlir::LLVM::DINullTypeAttr::get(context); + else + elTyAttr = convertType(elTy, fileAttr, scope, declOp); return mlir::LLVM::DIDerivedTypeAttr::get( context, llvm::dwarf::DW_TAG_pointer_type, @@ -668,20 +673,6 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, return convertRecordType(recTy, fileAttr, scope, declOp); } else if (auto tupleTy = mlir::dyn_cast_if_present(Ty)) { return convertTupleType(tupleTy, fileAttr, scope, declOp); - } else if (auto classTy = mlir::dyn_cast_if_present(Ty)) { - // ClassType when passed to the function have double indirection so it - // is represented as pointer to type (and not type as a RecordType will be - // for example). If ClassType wraps a pointer or allocatable then we get - // the real underlying type to avoid translating the Ty to - // Ptr -> Ptr -> type. - mlir::Type elTy = classTy.getEleTy(); - if (auto ptrTy = mlir::dyn_cast_if_present(elTy)) - elTy = ptrTy.getElementType(); - else if (auto heapTy = mlir::dyn_cast_if_present(elTy)) - elTy = heapTy.getElementType(); - return convertPointerLikeType(elTy, fileAttr, scope, declOp, - /*genAllocated=*/false, - /*genAssociated=*/false); } else if (auto refTy = mlir::dyn_cast_if_present(Ty)) { auto elTy = refTy.getEleTy(); return convertPointerLikeType(elTy, fileAttr, scope, declOp, @@ -693,8 +684,13 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, return genBasicType(context, mlir::StringAttr::get(context, "integer"), llvmTypeConverter.getIndexTypeBitwidth(), llvm::dwarf::DW_ATE_signed); - } else if (auto boxTy = mlir::dyn_cast_or_null(Ty)) { - auto elTy = boxTy.getElementType(); + } else if (auto boxTy = mlir::dyn_cast_or_null(Ty)) { + if (mlir::isa(Ty)) + return convertPointerLikeType(boxTy.unwrapInnerType(), fileAttr, scope, + declOp, /*genAllocated=*/false, + /*genAssociated=*/true); + + auto elTy = boxTy.getEleTy(); if (auto seqTy = mlir::dyn_cast_or_null(elTy)) return convertBoxedSequenceType(seqTy, fileAttr, scope, declOp, false, false); diff --git a/flang/test/Transforms/debug-class-type.fir b/flang/test/Transforms/debug-class-type.fir index e11dc7b2a2086..aad15a831fd2f 100644 --- a/flang/test/Transforms/debug-class-type.fir +++ b/flang/test/Transforms/debug-class-type.fir @@ -11,6 +11,10 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<>} { %1 = fircg.ext_declare %0 {uniq_name = "_QFEx"} : (!fir.ref>>}>>>>) -> !fir.ref>>}>>>> loc(#loc3) %2 = fir.address_of(@_QFEy) : !fir.ref>>}>>>> %3 = fircg.ext_declare %2 {uniq_name = "_QFEy"} : (!fir.ref>>}>>>>) -> !fir.ref>>}>>>> loc(#loc4) + %4 = fir.address_of(@_QFEz) : !fir.ref> + %5 = fircg.ext_declare %4 {uniq_name = "_QFEz"} : (!fir.ref>) -> !fir.ref> loc(#loc4) + %6 = fir.address_of(@_QFEt) : !fir.ref>> + %7 = fircg.ext_declare %6 {uniq_name = "_QFEt"} : (!fir.ref>>) -> !fir.ref>> loc(#loc4) return } loc(#loc2) } @@ -22,6 +26,9 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<>} { // CHECK-DAG: #[[TY1:.*]] = #llvm.di_composite_type<{{.*}}name = "test_type"{{.*}}> // CHECK-DAG: #[[TY2:.*]] = #llvm.di_derived_type +// CHECK-DAG: #[[TY3:.*]] = #llvm.di_derived_type // CHECK-DAG: #llvm.di_subroutine_type // CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "x"{{.*}}type = #[[TY2]]> // CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "y"{{.*}}type = #[[TY2]]> +// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "z"{{.*}}type = #[[TY3]]> +// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "t"{{.*}}type = #[[TY3]]> From fe75d2c7e568f8f8f080097fd281f09e0f2f58ab Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Wed, 13 Nov 2024 20:21:59 +0000 Subject: [PATCH 3/3] Handle review comments. Dont special case ClassTyp but handle it like a BoxType. Also in default case, generate a pointer to underlying type instead of a PlaceHolder type. --- flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp index a9f2782a8e9a5..cc99698ead33f 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp @@ -685,11 +685,6 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, llvmTypeConverter.getIndexTypeBitwidth(), llvm::dwarf::DW_ATE_signed); } else if (auto boxTy = mlir::dyn_cast_or_null(Ty)) { - if (mlir::isa(Ty)) - return convertPointerLikeType(boxTy.unwrapInnerType(), fileAttr, scope, - declOp, /*genAllocated=*/false, - /*genAssociated=*/true); - auto elTy = boxTy.getEleTy(); if (auto seqTy = mlir::dyn_cast_or_null(elTy)) return convertBoxedSequenceType(seqTy, fileAttr, scope, declOp, false, @@ -702,7 +697,9 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, return convertPointerLikeType(ptrTy.getElementType(), fileAttr, scope, declOp, /*genAllocated=*/false, /*genAssociated=*/true); - return genPlaceholderType(context); + return convertPointerLikeType(elTy, fileAttr, scope, declOp, + /*genAllocated=*/false, + /*genAssociated=*/false); } else { // FIXME: These types are currently unhandled. We are generating a // placeholder type to allow us to test supported bits.