Skip to content

[flang][debug] Support assumed-rank arrays. #114404

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

Merged
merged 1 commit into from
Nov 5, 2024

Conversation

abidh
Copy link
Contributor

@abidh abidh commented Oct 31, 2024

The assumed-rank array are represented by DIGenericSubrange in debug metadata. We have to provide 2 things.

  1. Expression to get rank value at the runtime from descriptor.

  2. Assuming the dimension number for which we want the array information has been put on the DWARF expression stack, expressions which will extract the lowerBound, count and stride information from the descriptor for the said dimension.

With this patch in place, this is how I see an assumed_rank variable being evaluated by GDB.

function mean(x) result(y)
integer, intent(in) :: x(..)
...
end

program main
use mod
implicit none
integer :: x1,xvec(3),xmat(3,3),xtens(3,3,3)
x1 = 5
xvec = 6
xmat = 7
xtens = 8
print *,mean(xvec), mean(xmat), mean(xtens), mean(x1)
end program main

(gdb) p x
$1 = (6, 6, 6)

(gdb) p x
$2 = ((7, 7, 7) (7, 7, 7) (7, 7, 7))

(gdb) p x
$3 = (((8, 8, 8) (8, 8, 8) (8, 8, 8)) ((8, 8, 8) (8, 8, 8) (8, 8, 8)) ((8, 8, 8) (8, 8, 8) (8, 8, 8)))

(gdb) p x
$4 = 5

The assumed-rank array are represented by DIGenericSubrange in debug
metadata. We have to provide 2 things.

1. Expression to get rank value at the runtime from descriptor.

2. Assuming the dimension number for which we want the array information
has been put on the DWARF expression stack, expressions which will
extract the lowerBound, count and stride information from the descriptor
for the said dimension.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Oct 31, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 31, 2024

@llvm/pr-subscribers-flang-fir-hlfir

Author: Abid Qadeer (abidh)

Changes

The assumed-rank array are represented by DIGenericSubrange in debug metadata. We have to provide 2 things.

  1. Expression to get rank value at the runtime from descriptor.

  2. Assuming the dimension number for which we want the array information has been put on the DWARF expression stack, expressions which will extract the lowerBound, count and stride information from the descriptor for the said dimension.

With this patch in place, this is how I see an assumed_rank variable being evaluated by GDB.

function mean(x) result(y)
integer, intent(in) :: x(..)
...
end

program main
use mod
implicit none
integer :: x1,xvec(3),xmat(3,3),xtens(3,3,3)
x1 = 5
xvec = 6
xmat = 7
xtens = 8
print *,mean(xvec), mean(xmat), mean(xtens), mean(x1)
end program main

(gdb) p x
$1 = (6, 6, 6)

(gdb) p x
$2 = ((7, 7, 7) (7, 7, 7) (7, 7, 7))

(gdb) p x
$3 = (((8, 8, 8) (8, 8, 8) (8, 8, 8)) ((8, 8, 8) (8, 8, 8) (8, 8, 8)) ((8, 8, 8) (8, 8, 8) (8, 8, 8)))

(gdb) p x
$4 = 5

Full diff: https://github.com/llvm/llvm-project/pull/114404.diff

3 Files Affected:

  • (modified) flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp (+58-7)
  • (modified) flang/lib/Optimizer/Transforms/DebugTypeGenerator.h (+2)
  • (added) flang/test/Transforms/debug-assumed-rank-array.fir (+14)
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index a070c87137fa16..0187524d76cdd5 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -58,12 +58,17 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m,
   mlir::Type llvmDimsType = getDescFieldTypeModel<kDimsPosInBox>()(context);
   mlir::Type llvmPtrType = getDescFieldTypeModel<kAddrPosInBox>()(context);
   mlir::Type llvmLenType = getDescFieldTypeModel<kElemLenPosInBox>()(context);
+  mlir::Type llvmRankType = getDescFieldTypeModel<kRankPosInBox>()(context);
+
   dimsOffset =
       getComponentOffset<kDimsPosInBox>(*dataLayout, context, llvmDimsType);
   dimsSize = dataLayout->getTypeSize(llvmDimsType);
   ptrSize = dataLayout->getTypeSize(llvmPtrType);
+  rankSize = dataLayout->getTypeSize(llvmRankType);
   lenOffset =
       getComponentOffset<kElemLenPosInBox>(*dataLayout, context, llvmLenType);
+  rankOffset =
+      getComponentOffset<kRankPosInBox>(*dataLayout, context, llvmRankType);
 }
 
 static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
@@ -114,10 +119,7 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
     bool genAllocated, bool genAssociated) {
 
   mlir::MLIRContext *context = module.getContext();
-  // FIXME: Assumed rank arrays not supported yet
-  if (seqTy.hasUnknownShape())
-    return genPlaceholderType(context);
-
+  llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
   llvm::SmallVector<mlir::LLVM::DIExpressionElemAttr> ops;
   auto addOp = [&](unsigned opc, llvm::ArrayRef<uint64_t> vals) {
     ops.push_back(mlir::LLVM::DIExpressionElemAttr::get(context, opc, vals));
@@ -129,6 +131,58 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
   // dataLocation = *base_addr
   mlir::LLVM::DIExpressionAttr dataLocation =
       mlir::LLVM::DIExpressionAttr::get(context, ops);
+  ops.clear();
+
+  mlir::LLVM::DITypeAttr elemTy =
+      convertType(seqTy.getEleTy(), fileAttr, scope, declOp);
+
+  // Assumed-rank arrays
+  if (seqTy.hasUnknownShape()) {
+    addOp(llvm::dwarf::DW_OP_push_object_address, {});
+    addOp(llvm::dwarf::DW_OP_plus_uconst, {rankOffset});
+    addOp(llvm::dwarf::DW_OP_deref_size, {rankSize});
+    mlir::LLVM::DIExpressionAttr rank =
+        mlir::LLVM::DIExpressionAttr::get(context, ops);
+    ops.clear();
+
+    auto genSubrangeOp = [&](unsigned field) -> mlir::LLVM::DIExpressionAttr {
+      // The dwarf expression for generic subrange assumes that dimension for
+      // which it is being generated is already pushed on the stack. Here is the
+      // formula we will use to calculate count for example.
+      // *(base_addr + offset_count_0 + (dimsSize x dimension_number)).
+      // where offset_count_0 is offset of the count field for the 0th dimension
+      addOp(llvm::dwarf::DW_OP_push_object_address, {});
+      addOp(llvm::dwarf::DW_OP_over, {});
+      addOp(llvm::dwarf::DW_OP_constu, {dimsSize});
+      addOp(llvm::dwarf::DW_OP_mul, {});
+      addOp(llvm::dwarf::DW_OP_plus_uconst,
+            {dimsOffset + ((dimsSize / 3) * field)});
+      addOp(llvm::dwarf::DW_OP_plus, {});
+      addOp(llvm::dwarf::DW_OP_deref, {});
+      mlir::LLVM::DIExpressionAttr attr =
+          mlir::LLVM::DIExpressionAttr::get(context, ops);
+      ops.clear();
+      return attr;
+    };
+
+    mlir::LLVM::DIExpressionAttr lowerAttr = genSubrangeOp(kDimLowerBoundPos);
+    mlir::LLVM::DIExpressionAttr countAttr = genSubrangeOp(kDimExtentPos);
+    mlir::LLVM::DIExpressionAttr strideAttr = genSubrangeOp(kDimStridePos);
+
+    auto subrangeTy = mlir::LLVM::DIGenericSubrangeAttr::get(
+        context, countAttr, lowerAttr, /*upperBound=*/nullptr, strideAttr);
+    elements.push_back(subrangeTy);
+
+    return mlir::LLVM::DICompositeTypeAttr::get(
+        context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr,
+        /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy,
+        mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0,
+        elements, dataLocation, rank, /*allocated=*/nullptr,
+        /*associated=*/nullptr);
+  }
+
+  addOp(llvm::dwarf::DW_OP_push_object_address, {});
+  addOp(llvm::dwarf::DW_OP_deref, {});
   addOp(llvm::dwarf::DW_OP_lit0, {});
   addOp(llvm::dwarf::DW_OP_ne, {});
 
@@ -139,9 +193,6 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
   mlir::LLVM::DIExpressionAttr associated = genAssociated ? valid : nullptr;
   ops.clear();
 
-  llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
-  mlir::LLVM::DITypeAttr elemTy =
-      convertType(seqTy.getEleTy(), fileAttr, scope, declOp);
   unsigned offset = dimsOffset;
   unsigned index = 0;
   mlir::IntegerType intTy = mlir::IntegerType::get(context, 64);
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
index c1fce4bdae5ce5..7daa0af166e697 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
@@ -89,6 +89,8 @@ class DebugTypeGenerator {
   std::uint64_t dimsOffset;
   std::uint64_t ptrSize;
   std::uint64_t lenOffset;
+  std::uint64_t rankOffset;
+  std::uint64_t rankSize;
   llvm::DenseMap<mlir::Type, mlir::LLVM::DITypeAttr> typeCache;
 };
 
diff --git a/flang/test/Transforms/debug-assumed-rank-array.fir b/flang/test/Transforms/debug-assumed-rank-array.fir
new file mode 100644
index 00000000000000..ce474cd259619b
--- /dev/null
+++ b/flang/test/Transforms/debug-assumed-rank-array.fir
@@ -0,0 +1,14 @@
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
+  func.func @_QFPfn(%arg0: !fir.box<!fir.array<*:i32>> )  {
+    %1 = fir.undefined !fir.dscope
+    %2 = fircg.ext_declare %arg0 dummy_scope %1 {uniq_name = "_QFFfnEx"} : (!fir.box<!fir.array<*:i32>>, !fir.dscope) -> !fir.box<!fir.array<*:i32>> loc(#loc2)
+    return
+  } loc(#loc1)
+}
+#loc1 = loc("test1.f90":1:1)
+#loc2 = loc("test1.f90":3:16)
+
+// CHECK: #[[TY:.*]] = #llvm.di_composite_type<tag = DW_TAG_array_type{{.*}}elements = #llvm.di_generic_subrange<count = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_over, DW_OP_constu(24), DW_OP_mul, DW_OP_plus_uconst(32), DW_OP_plus, DW_OP_deref]>, lowerBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_over, DW_OP_constu(24), DW_OP_mul, DW_OP_plus_uconst(24), DW_OP_plus, DW_OP_deref]>, stride = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_over, DW_OP_constu(24), DW_OP_mul, DW_OP_plus_uconst(40), DW_OP_plus, DW_OP_deref]>>, dataLocation = <[DW_OP_push_object_address, DW_OP_deref]>, rank = <[DW_OP_push_object_address, DW_OP_plus_uconst(20), DW_OP_deref_size(1)]>>
+// CHECK: #llvm.di_local_variable<{{.*}}name = "x"{{.*}}type = #[[TY]]{{.*}}>

Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with how you're using the descriptors, the code changes look good, and the results look correct. It would be good if somebody more familiar with DWARF could also take a look.

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@abidh abidh merged commit a993dfc into llvm:main Nov 5, 2024
11 checks passed
@abidh abidh deleted the flang_generic_subrange branch November 18, 2024 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants