[flang-commits] [flang] [flang][debug] Support ClassType. (PR #114809)

Abid Qadeer via flang-commits flang-commits at lists.llvm.org
Tue Nov 5 13:33:12 PST 2024


https://github.com/abidh updated https://github.com/llvm/llvm-project/pull/114809

>From 8fa049070f7e3749b8f99936611bc401037b01d4 Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Mon, 28 Oct 2024 17:52:56 +0000
Subject: [PATCH 1/2] [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 a070c87137fa16..28c4b9fac74ec5 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -617,6 +617,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<mlir::TupleType>(Ty)) {
     return convertTupleType(tupleTy, fileAttr, scope, declOp);
+  } else if (auto classTy = mlir::dyn_cast_if_present<fir::ClassType>(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<fir::PointerType>(elTy))
+      elTy = ptrTy.getElementType();
+    else if (auto heapTy = mlir::dyn_cast_if_present<fir::HeapType>(elTy))
+      elTy = heapTy.getElementType();
+    return convertPointerLikeType(elTy, fileAttr, scope, declOp,
+                                  /*genAllocated=*/false,
+                                  /*genAssociated=*/false);
   } 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-class-type.fir b/flang/test/Transforms/debug-class-type.fir
new file mode 100644
index 00000000000000..e11dc7b2a2086a
--- /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<!fir.heap<!fir.array<?x?xf32>>>}> dispatch_table {
+    fir.dt_entry "test_proc", @_QPtest_proc
+  } loc(#loc1)
+  func.func private @_QPtest_proc(%arg0: !fir.class<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>)
+
+    func.func @test()  {
+    %0 = fir.address_of(@_QFEx) : !fir.ref<!fir.class<!fir.heap<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>>
+    %1 = fircg.ext_declare %0 {uniq_name = "_QFEx"} : (!fir.ref<!fir.class<!fir.heap<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>>) -> !fir.ref<!fir.class<!fir.heap<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>> loc(#loc3)
+    %2 = fir.address_of(@_QFEy) : !fir.ref<!fir.class<!fir.ptr<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>>
+    %3 = fircg.ext_declare %2 {uniq_name = "_QFEy"} : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>>) -> !fir.ref<!fir.class<!fir.ptr<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>> 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<tag = DW_TAG_pointer_type, name = "", baseType = #[[TY1]]{{.*}}>
+// CHECK-DAG: #llvm.di_subroutine_type<callingConvention = DW_CC_normal, types = #di_null_type, #[[TY2]]>
+// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "x"{{.*}}type = #[[TY2]]>
+// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "y"{{.*}}type = #[[TY2]]>

>From 33be1a0df32ef23fb87221985e2b1e84b91185c0 Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Tue, 5 Nov 2024 19:46:24 +0000
Subject: [PATCH 2/2] 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 28c4b9fac74ec5..b80d652e53e621 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -578,7 +578,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<mlir::NoneType>(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,
@@ -617,20 +622,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<mlir::TupleType>(Ty)) {
     return convertTupleType(tupleTy, fileAttr, scope, declOp);
-  } else if (auto classTy = mlir::dyn_cast_if_present<fir::ClassType>(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<fir::PointerType>(elTy))
-      elTy = ptrTy.getElementType();
-    else if (auto heapTy = mlir::dyn_cast_if_present<fir::HeapType>(elTy))
-      elTy = heapTy.getElementType();
-    return convertPointerLikeType(elTy, fileAttr, scope, declOp,
-                                  /*genAllocated=*/false,
-                                  /*genAssociated=*/false);
   } else if (auto refTy = mlir::dyn_cast_if_present<fir::ReferenceType>(Ty)) {
     auto elTy = refTy.getEleTy();
     return convertPointerLikeType(elTy, fileAttr, scope, declOp,
@@ -642,8 +633,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<fir::BoxType>(Ty)) {
-    auto elTy = boxTy.getElementType();
+  } else if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(Ty)) {
+    if (mlir::isa<fir::ClassType>(Ty))
+      return convertPointerLikeType(boxTy.unwrapInnerType(), fileAttr, scope,
+                                    declOp, /*genAllocated=*/false,
+                                    /*genAssociated=*/true);
+
+    auto elTy = boxTy.getEleTy();
     if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(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 e11dc7b2a2086a..aad15a831fd2fa 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.class<!fir.heap<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>>) -> !fir.ref<!fir.class<!fir.heap<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>> loc(#loc3)
     %2 = fir.address_of(@_QFEy) : !fir.ref<!fir.class<!fir.ptr<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>>
     %3 = fircg.ext_declare %2 {uniq_name = "_QFEy"} : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>>) -> !fir.ref<!fir.class<!fir.ptr<!fir.type<_QTtest_type{a:i32,b:!fir.box<!fir.heap<!fir.array<?x?xf32>>>}>>>> loc(#loc4)
+    %4 = fir.address_of(@_QFEz) : !fir.ref<!fir.class<none>>
+    %5 = fircg.ext_declare %4 {uniq_name = "_QFEz"} : (!fir.ref<!fir.class<none>>) -> !fir.ref<!fir.class<none>> loc(#loc4)
+    %6 = fir.address_of(@_QFEt) : !fir.ref<!fir.class<!fir.ptr<none>>>
+    %7 = fircg.ext_declare %6 {uniq_name = "_QFEt"} : (!fir.ref<!fir.class<!fir.ptr<none>>>) -> !fir.ref<!fir.class<!fir.ptr<none>>> 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<tag = DW_TAG_pointer_type, name = "", baseType = #[[TY1]]{{.*}}>
+// CHECK-DAG: #[[TY3:.*]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, name = "", baseType = #di_null_type{{.*}}>
 // CHECK-DAG: #llvm.di_subroutine_type<callingConvention = DW_CC_normal, types = #di_null_type, #[[TY2]]>
 // 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]]>



More information about the flang-commits mailing list