1414
1515#include " DebugTypeGenerator.h"
1616#include " flang/Optimizer/CodeGen/DescriptorModel.h"
17- #include " flang/Optimizer/CodeGen/TypeConverter.h"
1817#include " flang/Optimizer/Support/InternalNames.h"
1918#include " mlir/Pass/Pass.h"
2019#include " llvm/ADT/ScopeExit.h"
@@ -48,7 +47,7 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m,
4847 mlir::SymbolTable *symbolTable_,
4948 const mlir::DataLayout &dl)
5049 : module (m), symbolTable(symbolTable_), dataLayout{&dl},
51- kindMapping (getKindMapping(m)) {
50+ kindMapping (getKindMapping(m)), llvmTypeConverter(m, false , false , dl) {
5251 LLVM_DEBUG (llvm::dbgs () << " DITypeAttr generator\n " );
5352
5453 mlir::MLIRContext *context = module .getContext ();
@@ -160,29 +159,110 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
160159 dataLocation, /* rank=*/ nullptr , allocated, associated);
161160}
162161
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+
163226mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType (
164227 fir::RecordType Ty, mlir::LLVM::DIFileAttr fileAttr,
165228 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;
166235 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+
167247 auto result = fir::NameUniquer::deconstruct (Ty.getName ());
168248 if (result.first != fir::NameUniquer::NameKind::DERIVED_TYPE)
169249 return genPlaceholderType (context);
170250
171251 fir::TypeInfoOp tiOp = symbolTable->lookup <fir::TypeInfoOp>(Ty.getName ());
172252 unsigned line = (tiOp) ? getLineFromLoc (tiOp.getLoc ()) : 1 ;
173253
174- llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
175254 std::uint64_t offset = 0 ;
176255 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+
185263 // FIXME: Handle non defaults array bound in derived types
264+ uint64_t byteSize = dataLayout->getTypeSize (llvmTy);
265+ unsigned short byteAlign = dataLayout->getTypeABIAlignment (llvmTy);
186266 mlir::LLVM::DITypeAttr elemTy =
187267 convertType (fieldTy, fileAttr, scope, /* declOp=*/ nullptr );
188268 offset = llvm::alignTo (offset, byteAlign);
@@ -195,12 +275,20 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
195275 offset += llvm::alignTo (byteSize, byteAlign);
196276 }
197277
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,
200280 mlir::StringAttr::get (context, result.second .name ), fileAttr, line, scope,
201281 /* baseType=*/ nullptr , mlir::LLVM::DIFlags::Zero, offset * 8 ,
202282 /* alignInBits=*/ 0 , elements, /* dataLocation=*/ nullptr , /* rank=*/ nullptr ,
203283 /* 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;
204292}
205293
206294mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType (
0 commit comments