Skip to content

Commit 421180e

Browse files
committed
[flang][debug] Support assume shape arrays.
This PR generates dwarf to extract the information about the arrays from descriptor. To calculate the offset of the fields in the descriptor, we are adding up the sizes of the fields above. It seems to work ok for 64-bit target. Will have to see if some changes are required for 32-bits targets. As we use data layout now, some tests needed to be adjusted to have a dummy data layout to avoid failure. With this change in place, GDB is able show the assumed shape arrays correctly. subroutine ff(n, m, arr) integer n, m integer :: arr(:, :) print *, arr do i = 1, n do j = 1, m arr(j, i) = (i * 5) + j + 10 end do end do print *, arr end subroutine ff Breakpoint 1, ff (n=4, m=3, arr=...) at test1.f90:13 13 print *, arr (gdb) p arr $1 = ((6, 7, 8, 9) (11, 12, 13, 14) (16, 17, 18, 19)) (gdb) ptype arr type = integer (4,3) (gdb) c Continuing. 6 7 8 9 11 12 13 14 16 17 18 19
1 parent ae9d89d commit 421180e

14 files changed

+188
-11
lines changed

flang/lib/Optimizer/CodeGen/TypeConverter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
#define DEBUG_TYPE "flang-type-conversion"
1414

1515
#include "flang/Optimizer/CodeGen/TypeConverter.h"
16-
#include "DescriptorModel.h"
1716
#include "flang/Common/Fortran.h"
1817
#include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done
18+
#include "flang/Optimizer/CodeGen/DescriptorModel.h"
1919
#include "flang/Optimizer/CodeGen/TBAABuilder.h"
2020
#include "flang/Optimizer/CodeGen/Target.h"
2121
#include "flang/Optimizer/Dialect/FIRType.h"

flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#define DEBUG_TYPE "flang-debug-type-generator"
1414

1515
#include "DebugTypeGenerator.h"
16+
#include "flang/Optimizer/CodeGen/DescriptorModel.h"
17+
#include "flang/Optimizer/CodeGen/TypeConverter.h"
18+
#include "flang/Optimizer/Support/DataLayout.h"
19+
#include "mlir/Pass/Pass.h"
1620
#include "llvm/ADT/ScopeExit.h"
1721
#include "llvm/BinaryFormat/Dwarf.h"
1822
#include "llvm/Support/Debug.h"
@@ -22,6 +26,60 @@ namespace fir {
2226
DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m)
2327
: module(m), kindMapping(getKindMapping(m)) {
2428
LLVM_DEBUG(llvm::dbgs() << "DITypeAttr generator\n");
29+
30+
std::optional<mlir::DataLayout> dl =
31+
fir::support::getOrSetDataLayout(module, /*allowDefaultLayout=*/true);
32+
if (!dl)
33+
mlir::emitError(module.getLoc(), "Missing data layout attribute in module");
34+
35+
mlir::MLIRContext *context = module.getContext();
36+
37+
// The debug information requires the offset of certain fields in the
38+
// descriptors like lower_bound and extent for each dimension. The code
39+
// below uses getDescFieldTypeModel to get the type representing each field
40+
// and then use data layout to get its size. It adds the size to get the
41+
// offset.
42+
// As has been mentioned in DescriptorModel.h that code may be confusing
43+
// host for the target in calculating the type of the descriptor fields. But
44+
// debug info is using similar logic to what codegen is doing so it will
45+
// atleast be representing the generated code correctly.
46+
// My testing for a 32-bit shows that base_addr* is correctly given as a
47+
// 32-bit entity. The index types are 64-bit so I am a bit uncertain how
48+
// the alignment will effect the calculation of offsets in that case.
49+
50+
// base_addr*
51+
dimsOffset =
52+
dl->getTypeSizeInBits(getDescFieldTypeModel<kAddrPosInBox>()(context));
53+
54+
// elem_len
55+
dimsOffset +=
56+
dl->getTypeSizeInBits(getDescFieldTypeModel<kElemLenPosInBox>()(context));
57+
58+
// version
59+
dimsOffset +=
60+
dl->getTypeSizeInBits(getDescFieldTypeModel<kVersionPosInBox>()(context));
61+
62+
// rank
63+
dimsOffset +=
64+
dl->getTypeSizeInBits(getDescFieldTypeModel<kRankPosInBox>()(context));
65+
66+
// type
67+
dimsOffset +=
68+
dl->getTypeSizeInBits(getDescFieldTypeModel<kTypePosInBox>()(context));
69+
70+
// attribute
71+
dimsOffset += dl->getTypeSizeInBits(
72+
getDescFieldTypeModel<kAttributePosInBox>()(context));
73+
74+
// f18Addendum
75+
dimsOffset += dl->getTypeSizeInBits(
76+
getDescFieldTypeModel<kF18AddendumPosInBox>()(context));
77+
78+
// dims
79+
dimsSize =
80+
dl->getTypeSizeInBits(getDescFieldTypeModel<kDimsPosInBox>()(context));
81+
dimsOffset /= 8;
82+
dimsSize /= 8;
2583
}
2684

2785
static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
@@ -37,10 +95,82 @@ static mlir::LLVM::DITypeAttr genPlaceholderType(mlir::MLIRContext *context) {
3795
llvm::dwarf::DW_ATE_signed);
3896
}
3997

98+
mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
99+
fir::SequenceType seqTy, mlir::LLVM::DIFileAttr fileAttr,
100+
mlir::LLVM::DIScopeAttr scope, mlir::Location loc, bool genAllocated,
101+
bool genAssociated) {
102+
103+
mlir::MLIRContext *context = module.getContext();
104+
// FIXME: Assumed rank arrays not supported yet
105+
if (seqTy.hasUnknownShape())
106+
return genPlaceholderType(context);
107+
108+
llvm::SmallVector<mlir::LLVM::DIExpressionElemAttr> ops;
109+
auto addOp = [&](unsigned opc, llvm::ArrayRef<uint64_t> vals) {
110+
ops.push_back(mlir::LLVM::DIExpressionElemAttr::get(context, opc, vals));
111+
};
112+
113+
addOp(llvm::dwarf::DW_OP_push_object_address, {});
114+
addOp(llvm::dwarf::DW_OP_deref, {});
115+
116+
// dataLocation = *base_addr
117+
mlir::LLVM::DIExpressionAttr dataLocation =
118+
mlir::LLVM::DIExpressionAttr::get(context, ops);
119+
addOp(llvm::dwarf::DW_OP_lit0, {});
120+
addOp(llvm::dwarf::DW_OP_ne, {});
121+
122+
// allocated = associated = (*base_addr != 0)
123+
mlir::LLVM::DIExpressionAttr valid =
124+
mlir::LLVM::DIExpressionAttr::get(context, ops);
125+
mlir::LLVM::DIExpressionAttr associated = genAllocated ? valid : nullptr;
126+
mlir::LLVM::DIExpressionAttr allocated = genAssociated ? valid : nullptr;
127+
ops.clear();
128+
129+
llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
130+
mlir::LLVM::DITypeAttr elemTy =
131+
convertType(seqTy.getEleTy(), fileAttr, scope, loc);
132+
unsigned offset = dimsOffset;
133+
const unsigned indexSize = dimsSize / 3;
134+
for ([[maybe_unused]] auto _ : seqTy.getShape()) {
135+
// For each dimension, find the offset of count and lower bound in the
136+
// descriptor and generate the dwarf expression to extract it.
137+
// FIXME: If `indexSize` happens to be bigger than address size on the
138+
// system then we may have to change 'DW_OP_deref' here.
139+
addOp(llvm::dwarf::DW_OP_push_object_address, {});
140+
addOp(llvm::dwarf::DW_OP_plus_uconst,
141+
{offset + (indexSize * kDimExtentPos)});
142+
addOp(llvm::dwarf::DW_OP_deref, {});
143+
// count[i] = *(base_addr + offset + (indexSize * kDimExtentPos))
144+
// where 'offset' is dimsOffset + (i * dimsSize)
145+
mlir::LLVM::DIExpressionAttr countAttr =
146+
mlir::LLVM::DIExpressionAttr::get(context, ops);
147+
ops.clear();
148+
149+
addOp(llvm::dwarf::DW_OP_push_object_address, {});
150+
addOp(llvm::dwarf::DW_OP_plus_uconst,
151+
{offset + (indexSize * kDimLowerBoundPos)});
152+
addOp(llvm::dwarf::DW_OP_deref, {});
153+
// lower_bound[i] = *(base_addr + offset + (indexSize * kDimLowerBoundPos))
154+
mlir::LLVM::DIExpressionAttr lowerAttr =
155+
mlir::LLVM::DIExpressionAttr::get(context, ops);
156+
ops.clear();
157+
158+
offset += dimsSize;
159+
mlir::LLVM::DISubrangeAttr subrangeTy = mlir::LLVM::DISubrangeAttr::get(
160+
context, nullptr, lowerAttr, countAttr, nullptr);
161+
elements.push_back(subrangeTy);
162+
}
163+
return mlir::LLVM::DICompositeTypeAttr::get(
164+
context, llvm::dwarf::DW_TAG_array_type, /*recursive id*/ {},
165+
/* name */ nullptr, /* file */ nullptr, /* line */ 0,
166+
/* scope */ nullptr, elemTy, mlir::LLVM::DIFlags::Zero,
167+
/* sizeInBits */ 0, /*alignInBits*/ 0, elements, dataLocation,
168+
/* rank */ nullptr, allocated, associated);
169+
}
170+
40171
mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType(
41172
fir::SequenceType seqTy, mlir::LLVM::DIFileAttr fileAttr,
42173
mlir::LLVM::DIScopeAttr scope, mlir::Location loc) {
43-
44174
mlir::MLIRContext *context = module.getContext();
45175
// FIXME: Only fixed sizes arrays handled at the moment.
46176
if (seqTy.hasDynamicExtents())
@@ -112,6 +242,12 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr,
112242
bitWidth * 2, llvm::dwarf::DW_ATE_complex_float);
113243
} else if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(Ty)) {
114244
return convertSequenceType(seqTy, fileAttr, scope, loc);
245+
} else if (auto boxTy = mlir::dyn_cast_or_null<fir::BoxType>(Ty)) {
246+
auto elTy = boxTy.getElementType();
247+
if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(elTy))
248+
return convertBoxedSequenceType(seqTy, fileAttr, scope, loc, false,
249+
false);
250+
return genPlaceholderType(context);
115251
} else {
116252
// FIXME: These types are currently unhandled. We are generating a
117253
// placeholder type to allow us to test supported bits.

flang/lib/Optimizer/Transforms/DebugTypeGenerator.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,20 @@ class DebugTypeGenerator {
3535
mlir::LLVM::DIFileAttr fileAttr,
3636
mlir::LLVM::DIScopeAttr scope,
3737
mlir::Location loc);
38+
39+
/// The 'genAllocated' is true when we want to generate 'allocated' field
40+
/// in the DICompositeType. It is needed for the allocatable arrays.
41+
/// Similarly, 'genAssociated' is used with 'pointer' type to generate
42+
/// 'associated' field.
43+
mlir::LLVM::DITypeAttr
44+
convertBoxedSequenceType(fir::SequenceType seqTy,
45+
mlir::LLVM::DIFileAttr fileAttr,
46+
mlir::LLVM::DIScopeAttr scope, mlir::Location loc,
47+
bool genAllocated, bool genAssociated);
3848
mlir::ModuleOp module;
3949
KindMapping kindMapping;
50+
size_t dimsSize;
51+
size_t dimsOffset;
4052
};
4153

4254
} // namespace fir
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
2+
3+
subroutine ff(arr)
4+
implicit none
5+
integer :: arr(:, :)
6+
return arr(1,1)
7+
end subroutine ff
8+
9+
! CHECK-DAG: !DICompositeType(tag: DW_TAG_array_type{{.*}}elements: ![[ELEMS:[0-9]+]], dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref))
10+
! CHECK-DAG: ![[ELEMS]] = !{![[ELEM1:[0-9]+]], ![[ELEM2:[0-9]+]]}
11+
! CHECK-DAG: ![[ELEM1]] = !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 24, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 32, DW_OP_deref))
12+
! CHECK-DAG: ![[ELEM2]] = !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 48, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 56, DW_OP_deref))
13+

flang/test/Transforms/debug-90683.fir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// This test checks that debug information for fir.real type works ok.
44

5-
module attributes {} {
5+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
66
func.func @_QPfn1(%arg0: !fir.ref<!fir.complex<8>> {fir.bindc_name = "a"} ) {
77
%0 = fir.declare %arg0 {uniq_name = "_QFfn1Ea"} : (!fir.ref<!fir.complex<8>>) -> !fir.ref<!fir.complex<8>>
88
%1 = fir.alloca f32 {bindc_name = "abserror", uniq_name = "_QFfn1Eabserror"}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
2+
3+
module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>, #dlti.dl_entry<"dlti.endianness", "little">>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"} {
4+
func.func @ff_(%arg0: !fir.box<!fir.array<?x?xi32>> {fir.bindc_name = "arr"} ) {
5+
%0 = fir.undefined !fir.dscope
6+
%1 = fircg.ext_declare %arg0 dummy_scope %0 {uniq_name = "_QFffEarr"} : (!fir.box<!fir.array<?x?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?x?xi32>> loc(#loc1)
7+
return
8+
} loc(#loc2)
9+
}
10+
#loc1 = loc("test1.f90":1:1)
11+
#loc2 = loc("test1.f90":3:16)
12+
13+
// CHECK: #llvm.di_composite_type<tag = DW_TAG_array_type
14+
// CHECK-SAME: elements = #llvm.di_subrange<lowerBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(24), DW_OP_deref]>, upperBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(32), DW_OP_deref]>>
15+
// CHECK-SAME: #llvm.di_subrange<lowerBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(48), DW_OP_deref]>, upperBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(56), DW_OP_deref]>>
16+
// CHECK-SAME: dataLocation = <[DW_OP_push_object_address, DW_OP_deref]>>

flang/test/Transforms/debug-complex-1.fir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// check conversion of complex type of different size. Both fir and mlir
44
// variants are checked.
55

6-
module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.target_triple = "native"} {
6+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
77
func.func @test1(%x : !fir.complex<4>) -> !fir.complex<8> {
88
%1 = fir.convert %x : (!fir.complex<4>) -> !fir.complex<8>
99
return %1 : !fir.complex<8>

flang/test/Transforms/debug-fixed-array-type.fir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
22

3-
module attributes {} {
3+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
44
func.func @_QQmain() attributes {fir.bindc_name = "mn"} {
55
%c7 = arith.constant 7 : index
66
%c8 = arith.constant 8 : index

flang/test/Transforms/debug-line-table-existing.fir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// REQUIRES: system-linux
44

55
// Test that there are no changes to a function with existed fused loc debug
6-
module attributes {} {
6+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
77
func.func @_QPs1() {
88
return loc(#loc1)
99
} loc(#loc2)

flang/test/Transforms/debug-line-table-inc-file.fir

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// REQUIRES: system-linux
44

55
// Test for included functions that have a different debug location than the current file
6-
module attributes {} {
6+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
77
func.func @_QPsinc() {
88
return loc(#loc2)
99
} loc(#loc1)
@@ -19,7 +19,7 @@ module attributes {} {
1919
#loc4 = loc("/home/user01/llvm-project/build_release/simple.f90":4:3)
2020
#loc5 = loc("/home/user01/llvm-project/build_release/simple.f90":5:1)
2121
22-
// CHECK: module {
22+
// CHECK: module
2323
// CHECK: func.func @_QPsinc() {
2424
// CHECK: } loc(#[[FUSED_LOC_INC_FILE:.*]])
2525
// CHECK: func.func @_QQmain() {

flang/test/Transforms/debug-line-table-inc-same-file.fir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
// Test that there is only one FileAttribute generated for multiple functions
66
// in the same file.
7-
module attributes {} {
7+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
88
func.func @_QPs1() {
99
return loc(#loc2)
1010
} loc(#loc1)

flang/test/Transforms/debug-line-table.fir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// RUN: fir-opt --add-debug-info="debug-level=LineTablesOnly" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=LINETABLE
44
// RUN: fir-opt --add-debug-info="is-optimized=true" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=OPT
55

6-
module attributes { fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", llvm.target_triple = "aarch64-unknown-linux-gnu"} {
6+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
77
func.func @_QPsb() {
88
return loc(#loc_sb)
99
} loc(#loc_sb)

flang/test/Transforms/debug-module-1.fir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
22

33

4-
module attributes {} {
4+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
55
fir.global @_QMhelperEgli : i32 {
66
%0 = fir.zero_bits i32
77
fir.has_value %0 : i32

0 commit comments

Comments
 (0)