Skip to content

[flang][NFC] Cache derived type translation in lowering #80179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion flang/include/flang/Lower/AbstractConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class CharBlock;
}
namespace semantics {
class Symbol;
class Scope;
class DerivedTypeSpec;
} // namespace semantics

Expand All @@ -59,7 +60,7 @@ struct Variable;
using SomeExpr = Fortran::evaluate::Expr<Fortran::evaluate::SomeType>;
using SymbolRef = Fortran::common::Reference<const Fortran::semantics::Symbol>;
using TypeConstructionStack =
llvm::SmallVector<std::pair<const Fortran::lower::SymbolRef, mlir::Type>>;
llvm::DenseMap<const Fortran::semantics::Scope *, mlir::Type>;
class StatementContext;

using ExprToValueMap = llvm::DenseMap<const SomeExpr *, mlir::Value>;
Expand Down
26 changes: 9 additions & 17 deletions flang/lib/Lower/ConvertType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,19 +374,20 @@ struct TypeBuilderImpl {
mlir::Type genDerivedType(const Fortran::semantics::DerivedTypeSpec &tySpec) {
std::vector<std::pair<std::string, mlir::Type>> ps;
std::vector<std::pair<std::string, mlir::Type>> cs;
const Fortran::semantics::Symbol &typeSymbol = tySpec.typeSymbol();
if (mlir::Type ty = getTypeIfDerivedAlreadyInConstruction(typeSymbol))
return ty;

if (tySpec.IsVectorType()) {
return genVectorType(tySpec);
}

const Fortran::semantics::Symbol &typeSymbol = tySpec.typeSymbol();
const Fortran::semantics::Scope &derivedScope = DEREF(tySpec.GetScope());
if (mlir::Type ty = getTypeIfDerivedAlreadyInConstruction(derivedScope))
return ty;

auto rec = fir::RecordType::get(context, converter.mangleName(tySpec));
// Maintain the stack of types for recursive references.
derivedTypeInConstruction.emplace_back(typeSymbol, rec);
// Maintain the stack of types for recursive references and to speed-up
// the derived type constructions that can be expensive for derived type
// with dozens of components/parents (modern Fortran).
derivedTypeInConstruction.try_emplace(&derivedScope, rec);

// Gather the record type fields.
// (1) The data components.
Expand Down Expand Up @@ -446,7 +447,6 @@ struct TypeBuilderImpl {
}

rec.finalize(ps, cs);
popDerivedTypeInConstruction();

if (!ps.empty()) {
// TODO: this type is a PDT (parametric derived type) with length
Expand Down Expand Up @@ -552,16 +552,8 @@ struct TypeBuilderImpl {
/// type `t` have type `t`. This helper returns `t` if it is already being
/// lowered to avoid infinite loops.
mlir::Type getTypeIfDerivedAlreadyInConstruction(
const Fortran::lower::SymbolRef derivedSym) const {
for (const auto &[sym, type] : derivedTypeInConstruction)
if (sym == derivedSym)
return type;
return {};
}

void popDerivedTypeInConstruction() {
assert(!derivedTypeInConstruction.empty());
derivedTypeInConstruction.pop_back();
const Fortran::semantics::Scope &derivedScope) const {
return derivedTypeInConstruction.lookup(&derivedScope);
}

/// Stack derived type being processed to avoid infinite loops in case of
Expand Down
14 changes: 14 additions & 0 deletions flang/test/Lower/derived-types-kind-params-2.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
! This is a crazy program, recursive derived types with recursive kind
! parameters are a terrible idea if they do not converge quickly.

! RUN: bbc -emit-hlfir -o - -I nw %s | FileCheck %s

subroutine foo(x)
type t(k)
integer, kind :: k
type(t(modulo(k+1,2))), pointer :: p
end type
type(t(1)) :: x
end subroutine
! CHECK-LABEL: func.func @_QPfoo(
! CHECK-SAME: !fir.ref<!fir.type<_QFfooTtK1{p:!fir.box<!fir.ptr<!fir.type<_QFfooTtK0{p:!fir.box<!fir.ptr<!fir.type<_QFfooTtK1>>>}>>>}>>