[flang-commits] [flang] [flang][debug] Support derived type components with box types. (PR #109424)
Abid Qadeer via flang-commits
flang-commits at lists.llvm.org
Wed Sep 25 10:49:29 PDT 2024
https://github.com/abidh updated https://github.com/llvm/llvm-project/pull/109424
>From d362deab0a2efb794d52aa23b77999a88d300acd Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Mon, 16 Sep 2024 20:10:20 +0100
Subject: [PATCH 1/6] [flang][debug] Support derived type components with box
types.
Our support for derived types uses `getTypeSizeAndAlignment` to calculate
the offset of the members. The `fir.box` was not supported in that
function. It meant that any member which required descriptor was not
supported in the derived type.
This PR enhances `getTypeSizeAndAlignment` to support `fir.box`. The
implementation uses the following formula to calculate the size.
size = offset_of_dims_field + (rank * size_of_dims_field)
If an addendum is required then size of its 2 field is also added to the
final size.
The code to calculate the offset of the descriptor was already present
in the `DebugTypeGenerator.cpp`. It has been moved to a separate file
so that it can be used in multiple places.
There are 2 other changes in this PR:
1. The recID field is used to handle cases where we have a member
references its parent type.
2. A type cache is maintained to avoid duplication. It is also needed
for circular reference case.
Fixes #108001.
---
.../Optimizer/CodeGen/DescriptorOffsets.h | 39 +++++++++++++++++++
flang/lib/Optimizer/Dialect/FIRType.cpp | 28 +++++++++++++
.../Transforms/DebugTypeGenerator.cpp | 32 +++++++++++----
.../Optimizer/Transforms/DebugTypeGenerator.h | 1 +
.../test/Transforms/debug-derived-type-1.fir | 35 ++++++++++++++---
5 files changed, 122 insertions(+), 13 deletions(-)
create mode 100644 flang/include/flang/Optimizer/CodeGen/DescriptorOffsets.h
diff --git a/flang/include/flang/Optimizer/CodeGen/DescriptorOffsets.h b/flang/include/flang/Optimizer/CodeGen/DescriptorOffsets.h
new file mode 100644
index 00000000000000..1d62197f38fca3
--- /dev/null
+++ b/flang/include/flang/Optimizer/CodeGen/DescriptorOffsets.h
@@ -0,0 +1,39 @@
+//===-- DescriptorOffsets.h -- offsets of descriptors fields ---*- C++ -*-====//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPTIMIZER_DESCRIPTOR_OFFSETS_H
+#define OPTIMIZER_DESCRIPTOR_OFFSETS_H
+
+#include "flang/Optimizer/CodeGen/DescriptorModel.h"
+
+namespace fir {
+
+/// Calculate offset of any field in the descriptor.
+template <int Field>
+static std::uint64_t getDescComponentOffset(const mlir::DataLayout &dl,
+ mlir::MLIRContext *context,
+ mlir::Type fieldType) {
+ static_assert(Field > 0 && Field < 8);
+ mlir::Type previousFieldType = getDescFieldTypeModel<Field - 1>()(context);
+ std::uint64_t previousOffset =
+ getDescComponentOffset<Field - 1>(dl, context, previousFieldType);
+ std::uint64_t offset = previousOffset + dl.getTypeSize(previousFieldType);
+ std::uint64_t fieldAlignment = dl.getTypeABIAlignment(fieldType);
+ return llvm::alignTo(offset, fieldAlignment);
+}
+
+template <>
+std::uint64_t getDescComponentOffset<0>(const mlir::DataLayout &dl,
+ mlir::MLIRContext *context,
+ mlir::Type fieldType) {
+ return 0;
+}
+
+} // namespace fir
+
+#endif // OPTIMIZER_DESCRIPTOR_OFFSETS_H
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 05f644654efe1b..694c66e2fc9969 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -13,6 +13,9 @@
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/ISO_Fortran_binding_wrapper.h"
#include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/CodeGen/DescriptorModel.h"
+#include "flang/Optimizer/CodeGen/DescriptorOffsets.h"
+#include "flang/Optimizer/CodeGen/TypeConverter.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "flang/Tools/PointerModels.h"
@@ -1455,6 +1458,31 @@ fir::getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty,
compSize *= character.getLen();
return std::pair{compSize, compAlign};
}
+ if (auto boxTy = mlir::dyn_cast<fir::BoxType>(ty)) {
+ mlir::MLIRContext *context = boxTy.getContext();
+ mlir::Type ptrType = getDescFieldTypeModel<kAddrPosInBox>()(context);
+ mlir::Type dimsType = getDescFieldTypeModel<kDimsPosInBox>()(context);
+ std::uint64_t size =
+ getDescComponentOffset<kDimsPosInBox>(dl, context, dimsType);
+ unsigned rank = getBoxRank(ty);
+ if (rank > 0) {
+ std::uint64_t dimsSize = dl.getTypeSize(dimsType);
+ size += (rank * dimsSize);
+ }
+ if (boxHasAddendum(boxTy)) {
+ mlir::Type optType =
+ getExtendedDescFieldTypeModel<kOptTypePtrPosInBox>()(context);
+ mlir::Type rowType =
+ getExtendedDescFieldTypeModel<kOptRowTypePosInBox>()(context);
+ std::uint64_t fieldSize = dl.getTypeSize(optType);
+ std::uint64_t fieldAlignment = dl.getTypeABIAlignment(optType);
+ size += llvm::alignTo(fieldSize, fieldAlignment);
+ fieldSize = dl.getTypeSize(rowType);
+ fieldAlignment = dl.getTypeABIAlignment(rowType);
+ size += llvm::alignTo(fieldSize, fieldAlignment);
+ }
+ return std::pair{size, (unsigned short)dl.getTypeSize(ptrType)};
+ }
return std::nullopt;
}
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index 1390fae062b934..65784224e07339 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -13,7 +13,7 @@
#define DEBUG_TYPE "flang-debug-type-generator"
#include "DebugTypeGenerator.h"
-#include "flang/Optimizer/CodeGen/DescriptorModel.h"
+#include "flang/Optimizer/CodeGen/DescriptorOffsets.h"
#include "flang/Optimizer/CodeGen/TypeConverter.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "mlir/Pass/Pass.h"
@@ -59,11 +59,11 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m,
mlir::Type llvmPtrType = getDescFieldTypeModel<kAddrPosInBox>()(context);
mlir::Type llvmLenType = getDescFieldTypeModel<kElemLenPosInBox>()(context);
dimsOffset =
- getComponentOffset<kDimsPosInBox>(*dataLayout, context, llvmDimsType);
+ getDescComponentOffset<kDimsPosInBox>(*dataLayout, context, llvmDimsType);
dimsSize = dataLayout->getTypeSize(llvmDimsType);
ptrSize = dataLayout->getTypeSize(llvmPtrType);
- lenOffset =
- getComponentOffset<kElemLenPosInBox>(*dataLayout, context, llvmLenType);
+ lenOffset = getDescComponentOffset<kElemLenPosInBox>(*dataLayout, context,
+ llvmLenType);
}
static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
@@ -163,7 +163,24 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
fir::RecordType Ty, mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scope, fir::cg::XDeclareOp declOp) {
+ // Check if this type has already been converted.
+ auto iter = typeCache.find(Ty);
+ if (iter != typeCache.end())
+ return iter->second;
+
+ llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
mlir::MLIRContext *context = module.getContext();
+ auto recId = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
+ // Generate a place holder TypeAttr which will be used if a member
+ // references the parent type.
+ auto comAttr = mlir::LLVM::DICompositeTypeAttr::get(
+ context, recId, /*isRecSelf=*/true, llvm::dwarf::DW_TAG_structure_type,
+ mlir::StringAttr::get(context, ""), fileAttr, /*line=*/0, scope,
+ /*baseType=*/nullptr, mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0,
+ /*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr,
+ /*allocated=*/nullptr, /*associated=*/nullptr);
+ typeCache[Ty] = comAttr;
+
auto result = fir::NameUniquer::deconstruct(Ty.getName());
if (result.first != fir::NameUniquer::NameKind::DERIVED_TYPE)
return genPlaceholderType(context);
@@ -171,7 +188,6 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
fir::TypeInfoOp tiOp = symbolTable->lookup<fir::TypeInfoOp>(Ty.getName());
unsigned line = (tiOp) ? getLineFromLoc(tiOp.getLoc()) : 1;
- llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
std::uint64_t offset = 0;
for (auto [fieldName, fieldTy] : Ty.getTypeList()) {
auto result = fir::getTypeSizeAndAlignment(module.getLoc(), fieldTy,
@@ -195,12 +211,14 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
offset += llvm::alignTo(byteSize, byteAlign);
}
- return mlir::LLVM::DICompositeTypeAttr::get(
- context, llvm::dwarf::DW_TAG_structure_type,
+ auto finalAttr = mlir::LLVM::DICompositeTypeAttr::get(
+ context, recId, /*isRecSelf=*/false, llvm::dwarf::DW_TAG_structure_type,
mlir::StringAttr::get(context, result.second.name), fileAttr, line, scope,
/*baseType=*/nullptr, mlir::LLVM::DIFlags::Zero, offset * 8,
/*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr,
/*allocated=*/nullptr, /*associated=*/nullptr);
+ typeCache[Ty] = finalAttr;
+ return finalAttr;
}
mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType(
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
index e3220f18958df2..104f3591d5ba8a 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
@@ -72,6 +72,7 @@ class DebugTypeGenerator {
std::uint64_t dimsOffset;
std::uint64_t ptrSize;
std::uint64_t lenOffset;
+ llvm::DenseMap<mlir::Type, mlir::LLVM::DITypeAttr> typeCache;
};
} // namespace fir
diff --git a/flang/test/Transforms/debug-derived-type-1.fir b/flang/test/Transforms/debug-derived-type-1.fir
index e453db6ae6fbb7..26f7017f5f5a38 100644
--- a/flang/test/Transforms/debug-derived-type-1.fir
+++ b/flang/test/Transforms/debug-derived-type-1.fir
@@ -12,12 +12,18 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr<272>, d
%0 = fir.zero_bits !fir.type<_QMt1Tt_t1{age:i32,points:!fir.array<3x!fir.complex<4>>,cond:!fir.logical<1>,name:!fir.char<1,20>,ratio:f64}>
fir.has_value %0 : !fir.type<_QMt1Tt_t1{age:i32,points:!fir.array<3x!fir.complex<4>>,cond:!fir.logical<1>,name:!fir.char<1,20>,ratio:f64}>
} loc(#loc6)
+ fir.global @_QMtest_1Exyz : !fir.type<_QMtest_1Tsometype{m_array:!fir.array<3xi32>,m_vt1:!fir.box<!fir.heap<!fir.type<_QMtest_1Tt1{name:!fir.char<1,20>,height:f32}>>>,v2:i32,m_alloc:!fir.box<!fir.heap<!fir.array<?xi32>>>,v3:i32,m_first:!fir.box<!fir.heap<!fir.char<1,?>>>,v4:i32,m_p1:!fir.box<!fir.ptr<i32>>,v5:i32,m_p2:!fir.box<!fir.ptr<i32>>,v6:i32,m_p3:!fir.box<!fir.ptr<!fir.array<?xi32>>>,v7:i32}> {
+ %0 = fir.zero_bits !fir.type<_QMtest_1Tsometype{m_array:!fir.array<3xi32>,m_vt1:!fir.box<!fir.heap<!fir.type<_QMtest_1Tt1{name:!fir.char<1,20>,height:f32}>>>,v2:i32,m_alloc:!fir.box<!fir.heap<!fir.array<?xi32>>>,v3:i32,m_first:!fir.box<!fir.heap<!fir.char<1,?>>>,v4:i32,m_p1:!fir.box<!fir.ptr<i32>>,v5:i32,m_p2:!fir.box<!fir.ptr<i32>>,v6:i32,m_p3:!fir.box<!fir.ptr<!fir.array<?xi32>>>,v7:i32}>
+ fir.has_value %0 : !fir.type<_QMtest_1Tsometype{m_array:!fir.array<3xi32>,m_vt1:!fir.box<!fir.heap<!fir.type<_QMtest_1Tt1{name:!fir.char<1,20>,height:f32}>>>,v2:i32,m_alloc:!fir.box<!fir.heap<!fir.array<?xi32>>>,v3:i32,m_first:!fir.box<!fir.heap<!fir.char<1,?>>>,v4:i32,m_p1:!fir.box<!fir.ptr<i32>>,v5:i32,m_p2:!fir.box<!fir.ptr<i32>>,v6:i32,m_p3:!fir.box<!fir.ptr<!fir.array<?xi32>>>,v7:i32}>
+ } loc(#loc12)
fir.type_info @_QMt1Tt_t1 noinit nodestroy nofinal : !fir.type<_QMt1Tt_t1{age:i32,points:!fir.array<3x!fir.complex<4>>,cond:!fir.logical<1>,name:!fir.char<1,20>,ratio:f64}> loc(#loc7)
fir.type_info @_QMm_employeeTt_address noinit nodestroy nofinal : !fir.type<_QMm_employeeTt_address{house_number:i32}> loc(#loc1)
fir.type_info @_QMm_employeeTt_person noinit nodestroy nofinal extends !fir.type<_QMm_employeeTt_address{house_number:i32}> : !fir.type<_QMm_employeeTt_person{t_address:!fir.type<_QMm_employeeTt_address{house_number:i32}>,name:!fir.char<1,20>}> loc(#loc2)
fir.type_info @_QMm_employeeTt_date noinit nodestroy nofinal : !fir.type<_QMm_employeeTt_date{year:i32,month:i32,day:i32}> loc(#loc3)
fir.type_info @_QMm_employeeTt_employee noinit nodestroy nofinal extends !fir.type<_QMm_employeeTt_person{t_address:!fir.type<_QMm_employeeTt_address{house_number:i32}>,name:!fir.char<1,20>}> : !fir.type<_QMm_employeeTt_employee{t_person:!fir.type<_QMm_employeeTt_person{t_address:!fir.type<_QMm_employeeTt_address{house_number:i32}>,name:!fir.char<1,20>}>,hired_date:!fir.type<_QMm_employeeTt_date{year:i32,month:i32,day:i32}>,monthly_salary:f32}> loc(#loc4)
fir.type_info @_QFTt_pair noinit nodestroy nofinal : !fir.type<_QFTt_pair{i:i64,x:f64}> loc(#loc8)
+ fir.type_info @_QMtest_1Tt1 noinit nodestroy nofinal : !fir.type<_QMtest_1Tt1{name:!fir.char<1,20>,height:f32}> loc(#loc11)
+ fir.type_info @_QMtest_1Tsometype nofinal : !fir.type<_QMtest_1Tsometype{m_array:!fir.array<3xi32>,m_vt1:!fir.box<!fir.heap<!fir.type<_QMtest_1Tt1{name:!fir.char<1,20>,height:f32}>>>,v2:i32,m_alloc:!fir.box<!fir.heap<!fir.array<?xi32>>>,v3:i32,m_first:!fir.box<!fir.heap<!fir.char<1,?>>>,v4:i32,m_p1:!fir.box<!fir.ptr<i32>>,v5:i32,m_p2:!fir.box<!fir.ptr<i32>>,v6:i32,m_p3:!fir.box<!fir.ptr<!fir.array<?xi32>>>,v7:i32}> loc(#loc12)
func.func @_QQmain() attributes {fir.bindc_name = "test"} {
%1 = fir.alloca !fir.type<_QFTt_pair{i:i64,x:f64}> {bindc_name = "pair", uniq_name = "_QFEpair"}
%2 = fircg.ext_declare %1 {uniq_name = "_QFEpair"} : (!fir.ref<!fir.type<_QFTt_pair{i:i64,x:f64}>>) -> !fir.ref<!fir.type<_QFTt_pair{i:i64,x:f64}>> loc(#loc9)
@@ -34,6 +40,8 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr<272>, d
#loc8 = loc("derived1.f90":85:3)
#loc9 = loc("derived1.f90":77:3)
#loc10 = loc("derived1.f90":75:3)
+#loc11 = loc("derived1.f90":95:3)
+#loc12 = loc("derived1.f90":105:3)
// CHECK-DAG: #[[INT_TY:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "integer", sizeInBits = 32, encoding = DW_ATE_signed>
@@ -47,27 +55,42 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr<272>, d
// CHECK-DAG: #[[MOD:.*]] = #llvm.di_module<{{.*}}name = "m_employee"{{.*}}>
// CHECK-DAG: #[[MOD1:.*]] = #llvm.di_module<{{.*}}name = "t1"{{.*}}>
// CHECK-DAG: #[[ELMA1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "house_number", baseType = #[[INT_TY]], sizeInBits = 32, alignInBits = 32>
-// CHECK-DAG: #[[ADDR:.*]] = #llvm.di_composite_type<tag = DW_TAG_structure_type, name = "t_address"{{.*}}line = 24, scope = #[[MOD]], sizeInBits = 32, elements = #[[ELMA1]]>
+// CHECK-DAG: #[[ADDR:.*]] = #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_address"{{.*}}line = 24, scope = #[[MOD]], sizeInBits = 32, elements = #[[ELMA1]]>
// CHECK-DAG: #[[ELMD1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "year", baseType = #[[INT_TY]], sizeInBits = 32, alignInBits = 32>
// CHECK-DAG: #[[ELMD2:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "month", baseType = #[[INT_TY]], sizeInBits = 32, alignInBits = 32, offsetInBits = 32>
// CHECK-DAG: #[[ELMD3:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "day", baseType = #[[INT_TY]], sizeInBits = 32, alignInBits = 32, offsetInBits = 64>
-// CHECK-DAG: #[[DATE:.*]] = #llvm.di_composite_type<tag = DW_TAG_structure_type, name = "t_date", file = #di_file, line = 17, scope = #[[MOD]], sizeInBits = 96, elements = #[[ELMD1]], #[[ELMD2]], #[[ELMD3]]>
+// CHECK-DAG: #[[DATE:.*]] = #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_date", file = #di_file, line = 17, scope = #[[MOD]], sizeInBits = 96, elements = #[[ELMD1]], #[[ELMD2]], #[[ELMD3]]>
// CHECK-DAG: #[[ELMP1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "t_address", baseType = #[[ADDR]], sizeInBits = 32, alignInBits = 32>
// CHECK-DAG: #[[ELMP2:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "name", baseType = #[[STR_TY]], sizeInBits = 160, alignInBits = 8, offsetInBits = 32>
-// CHECK-DAG: #[[PERS:.*]] = #llvm.di_composite_type<tag = DW_TAG_structure_type, name = "t_person"{{.*}}line = 35, scope = #[[MOD]], sizeInBits = 192, elements = #[[ELMP1]], #[[ELMP2]]>
+// CHECK-DAG: #[[PERS:.*]] = #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_person"{{.*}}line = 35, scope = #[[MOD]], sizeInBits = 192, elements = #[[ELMP1]], #[[ELMP2]]>
// CHECK-DAG: #[[ELME1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "t_person", baseType = #[[PERS]], sizeInBits = 192, alignInBits = 32>
// CHECK-DAG: #[[ELME2:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "hired_date", baseType = #[[DATE]], sizeInBits = 96, alignInBits = 32, offsetInBits = 192>
// CHECK-DAG: #[[ELME3:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "monthly_salary", baseType = #[[REAL4_TY]], sizeInBits = 32, alignInBits = 32, offsetInBits = 288>
-// CHECK-DAG: #[[EMP:.*]] = #llvm.di_composite_type<tag = DW_TAG_structure_type, name = "t_employee"{{.*}}line = 46, scope = #[[MOD]], sizeInBits = 320, elements = #[[ELME1]], #[[ELME2]], #[[ELME3]]>
+// CHECK-DAG: #[[EMP:.*]] = #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_employee"{{.*}}line = 46, scope = #[[MOD]], sizeInBits = 320, elements = #[[ELME1]], #[[ELME2]], #[[ELME3]]>
// CHECK-DAG: #[[ELM1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "age", baseType = #[[INT_TY]], sizeInBits = 32, alignInBits = 32>
// CHECK-DAG: #[[ELM2:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "points", baseType = #[[CMX_ARR]], sizeInBits = 192, alignInBits = 32, offsetInBits = 32>
// CHECK-DAG: #[[ELM3:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "cond", baseType = #[[LOG_TY]], sizeInBits = 8, alignInBits = 8, offsetInBits = 224>
// CHECK-DAG: #[[ELM4:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "name", baseType = #[[STR_TY]], sizeInBits = 160, alignInBits = 8, offsetInBits = 232>
// CHECK-DAG: #[[ELM5:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "ratio", baseType = #[[REAL8_TY]], sizeInBits = 64, alignInBits = 64, offsetInBits = 448>
-// CHECK-DAG: #llvm.di_composite_type<tag = DW_TAG_structure_type, name = "t_t1"{{.*}}, line = 70, scope = #[[MOD1]], sizeInBits = 512, elements = #[[ELM1]], #[[ELM2]], #[[ELM3]], #[[ELM4]], #[[ELM5]]>
+// CHECK-DAG: #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_t1"{{.*}}, line = 70, scope = #[[MOD1]], sizeInBits = 512, elements = #[[ELM1]], #[[ELM2]], #[[ELM3]], #[[ELM4]], #[[ELM5]]>
// CHECK-DAG: #[[SP:.*]] = #llvm.di_subprogram
// CHECK-DAG: #[[ELML1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "i", baseType = #[[INT8_TY]], sizeInBits = 64, alignInBits = 64>
// CHECK-DAG: #[[ELML2:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "x", baseType = #[[REAL8_TY]], sizeInBits = 64, alignInBits = 64, offsetInBits = 64>
-// CHECK-DAG: #llvm.di_composite_type<tag = DW_TAG_structure_type, name = "t_pair"{{.*}}line = 85, scope = #di_subprogram, sizeInBits = 128, elements = #[[ELML1]], #[[ELML2]]>
+// CHECK-DAG: #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_pair"{{.*}}line = 85, scope = #di_subprogram, sizeInBits = 128, elements = #[[ELML1]], #[[ELML2]]>
+
+// CHECK-DAG: #[[E1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "m_array", baseType = #{{.*}}, sizeInBits = 96, alignInBits = 32>
+// CHECK-DAG: #[[E2:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "m_vt1", baseType = #{{.*}}, sizeInBits = 320, alignInBits = 64, offsetInBits = 128>
+// CHECK-DAG: #[[E3:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "v2", baseType = #{{.*}}, sizeInBits = 32, alignInBits = 32, offsetInBits = 448>
+// CHECK-DAG: #[[E4:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "m_alloc", baseType = #{{.*}}, sizeInBits = 384, alignInBits = 64, offsetInBits = 512>
+// CHECK-DAG: #[[E5:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "v3", baseType = #{{.*}}, sizeInBits = 32, alignInBits = 32, offsetInBits = 896>
+// CHECK-DAG: #[[E6:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "m_first", baseType = #{{.*}}, sizeInBits = 192, alignInBits = 64, offsetInBits = 960>
+// CHECK-DAG: #[[E7:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "v4", baseType = #{{.*}}, sizeInBits = 32, alignInBits = 32, offsetInBits = 1152>
+// CHECK-DAG: #[[E8:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "m_p1", baseType = #{{.*}}, sizeInBits = 192, alignInBits = 64, offsetInBits = 1216>
+// CHECK-DAG: #[[E9:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "v5", baseType = #{{.*}}, sizeInBits = 32, alignInBits = 32, offsetInBits = 1408>
+// CHECK-DAG: #[[E10:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "m_p2", baseType = #{{.*}}, sizeInBits = 192, alignInBits = 64, offsetInBits = 1472>
+// CHECK-DAG: #[[E11:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "v6", baseType = #{{.*}}, sizeInBits = 32, alignInBits = 32, offsetInBits = 1664>
+// CHECK-DAG: #[[E12:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "m_p3", baseType = #{{.*}}, sizeInBits = 384, alignInBits = 64, offsetInBits = 1728>
+// CHECK-DAG: #[[E13:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "v7", baseType = #{{.*}}, sizeInBits = 32, alignInBits = 32, offsetInBits = 2112>
+// CHECK-DAG: #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "sometype"{{.*}}sizeInBits = 2144, elements = #[[E1]], #[[E2]], #[[E3]], #[[E4]], #[[E5]], #[[E6]], #[[E7]], #[[E8]], #[[E9]], #[[E10]], #[[E11]], #[[E12]], #[[E13]]>
>From 01739a94cedc86f27fb3dda8615e181d7433adb9 Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Fri, 20 Sep 2024 14:33:45 +0100
Subject: [PATCH 2/6] Update cyclic derived type test.
---
flang/test/Integration/debug-cyclic-derived-type.f90 | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/flang/test/Integration/debug-cyclic-derived-type.f90 b/flang/test/Integration/debug-cyclic-derived-type.f90
index 03e06336a6e084..0325f62a0a9b4f 100644
--- a/flang/test/Integration/debug-cyclic-derived-type.f90
+++ b/flang/test/Integration/debug-cyclic-derived-type.f90
@@ -11,5 +11,11 @@ module m
type(t2) :: v3
end module
-! CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "t1"{{.*}})
-! CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "t2"{{.*}})
+! CHECK-DAG: ![[T1:[0-9]+]] = {{.*}}!DICompositeType(tag: DW_TAG_structure_type, name: "t1"{{.*}}elements: ![[T1_ELEMS:[0-9]+]])
+! CHECK-DAG: ![[T1_ELEMS]] = !{![[T1_ELEM1:[0-9]+]]}
+! CHECK-DAG: ![[T1_ELEM1]] = !DIDerivedType(tag: DW_TAG_member, name: "p", baseType: ![[T2P:[0-9]+]]{{.*}})
+! CHECK-DAG: ![[T2P]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[T2:[0-9]+]]{{.*}})
+
+! CHECK-DAG: ![[T2]] = {{.*}}!DICompositeType(tag: DW_TAG_structure_type, name: "t2"{{.*}}elements: ![[T2_ELEMS:[0-9]+]])
+! CHECK-DAG: ![[T2_ELEMS]] = !{![[T2_ELEM1:[0-9]+]]}
+! CHECK-DAG: ![[T2_ELEM1]] = !DIDerivedType(tag: DW_TAG_member, name: "v1", baseType: ![[T1]]{{.*}})
\ No newline at end of file
>From 4f81e4de55047f5a12f25d9fe4df57a817c846d2 Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Fri, 20 Sep 2024 21:28:06 +0100
Subject: [PATCH 3/6] Add new line at the end of file.
---
flang/test/Integration/debug-cyclic-derived-type.f90 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/test/Integration/debug-cyclic-derived-type.f90 b/flang/test/Integration/debug-cyclic-derived-type.f90
index 0325f62a0a9b4f..a26ffd19ef6b1e 100644
--- a/flang/test/Integration/debug-cyclic-derived-type.f90
+++ b/flang/test/Integration/debug-cyclic-derived-type.f90
@@ -18,4 +18,4 @@ module m
! CHECK-DAG: ![[T2]] = {{.*}}!DICompositeType(tag: DW_TAG_structure_type, name: "t2"{{.*}}elements: ![[T2_ELEMS:[0-9]+]])
! CHECK-DAG: ![[T2_ELEMS]] = !{![[T2_ELEM1:[0-9]+]]}
-! CHECK-DAG: ![[T2_ELEM1]] = !DIDerivedType(tag: DW_TAG_member, name: "v1", baseType: ![[T1]]{{.*}})
\ No newline at end of file
+! CHECK-DAG: ![[T2_ELEM1]] = !DIDerivedType(tag: DW_TAG_member, name: "v1", baseType: ![[T1]]{{.*}})
>From 2e726b3883a3f56d8fc1912f8636e49f48448a16 Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Tue, 24 Sep 2024 17:17:05 +0100
Subject: [PATCH 4/6] Handle review comments.
Use LLVMTypeConverter to convert the fir.box into an mlir::Type and then get its size from DataLayout.
---
.../Optimizer/CodeGen/DescriptorOffsets.h | 39 -------------------
flang/lib/Optimizer/Dialect/FIRType.cpp | 28 -------------
.../Transforms/DebugTypeGenerator.cpp | 27 +++++++------
3 files changed, 15 insertions(+), 79 deletions(-)
delete mode 100644 flang/include/flang/Optimizer/CodeGen/DescriptorOffsets.h
diff --git a/flang/include/flang/Optimizer/CodeGen/DescriptorOffsets.h b/flang/include/flang/Optimizer/CodeGen/DescriptorOffsets.h
deleted file mode 100644
index 1d62197f38fca3..00000000000000
--- a/flang/include/flang/Optimizer/CodeGen/DescriptorOffsets.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===-- DescriptorOffsets.h -- offsets of descriptors fields ---*- C++ -*-====//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef OPTIMIZER_DESCRIPTOR_OFFSETS_H
-#define OPTIMIZER_DESCRIPTOR_OFFSETS_H
-
-#include "flang/Optimizer/CodeGen/DescriptorModel.h"
-
-namespace fir {
-
-/// Calculate offset of any field in the descriptor.
-template <int Field>
-static std::uint64_t getDescComponentOffset(const mlir::DataLayout &dl,
- mlir::MLIRContext *context,
- mlir::Type fieldType) {
- static_assert(Field > 0 && Field < 8);
- mlir::Type previousFieldType = getDescFieldTypeModel<Field - 1>()(context);
- std::uint64_t previousOffset =
- getDescComponentOffset<Field - 1>(dl, context, previousFieldType);
- std::uint64_t offset = previousOffset + dl.getTypeSize(previousFieldType);
- std::uint64_t fieldAlignment = dl.getTypeABIAlignment(fieldType);
- return llvm::alignTo(offset, fieldAlignment);
-}
-
-template <>
-std::uint64_t getDescComponentOffset<0>(const mlir::DataLayout &dl,
- mlir::MLIRContext *context,
- mlir::Type fieldType) {
- return 0;
-}
-
-} // namespace fir
-
-#endif // OPTIMIZER_DESCRIPTOR_OFFSETS_H
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 694c66e2fc9969..05f644654efe1b 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -13,9 +13,6 @@
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/ISO_Fortran_binding_wrapper.h"
#include "flang/Optimizer/Builder/Todo.h"
-#include "flang/Optimizer/CodeGen/DescriptorModel.h"
-#include "flang/Optimizer/CodeGen/DescriptorOffsets.h"
-#include "flang/Optimizer/CodeGen/TypeConverter.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "flang/Tools/PointerModels.h"
@@ -1458,31 +1455,6 @@ fir::getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty,
compSize *= character.getLen();
return std::pair{compSize, compAlign};
}
- if (auto boxTy = mlir::dyn_cast<fir::BoxType>(ty)) {
- mlir::MLIRContext *context = boxTy.getContext();
- mlir::Type ptrType = getDescFieldTypeModel<kAddrPosInBox>()(context);
- mlir::Type dimsType = getDescFieldTypeModel<kDimsPosInBox>()(context);
- std::uint64_t size =
- getDescComponentOffset<kDimsPosInBox>(dl, context, dimsType);
- unsigned rank = getBoxRank(ty);
- if (rank > 0) {
- std::uint64_t dimsSize = dl.getTypeSize(dimsType);
- size += (rank * dimsSize);
- }
- if (boxHasAddendum(boxTy)) {
- mlir::Type optType =
- getExtendedDescFieldTypeModel<kOptTypePtrPosInBox>()(context);
- mlir::Type rowType =
- getExtendedDescFieldTypeModel<kOptRowTypePosInBox>()(context);
- std::uint64_t fieldSize = dl.getTypeSize(optType);
- std::uint64_t fieldAlignment = dl.getTypeABIAlignment(optType);
- size += llvm::alignTo(fieldSize, fieldAlignment);
- fieldSize = dl.getTypeSize(rowType);
- fieldAlignment = dl.getTypeABIAlignment(rowType);
- size += llvm::alignTo(fieldSize, fieldAlignment);
- }
- return std::pair{size, (unsigned short)dl.getTypeSize(ptrType)};
- }
return std::nullopt;
}
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index 65784224e07339..66f3fdb53729d0 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -13,7 +13,7 @@
#define DEBUG_TYPE "flang-debug-type-generator"
#include "DebugTypeGenerator.h"
-#include "flang/Optimizer/CodeGen/DescriptorOffsets.h"
+#include "flang/Optimizer/CodeGen/DescriptorModel.h"
#include "flang/Optimizer/CodeGen/TypeConverter.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "mlir/Pass/Pass.h"
@@ -59,11 +59,11 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m,
mlir::Type llvmPtrType = getDescFieldTypeModel<kAddrPosInBox>()(context);
mlir::Type llvmLenType = getDescFieldTypeModel<kElemLenPosInBox>()(context);
dimsOffset =
- getDescComponentOffset<kDimsPosInBox>(*dataLayout, context, llvmDimsType);
+ getComponentOffset<kDimsPosInBox>(*dataLayout, context, llvmDimsType);
dimsSize = dataLayout->getTypeSize(llvmDimsType);
ptrSize = dataLayout->getTypeSize(llvmPtrType);
- lenOffset = getDescComponentOffset<kElemLenPosInBox>(*dataLayout, context,
- llvmLenType);
+ lenOffset =
+ getComponentOffset<kElemLenPosInBox>(*dataLayout, context, llvmLenType);
}
static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
@@ -189,16 +189,19 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
unsigned line = (tiOp) ? getLineFromLoc(tiOp.getLoc()) : 1;
std::uint64_t offset = 0;
+ LLVMTypeConverter llvmTypeConverter(module, false, false, *dataLayout);
+
for (auto [fieldName, fieldTy] : Ty.getTypeList()) {
- auto result = fir::getTypeSizeAndAlignment(module.getLoc(), fieldTy,
- *dataLayout, kindMapping);
- // If we get a type whose size we can't determine, we will break the loop
- // and generate the derived type with whatever components we have
- // assembled thus far.
- if (!result)
- break;
- auto [byteSize, byteAlign] = *result;
+ mlir::Type llvmTy;
+ if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(fieldTy))
+ llvmTy =
+ llvmTypeConverter.convertBoxTypeAsStruct(boxTy, getBoxRank(boxTy));
+ else
+ llvmTy = llvmTypeConverter.convertType(fieldTy);
+
// FIXME: Handle non defaults array bound in derived types
+ uint64_t byteSize = dataLayout->getTypeSize(llvmTy);
+ unsigned short byteAlign = dataLayout->getTypeABIAlignment(llvmTy);
mlir::LLVM::DITypeAttr elemTy =
convertType(fieldTy, fileAttr, scope, /*declOp=*/nullptr);
offset = llvm::alignTo(offset, byteAlign);
>From 9f162b3e74c816c984ea708755022c7698737407 Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Wed, 25 Sep 2024 15:39:49 +0100
Subject: [PATCH 5/6] Make llvmTypeConverter a class member.
This helps avoid its instantiation for every RecordType.
---
flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp | 5 +----
flang/lib/Optimizer/Transforms/DebugTypeGenerator.h | 2 ++
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index 66f3fdb53729d0..d70a43f17abe46 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -14,7 +14,6 @@
#include "DebugTypeGenerator.h"
#include "flang/Optimizer/CodeGen/DescriptorModel.h"
-#include "flang/Optimizer/CodeGen/TypeConverter.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "mlir/Pass/Pass.h"
#include "llvm/ADT/ScopeExit.h"
@@ -48,7 +47,7 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m,
mlir::SymbolTable *symbolTable_,
const mlir::DataLayout &dl)
: module(m), symbolTable(symbolTable_), dataLayout{&dl},
- kindMapping(getKindMapping(m)) {
+ kindMapping(getKindMapping(m)), llvmTypeConverter(m, false, false, dl) {
LLVM_DEBUG(llvm::dbgs() << "DITypeAttr generator\n");
mlir::MLIRContext *context = module.getContext();
@@ -189,8 +188,6 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
unsigned line = (tiOp) ? getLineFromLoc(tiOp.getLoc()) : 1;
std::uint64_t offset = 0;
- LLVMTypeConverter llvmTypeConverter(module, false, false, *dataLayout);
-
for (auto [fieldName, fieldTy] : Ty.getTypeList()) {
mlir::Type llvmTy;
if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(fieldTy))
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
index 104f3591d5ba8a..b8a068e5ba148b 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
@@ -14,6 +14,7 @@
#define FORTRAN_OPTIMIZER_TRANSFORMS_DEBUGTYPEGENERATOR_H
#include "flang/Optimizer/CodeGen/CGOps.h"
+#include "flang/Optimizer/CodeGen/TypeConverter.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
@@ -68,6 +69,7 @@ class DebugTypeGenerator {
mlir::SymbolTable *symbolTable;
const mlir::DataLayout *dataLayout;
KindMapping kindMapping;
+ fir::LLVMTypeConverter llvmTypeConverter;
std::uint64_t dimsSize;
std::uint64_t dimsOffset;
std::uint64_t ptrSize;
>From a45bef35ea17e91a62adedffc6604d0861bd14fd Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Wed, 25 Sep 2024 17:57:29 +0100
Subject: [PATCH 6/6] 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.
https://github.com/llvm/llvm-project/pull/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.
---
.../Transforms/DebugTypeGenerator.cpp | 72 ++++++++++++++++++-
.../debug-cyclic-derived-type-2.f90 | 22 ++++++
2 files changed, 93 insertions(+), 1 deletion(-)
create mode 100644 flang/test/Integration/debug-cyclic-derived-type-2.f90
diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index d70a43f17abe46..6c25d6327c1b8d 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -159,6 +159,70 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
dataLocation, /*rank=*/nullptr, allocated, associated);
}
+// If the type is a pointer or array type then gets its underlying type.
+static mlir::LLVM::DITypeAttr getUnderlyingType(mlir::LLVM::DITypeAttr Ty) {
+ if (auto ptrTy =
+ mlir::dyn_cast_if_present<mlir::LLVM::DIDerivedTypeAttr>(Ty)) {
+ if (ptrTy.getTag() == llvm::dwarf::DW_TAG_pointer_type)
+ Ty = getUnderlyingType(ptrTy.getBaseType());
+ }
+ if (auto comTy =
+ mlir::dyn_cast_if_present<mlir::LLVM::DICompositeTypeAttr>(Ty)) {
+ if (comTy.getTag() == llvm::dwarf::DW_TAG_array_type)
+ Ty = getUnderlyingType(comTy.getBaseType());
+ }
+ return Ty;
+}
+
+// Currently, the handling of recursive debug type in mlir has some limitations.
+// Those limitations were discussed at the end of the thread for following PR.
+// https://github.com/llvm/llvm-project/pull/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 is. 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. Until this is fixed in mlir, we
+// avoid caching such types. Please see DebugTranslation::translateRecursive for
+// details on how mlir handles recursive types.
+static bool canCacheThisType(mlir::LLVM::DICompositeTypeAttr comTy) {
+ for (auto el : comTy.getElements()) {
+ if (auto mem =
+ mlir::dyn_cast_if_present<mlir::LLVM::DIDerivedTypeAttr>(el)) {
+ mlir::LLVM::DITypeAttr memTy = getUnderlyingType(mem.getBaseType());
+ if (auto baseTy =
+ mlir::dyn_cast_if_present<mlir::LLVM::DICompositeTypeAttr>(
+ memTy)) {
+ // We will not cache a type if one of its member meets the following
+ // conditions:
+ // 1. It is a structure type
+ // 2. It is a place holder type (getIsRecSelf() is true)
+ // 3. It is not a self reference. It is ok to have t1_self in t1.
+ if (baseTy.getTag() == llvm::dwarf::DW_TAG_structure_type &&
+ baseTy.getIsRecSelf() && (comTy.getRecId() != baseTy.getRecId()))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
fir::RecordType Ty, mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scope, fir::cg::XDeclareOp declOp) {
@@ -217,7 +281,13 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
/*baseType=*/nullptr, mlir::LLVM::DIFlags::Zero, offset * 8,
/*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr,
/*allocated=*/nullptr, /*associated=*/nullptr);
- typeCache[Ty] = finalAttr;
+ if (canCacheThisType(finalAttr)) {
+ typeCache[Ty] = finalAttr;
+ } else {
+ auto iter = typeCache.find(Ty);
+ if (iter != typeCache.end())
+ typeCache.erase(iter);
+ }
return finalAttr;
}
diff --git a/flang/test/Integration/debug-cyclic-derived-type-2.f90 b/flang/test/Integration/debug-cyclic-derived-type-2.f90
new file mode 100644
index 00000000000000..c49c9d00957e80
--- /dev/null
+++ b/flang/test/Integration/debug-cyclic-derived-type-2.f90
@@ -0,0 +1,22 @@
+! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
+
+! mainly test that this program does not cause an assertion failure
+module m
+ type t2
+ type(t1), pointer :: p1
+ end type
+ type t1
+ type(t2), pointer :: p2
+ integer abc
+ end type
+ type(t1) :: tee1
+end module
+
+program test
+ use m
+ type(t2) :: lc2
+ print *, lc2%p1%abc
+end program test
+
+! CHECK-DAG: DICompositeType(tag: DW_TAG_structure_type, name: "t1"{{.*}})
+! CHECK-DAG: DICompositeType(tag: DW_TAG_structure_type, name: "t2"{{.*}})
More information about the flang-commits
mailing list