Skip to content

Commit 84564e1

Browse files
authored
[flang][NFC] Cache derived type translation in lowering (#80179)
Derived type translation is proving expensive in modern fortran apps with many big derived types with dozens of components and parents. Extending the cache that prevent recursion is proving to have little cost on apps with small derived types and significant gain (can divide compile time by 2) on modern fortran apps. It is legal since the cache lifetime is less than the MLIRContext lifetime that owns the cached mlir::Type. Doing so also exposed that the current caching was incorrect, the type symbol is the same for kind parametrized derived types regardless of the kind parameters. Instances with different kinds should lower to different MLIR types. See added test. Using the type scopes fixes the problem.
1 parent 5fdf8c6 commit 84564e1

File tree

3 files changed

+25
-18
lines changed

3 files changed

+25
-18
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class CharBlock;
4747
}
4848
namespace semantics {
4949
class Symbol;
50+
class Scope;
5051
class DerivedTypeSpec;
5152
} // namespace semantics
5253

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

6566
using ExprToValueMap = llvm::DenseMap<const SomeExpr *, mlir::Value>;

flang/lib/Lower/ConvertType.cpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -374,19 +374,20 @@ struct TypeBuilderImpl {
374374
mlir::Type genDerivedType(const Fortran::semantics::DerivedTypeSpec &tySpec) {
375375
std::vector<std::pair<std::string, mlir::Type>> ps;
376376
std::vector<std::pair<std::string, mlir::Type>> cs;
377-
const Fortran::semantics::Symbol &typeSymbol = tySpec.typeSymbol();
378-
if (mlir::Type ty = getTypeIfDerivedAlreadyInConstruction(typeSymbol))
379-
return ty;
380-
381377
if (tySpec.IsVectorType()) {
382378
return genVectorType(tySpec);
383379
}
384380

381+
const Fortran::semantics::Symbol &typeSymbol = tySpec.typeSymbol();
385382
const Fortran::semantics::Scope &derivedScope = DEREF(tySpec.GetScope());
383+
if (mlir::Type ty = getTypeIfDerivedAlreadyInConstruction(derivedScope))
384+
return ty;
386385

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

391392
// Gather the record type fields.
392393
// (1) The data components.
@@ -446,7 +447,6 @@ struct TypeBuilderImpl {
446447
}
447448

448449
rec.finalize(ps, cs);
449-
popDerivedTypeInConstruction();
450450

451451
if (!ps.empty()) {
452452
// TODO: this type is a PDT (parametric derived type) with length
@@ -552,16 +552,8 @@ struct TypeBuilderImpl {
552552
/// type `t` have type `t`. This helper returns `t` if it is already being
553553
/// lowered to avoid infinite loops.
554554
mlir::Type getTypeIfDerivedAlreadyInConstruction(
555-
const Fortran::lower::SymbolRef derivedSym) const {
556-
for (const auto &[sym, type] : derivedTypeInConstruction)
557-
if (sym == derivedSym)
558-
return type;
559-
return {};
560-
}
561-
562-
void popDerivedTypeInConstruction() {
563-
assert(!derivedTypeInConstruction.empty());
564-
derivedTypeInConstruction.pop_back();
555+
const Fortran::semantics::Scope &derivedScope) const {
556+
return derivedTypeInConstruction.lookup(&derivedScope);
565557
}
566558

567559
/// Stack derived type being processed to avoid infinite loops in case of
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
! This is a crazy program, recursive derived types with recursive kind
2+
! parameters are a terrible idea if they do not converge quickly.
3+
4+
! RUN: bbc -emit-hlfir -o - -I nw %s | FileCheck %s
5+
6+
subroutine foo(x)
7+
type t(k)
8+
integer, kind :: k
9+
type(t(modulo(k+1,2))), pointer :: p
10+
end type
11+
type(t(1)) :: x
12+
end subroutine
13+
! CHECK-LABEL: func.func @_QPfoo(
14+
! CHECK-SAME: !fir.ref<!fir.type<_QFfooTtK1{p:!fir.box<!fir.ptr<!fir.type<_QFfooTtK0{p:!fir.box<!fir.ptr<!fir.type<_QFfooTtK1>>>}>>>}>>

0 commit comments

Comments
 (0)