-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
Conversation
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.
@llvm/pr-subscribers-flang-fir-hlfir Author: Abid Qadeer (abidh) ChangesThe assumed-rank array are represented by DIGenericSubrange in debug metadata. We have to provide 2 things.
With this patch in place, this is how I see an assumed_rank variable being evaluated by GDB.
Full diff: https://github.com/llvm/llvm-project/pull/114404.diff 3 Files Affected:
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]]{{.*}}>
|
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 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.
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!
The assumed-rank array are represented by DIGenericSubrange in debug metadata. We have to provide 2 things.
Expression to get rank value at the runtime from descriptor.
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.