Skip to content

Commit a45bef3

Browse files
committed
Workaround limitation in mlir handling of cyclic debug attributes.
This commit fixes an issue that can cause an assertion to fail in some circumstances at https://github.com/llvm/llvm-project/blob/26029d77a57cb4aaa1479064109e985a90d0edd8/mlir/lib/Target/LLVMIR/DebugTranslation.cpp#L270. The issue relates to the handling of recursive debug type in mlir. See the discussion at the end of follow PR for more details. llvm#106571 Problem could be explained with the following example code: type t2 type(t1), pointer :: p1 end type type t1 type(t2), pointer :: p2 end type In the description below, type_self means a temporary type that is generated as a place holder while the members of that type are being processed. If we process t1 first then we will have the following structure after it has been processed. t1 -> t2 -> t1_self This is because when we started processing t2, we did not have the complete t1 but its place holder t1_self. Now if some entity requires t2, we will already have that in cache and will return it. But this t2 refers to t1_self and not to t1. In mlir handling, only those types are allowed to have _self reference which are wrapped by entity whose reference it contains. So t1 -> t2 -> t1_self is ok because the t1_self reference can be resolved by the outer t1. But standalone t2 is not because there will be no way to resolve it. Please see DebugTranslation::translateRecursive for details on how mlir handles recursive types. The fix is not to cache the type that will fail if used standalone.
1 parent 9f162b3 commit a45bef3

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,70 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
159159
dataLocation, /*rank=*/nullptr, allocated, associated);
160160
}
161161

162+
// If the type is a pointer or array type then gets its underlying type.
163+
static mlir::LLVM::DITypeAttr getUnderlyingType(mlir::LLVM::DITypeAttr Ty) {
164+
if (auto ptrTy =
165+
mlir::dyn_cast_if_present<mlir::LLVM::DIDerivedTypeAttr>(Ty)) {
166+
if (ptrTy.getTag() == llvm::dwarf::DW_TAG_pointer_type)
167+
Ty = getUnderlyingType(ptrTy.getBaseType());
168+
}
169+
if (auto comTy =
170+
mlir::dyn_cast_if_present<mlir::LLVM::DICompositeTypeAttr>(Ty)) {
171+
if (comTy.getTag() == llvm::dwarf::DW_TAG_array_type)
172+
Ty = getUnderlyingType(comTy.getBaseType());
173+
}
174+
return Ty;
175+
}
176+
177+
// Currently, the handling of recursive debug type in mlir has some limitations.
178+
// Those limitations were discussed at the end of the thread for following PR.
179+
// https://github.com/llvm/llvm-project/pull/106571
180+
//
181+
// Problem could be explained with the following example code:
182+
// type t2
183+
// type(t1), pointer :: p1
184+
// end type
185+
// type t1
186+
// type(t2), pointer :: p2
187+
// end type
188+
// In the description below, type_self means a temporary type that is generated
189+
// as a place holder while the members of that type are being processed.
190+
//
191+
// If we process t1 first then we will have the following structure after it has
192+
// been processed.
193+
// t1 -> t2 -> t1_self
194+
// This is because when we started processing t2, we did not have the complete
195+
// t1 but its place holder t1_self.
196+
// Now if some entity requires t2, we will already have that in cache and will
197+
// return it. But this t2 refers to t1_self and not to t1. In mlir handling,
198+
// only those types are allowed to have _self reference which are wrapped by
199+
// entity whose reference it is. So t1 -> t2 -> t1_self is ok because the
200+
// t1_self reference can be resolved by the outer t1. But standalone t2 is not
201+
// because there will be no way to resolve it. Until this is fixed in mlir, we
202+
// avoid caching such types. Please see DebugTranslation::translateRecursive for
203+
// details on how mlir handles recursive types.
204+
static bool canCacheThisType(mlir::LLVM::DICompositeTypeAttr comTy) {
205+
for (auto el : comTy.getElements()) {
206+
if (auto mem =
207+
mlir::dyn_cast_if_present<mlir::LLVM::DIDerivedTypeAttr>(el)) {
208+
mlir::LLVM::DITypeAttr memTy = getUnderlyingType(mem.getBaseType());
209+
if (auto baseTy =
210+
mlir::dyn_cast_if_present<mlir::LLVM::DICompositeTypeAttr>(
211+
memTy)) {
212+
// We will not cache a type if one of its member meets the following
213+
// conditions:
214+
// 1. It is a structure type
215+
// 2. It is a place holder type (getIsRecSelf() is true)
216+
// 3. It is not a self reference. It is ok to have t1_self in t1.
217+
if (baseTy.getTag() == llvm::dwarf::DW_TAG_structure_type &&
218+
baseTy.getIsRecSelf() && (comTy.getRecId() != baseTy.getRecId()))
219+
return false;
220+
}
221+
}
222+
}
223+
return true;
224+
}
225+
162226
mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
163227
fir::RecordType Ty, mlir::LLVM::DIFileAttr fileAttr,
164228
mlir::LLVM::DIScopeAttr scope, fir::cg::XDeclareOp declOp) {
@@ -217,7 +281,13 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
217281
/*baseType=*/nullptr, mlir::LLVM::DIFlags::Zero, offset * 8,
218282
/*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr,
219283
/*allocated=*/nullptr, /*associated=*/nullptr);
220-
typeCache[Ty] = finalAttr;
284+
if (canCacheThisType(finalAttr)) {
285+
typeCache[Ty] = finalAttr;
286+
} else {
287+
auto iter = typeCache.find(Ty);
288+
if (iter != typeCache.end())
289+
typeCache.erase(iter);
290+
}
221291
return finalAttr;
222292
}
223293

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
2+
3+
! mainly test that this program does not cause an assertion failure
4+
module m
5+
type t2
6+
type(t1), pointer :: p1
7+
end type
8+
type t1
9+
type(t2), pointer :: p2
10+
integer abc
11+
end type
12+
type(t1) :: tee1
13+
end module
14+
15+
program test
16+
use m
17+
type(t2) :: lc2
18+
print *, lc2%p1%abc
19+
end program test
20+
21+
! CHECK-DAG: DICompositeType(tag: DW_TAG_structure_type, name: "t1"{{.*}})
22+
! CHECK-DAG: DICompositeType(tag: DW_TAG_structure_type, name: "t2"{{.*}})

0 commit comments

Comments
 (0)