14
14
15
15
#include " DebugTypeGenerator.h"
16
16
#include " flang/Optimizer/CodeGen/DescriptorModel.h"
17
- #include " flang/Optimizer/CodeGen/TypeConverter.h"
18
17
#include " flang/Optimizer/Support/InternalNames.h"
19
18
#include " mlir/Pass/Pass.h"
20
19
#include " llvm/ADT/ScopeExit.h"
@@ -48,7 +47,7 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m,
48
47
mlir::SymbolTable *symbolTable_,
49
48
const mlir::DataLayout &dl)
50
49
: module (m), symbolTable(symbolTable_), dataLayout{&dl},
51
- kindMapping (getKindMapping(m)) {
50
+ kindMapping (getKindMapping(m)), llvmTypeConverter(m, false , false , dl) {
52
51
LLVM_DEBUG (llvm::dbgs () << " DITypeAttr generator\n " );
53
52
54
53
mlir::MLIRContext *context = module .getContext ();
@@ -160,29 +159,110 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
160
159
dataLocation, /* rank=*/ nullptr , allocated, associated);
161
160
}
162
161
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
+
163
226
mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType (
164
227
fir::RecordType Ty, mlir::LLVM::DIFileAttr fileAttr,
165
228
mlir::LLVM::DIScopeAttr scope, fir::cg::XDeclareOp declOp) {
229
+ // Check if this type has already been converted.
230
+ auto iter = typeCache.find (Ty);
231
+ if (iter != typeCache.end ())
232
+ return iter->second ;
233
+
234
+ llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
166
235
mlir::MLIRContext *context = module .getContext ();
236
+ auto recId = mlir::DistinctAttr::create (mlir::UnitAttr::get (context));
237
+ // Generate a place holder TypeAttr which will be used if a member
238
+ // references the parent type.
239
+ auto comAttr = mlir::LLVM::DICompositeTypeAttr::get (
240
+ context, recId, /* isRecSelf=*/ true , llvm::dwarf::DW_TAG_structure_type,
241
+ mlir::StringAttr::get (context, " " ), fileAttr, /* line=*/ 0 , scope,
242
+ /* baseType=*/ nullptr , mlir::LLVM::DIFlags::Zero, /* sizeInBits=*/ 0 ,
243
+ /* alignInBits=*/ 0 , elements, /* dataLocation=*/ nullptr , /* rank=*/ nullptr ,
244
+ /* allocated=*/ nullptr , /* associated=*/ nullptr );
245
+ typeCache[Ty] = comAttr;
246
+
167
247
auto result = fir::NameUniquer::deconstruct (Ty.getName ());
168
248
if (result.first != fir::NameUniquer::NameKind::DERIVED_TYPE)
169
249
return genPlaceholderType (context);
170
250
171
251
fir::TypeInfoOp tiOp = symbolTable->lookup <fir::TypeInfoOp>(Ty.getName ());
172
252
unsigned line = (tiOp) ? getLineFromLoc (tiOp.getLoc ()) : 1 ;
173
253
174
- llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
175
254
std::uint64_t offset = 0 ;
176
255
for (auto [fieldName, fieldTy] : Ty.getTypeList ()) {
177
- auto result = fir::getTypeSizeAndAlignment (module .getLoc (), fieldTy,
178
- *dataLayout, kindMapping);
179
- // If we get a type whose size we can't determine, we will break the loop
180
- // and generate the derived type with whatever components we have
181
- // assembled thus far.
182
- if (!result)
183
- break ;
184
- auto [byteSize, byteAlign] = *result;
256
+ mlir::Type llvmTy;
257
+ if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(fieldTy))
258
+ llvmTy =
259
+ llvmTypeConverter.convertBoxTypeAsStruct (boxTy, getBoxRank (boxTy));
260
+ else
261
+ llvmTy = llvmTypeConverter.convertType (fieldTy);
262
+
185
263
// FIXME: Handle non defaults array bound in derived types
264
+ uint64_t byteSize = dataLayout->getTypeSize (llvmTy);
265
+ unsigned short byteAlign = dataLayout->getTypeABIAlignment (llvmTy);
186
266
mlir::LLVM::DITypeAttr elemTy =
187
267
convertType (fieldTy, fileAttr, scope, /* declOp=*/ nullptr );
188
268
offset = llvm::alignTo (offset, byteAlign);
@@ -195,12 +275,20 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
195
275
offset += llvm::alignTo (byteSize, byteAlign);
196
276
}
197
277
198
- return mlir::LLVM::DICompositeTypeAttr::get (
199
- context, llvm::dwarf::DW_TAG_structure_type,
278
+ auto finalAttr = mlir::LLVM::DICompositeTypeAttr::get (
279
+ context, recId, /* isRecSelf= */ false , llvm::dwarf::DW_TAG_structure_type,
200
280
mlir::StringAttr::get (context, result.second .name ), fileAttr, line, scope,
201
281
/* baseType=*/ nullptr , mlir::LLVM::DIFlags::Zero, offset * 8 ,
202
282
/* alignInBits=*/ 0 , elements, /* dataLocation=*/ nullptr , /* rank=*/ nullptr ,
203
283
/* allocated=*/ nullptr , /* associated=*/ nullptr );
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
+ }
291
+ return finalAttr;
204
292
}
205
293
206
294
mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType (
0 commit comments