Skip to content

Commit

Permalink
[flang] Lower basic derived types
Browse files Browse the repository at this point in the history
This patch lowers basic derived type to FIR.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: PeteSteinfeld

Differential Revision: https://reviews.llvm.org/D121383

Co-authored-by: V Donaldson <vdonaldson@nvidia.com>
Co-authored-by: Jean Perier <jperier@nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
  • Loading branch information
4 people committed Mar 10, 2022
1 parent 58966dd commit 589d51e
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 22 deletions.
4 changes: 2 additions & 2 deletions flang/include/flang/Lower/AbstractConverter.h
Expand Up @@ -137,8 +137,6 @@ class AbstractConverter {
// Types
//===--------------------------------------------------------------------===//

/// Generate the type of a DataRef
virtual mlir::Type genType(const Fortran::evaluate::DataRef &) = 0;
/// Generate the type of an Expr
virtual mlir::Type genType(const SomeExpr &) = 0;
/// Generate the type of a Symbol
Expand All @@ -149,6 +147,8 @@ class AbstractConverter {
virtual mlir::Type
genType(Fortran::common::TypeCategory tc, int kind,
llvm::ArrayRef<std::int64_t> lenParameters = llvm::None) = 0;
/// Generate the type from a DerivedTypeSpec.
virtual mlir::Type genType(const Fortran::semantics::DerivedTypeSpec &) = 0;
/// Generate the type from a Variable
virtual mlir::Type genType(const pft::Variable &) = 0;

Expand Down
6 changes: 6 additions & 0 deletions flang/include/flang/Lower/ConvertType.h
Expand Up @@ -44,6 +44,7 @@ struct SomeType;

namespace semantics {
class Symbol;
class DerivedTypeSpec;
} // namespace semantics

namespace lower {
Expand All @@ -62,6 +63,11 @@ using LenParameterTy = std::int64_t;
mlir::Type getFIRType(mlir::MLIRContext *ctxt, common::TypeCategory tc,
int kind, llvm::ArrayRef<LenParameterTy>);

/// Get a FIR type for a derived type
mlir::Type
translateDerivedTypeToFIRType(Fortran::lower::AbstractConverter &,
const Fortran::semantics::DerivedTypeSpec &);

/// Translate a SomeExpr to an mlir::Type.
mlir::Type translateSomeExprToFIRType(Fortran::lower::AbstractConverter &,
const SomeExpr &expr);
Expand Down
16 changes: 8 additions & 8 deletions flang/lib/Lower/Bridge.cpp
Expand Up @@ -241,26 +241,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return foldingContext;
}

mlir::Type genType(const Fortran::evaluate::DataRef &) override final {
TODO_NOLOC("Not implemented genType DataRef. Needed for more complex "
"expression lowering");
}
mlir::Type genType(const Fortran::lower::SomeExpr &expr) override final {
return Fortran::lower::translateSomeExprToFIRType(*this, expr);
}
mlir::Type genType(Fortran::lower::SymbolRef sym) override final {
return Fortran::lower::translateSymbolToFIRType(*this, sym);
}
mlir::Type genType(Fortran::common::TypeCategory tc) override final {
TODO_NOLOC("Not implemented genType TypeCategory. Needed for more complex "
"expression lowering");
}
mlir::Type
genType(Fortran::common::TypeCategory tc, int kind,
llvm::ArrayRef<std::int64_t> lenParameters) override final {
return Fortran::lower::getFIRType(&getMLIRContext(), tc, kind,
lenParameters);
}
mlir::Type
genType(const Fortran::semantics::DerivedTypeSpec &tySpec) override final {
return Fortran::lower::translateDerivedTypeToFIRType(*this, tySpec);
}
mlir::Type genType(Fortran::common::TypeCategory tc) override final {
TODO_NOLOC("Not implemented genType TypeCategory. Needed for more complex "
"expression lowering");
}
mlir::Type genType(const Fortran::lower::pft::Variable &var) override final {
return Fortran::lower::translateVariableToFIRType(*this, var);
}
Expand Down
12 changes: 9 additions & 3 deletions flang/lib/Lower/CallInterface.cpp
Expand Up @@ -215,7 +215,11 @@ void Fortran::lower::CallerInterface::walkResultLengths(
dynamicType.GetCharLength())
visitor(toEvExpr(*length));
} else if (dynamicType.category() == common::TypeCategory::Derived) {
TODO(converter.getCurrentLocation(), "walkResultLengths derived type");
const Fortran::semantics::DerivedTypeSpec &derivedTypeSpec =
dynamicType.GetDerivedTypeSpec();
if (Fortran::semantics::CountLenParameters(derivedTypeSpec) > 0)
TODO(converter.getCurrentLocation(),
"function result with derived type length parameters");
}
}

Expand Down Expand Up @@ -759,8 +763,10 @@ class Fortran::lower::CallInterfaceImpl {
Fortran::common::TypeCategory cat = dynamicType.category();
// DERIVED
if (cat == Fortran::common::TypeCategory::Derived) {
TODO(interface.converter.getCurrentLocation(),
"[translateDynamicType] Derived types");
if (dynamicType.IsPolymorphic())
TODO(interface.converter.getCurrentLocation(),
"[translateDynamicType] polymorphic types");
return getConverter().genType(dynamicType.GetDerivedTypeSpec());
}
// CHARACTER with compile time constant length.
if (cat == Fortran::common::TypeCategory::Character)
Expand Down
18 changes: 13 additions & 5 deletions flang/lib/Lower/ConvertExpr.cpp
Expand Up @@ -1109,10 +1109,10 @@ class ScalarExprLowering {
}

ExtValue gen(const Fortran::evaluate::DataRef &dref) {
TODO(getLoc(), "gen DataRef");
return std::visit([&](const auto &x) { return gen(x); }, dref.u);
}
ExtValue genval(const Fortran::evaluate::DataRef &dref) {
TODO(getLoc(), "genval DataRef");
return std::visit([&](const auto &x) { return genval(x); }, dref.u);
}

// Helper function to turn the Component structure into a list of nested
Expand Down Expand Up @@ -1166,10 +1166,18 @@ class ScalarExprLowering {
}

ExtValue gen(const Fortran::evaluate::Component &cmpt) {
TODO(getLoc(), "gen Component");
// Components may be pointer or allocatable. In the gen() path, the mutable
// aspect is lost to simplify handling on the client side. To retain the
// mutable aspect, genMutableBoxValue should be used.
return genComponent(cmpt).match(
[&](const fir::MutableBoxValue &mutableBox) {
return fir::factory::genMutableBoxRead(builder, getLoc(), mutableBox);
},
[](auto &box) -> ExtValue { return box; });
}

ExtValue genval(const Fortran::evaluate::Component &cmpt) {
TODO(getLoc(), "genval Component");
return genLoad(gen(cmpt));
}

ExtValue genval(const Fortran::semantics::Bound &bound) {
Expand Down Expand Up @@ -1345,7 +1353,7 @@ class ScalarExprLowering {
mlir::Type genType(const Fortran::evaluate::DynamicType &dt) {
if (dt.category() != Fortran::common::TypeCategory::Derived)
return converter.genType(dt.category(), dt.kind());
TODO(getLoc(), "genType Derived Type");
return converter.genType(dt.GetDerivedTypeSpec());
}

/// Lower a function reference
Expand Down
102 changes: 98 additions & 4 deletions flang/lib/Lower/ConvertType.cpp
Expand Up @@ -8,6 +8,7 @@

#include "flang/Lower/ConvertType.h"
#include "flang/Lower/AbstractConverter.h"
#include "flang/Lower/Mangler.h"
#include "flang/Lower/PFTBuilder.h"
#include "flang/Lower/Support/Utils.h"
#include "flang/Lower/Todo.h"
Expand All @@ -16,6 +17,7 @@
#include "flang/Semantics/type.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
#include "llvm/Support/Debug.h"

#define DEBUG_TYPE "flang-lower-type"

Expand Down Expand Up @@ -139,7 +141,7 @@ class TypeBuilder {

mlir::Type baseType;
if (category == Fortran::common::TypeCategory::Derived) {
TODO(converter.getCurrentLocation(), "genExprType derived");
baseType = genDerivedType(dynamicType->GetDerivedTypeSpec());
} else {
// LOGICAL, INTEGER, REAL, COMPLEX, CHARACTER
llvm::SmallVector<Fortran::lower::LenParameterTy> params;
Expand Down Expand Up @@ -231,8 +233,9 @@ class TypeBuilder {
ty = genFIRType(context, tySpec->category(), kind, params);
} else if (type->IsPolymorphic()) {
TODO(loc, "genSymbolType polymorphic types");
} else if (type->AsDerived()) {
TODO(loc, "genSymbolType derived type");
} else if (const Fortran::semantics::DerivedTypeSpec *tySpec =
type->AsDerived()) {
ty = genDerivedType(*tySpec);
} else {
fir::emitFatalError(loc, "symbol's type must have a type spec");
}
Expand Down Expand Up @@ -263,6 +266,71 @@ class TypeBuilder {
return ty;
}

/// Does \p component has non deferred lower bounds that are not compile time
/// constant 1.
static bool componentHasNonDefaultLowerBounds(
const Fortran::semantics::Symbol &component) {
if (const auto *objDetails =
component.detailsIf<Fortran::semantics::ObjectEntityDetails>())
for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape())
if (auto lb = bounds.lbound().GetExplicit())
if (auto constant = Fortran::evaluate::ToInt64(*lb))
if (!constant || *constant != 1)
return true;
return false;
}

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;
auto rec = fir::RecordType::get(context,
Fortran::lower::mangle::mangleName(tySpec));
// Maintain the stack of types for recursive references.
derivedTypeInConstruction.emplace_back(typeSymbol, rec);

// Gather the record type fields.
// (1) The data components.
for (const auto &field :
Fortran::semantics::OrderedComponentIterator(tySpec)) {
// Lowering is assuming non deferred component lower bounds are always 1.
// Catch any situations where this is not true for now.
if (componentHasNonDefaultLowerBounds(field))
TODO(converter.genLocation(field.name()),
"lowering derived type components with non default lower bounds");
if (IsProcName(field))
TODO(converter.genLocation(field.name()), "procedure components");
mlir::Type ty = genSymbolType(field);
// Do not add the parent component (component of the parents are
// added and should be sufficient, the parent component would
// duplicate the fields).
if (field.test(Fortran::semantics::Symbol::Flag::ParentComp))
continue;
cs.emplace_back(field.name().ToString(), ty);
}

// (2) The LEN type parameters.
for (const auto &param :
Fortran::semantics::OrderParameterDeclarations(typeSymbol))
if (param->get<Fortran::semantics::TypeParamDetails>().attr() ==
Fortran::common::TypeParamAttr::Len)
ps.emplace_back(param->name().ToString(), genSymbolType(*param));

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

if (!ps.empty()) {
// This type is a PDT (parametric derived type). Create the functions to
// use for allocation, dereferencing, and address arithmetic here.
TODO(converter.genLocation(typeSymbol.name()),
"parametrized derived types lowering");
}
LLVM_DEBUG(llvm::dbgs() << "derived type: " << rec << '\n');
return rec;
}

// To get the character length from a symbol, make an fold a designator for
// the symbol to cover the case where the symbol is an assumed length named
// constant and its length comes from its init expression length.
Expand Down Expand Up @@ -326,7 +394,27 @@ class TypeBuilder {
return genSymbolType(var.getSymbol(), var.isHeapAlloc(), var.isPointer());
}

private:
/// Derived type can be recursive. That is, pointer components of a derived
/// 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();
}

/// Stack derived type being processed to avoid infinite loops in case of
/// recursive derived types. The depth of derived types is expected to be
/// shallow (<10), so a SmallVector is sufficient.
llvm::SmallVector<std::pair<const Fortran::lower::SymbolRef, mlir::Type>>
derivedTypeInConstruction;
Fortran::lower::AbstractConverter &converter;
mlir::MLIRContext *context;
};
Expand All @@ -340,6 +428,12 @@ mlir::Type Fortran::lower::getFIRType(mlir::MLIRContext *context,
return genFIRType(context, tc, kind, params);
}

mlir::Type Fortran::lower::translateDerivedTypeToFIRType(
Fortran::lower::AbstractConverter &converter,
const Fortran::semantics::DerivedTypeSpec &tySpec) {
return TypeBuilder{converter}.genDerivedType(tySpec);
}

mlir::Type Fortran::lower::translateSomeExprToFIRType(
Fortran::lower::AbstractConverter &converter, const SomeExpr &expr) {
return TypeBuilder{converter}.genExprType(expr);
Expand Down

0 comments on commit 589d51e

Please sign in to comment.