diff --git a/flang/include/flang/Lower/ConvertType.h b/flang/include/flang/Lower/ConvertType.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Lower/ConvertType.h @@ -0,0 +1,131 @@ +//===-- Lower/ConvertType.h -- lowering of types ----------------*- 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 +// +//----------------------------------------------------------------------------// +/// +/// Conversion of front-end TYPE, KIND, ATTRIBUTE (TKA) information to FIR/MLIR. +/// This is meant to be the single point of truth (SPOT) for all type +/// conversions when lowering to FIR. This implements all lowering of parse +/// tree TKA to the FIR type system. If one is converting front-end types and +/// not using one of the routines provided here, it's being done wrong. +/// +/// [Coding style](https://llvm.org/docs/CodingStandards.html) +/// +//----------------------------------------------------------------------------// + +#ifndef FORTRAN_LOWER_CONVERT_TYPE_H +#define FORTRAN_LOWER_CONVERT_TYPE_H + +#include "flang/Common/Fortran.h" +#include "mlir/IR/Types.h" + +namespace mlir { +class Location; +class MLIRContext; +class Type; +} // namespace mlir + +namespace Fortran { +namespace common { +class IntrinsicTypeDefaultKinds; +template +class Reference; +} // namespace common + +namespace evaluate { +struct DataRef; +template +class Designator; +template +class Expr; +template +struct SomeKind; +struct SomeType; +template +class Type; +} // namespace evaluate + +namespace parser { +class CharBlock; +class CookedSource; +} // namespace parser + +namespace semantics { +class Symbol; +} // namespace semantics + +namespace lower { +namespace pft { +struct Variable; +} + +using SomeExpr = evaluate::Expr; +using SymbolRef = common::Reference; + +/// Get a FIR type based on a category and kind. +mlir::Type getFIRType(mlir::MLIRContext *ctxt, + common::IntrinsicTypeDefaultKinds const &defaults, + common::TypeCategory tc, int kind); + +/// Get a FIR type based on a category. +mlir::Type getFIRType(mlir::MLIRContext *ctxt, + common::IntrinsicTypeDefaultKinds const &defaults, + common::TypeCategory tc); + +/// Translate a Fortran::evaluate::DataRef to an mlir::Type. +mlir::Type +translateDataRefToFIRType(mlir::MLIRContext *ctxt, + common::IntrinsicTypeDefaultKinds const &defaults, + const evaluate::DataRef &dataRef); + +/// Translate a Fortran::evaluate::Designator<> to an mlir::Type. +template +inline mlir::Type translateDesignatorToFIRType( + mlir::MLIRContext *ctxt, common::IntrinsicTypeDefaultKinds const &defaults, + const evaluate::Designator> &) { + return getFIRType(ctxt, defaults, TC, KIND); +} + +/// Translate a Fortran::evaluate::Designator<> to an mlir::Type. +template +inline mlir::Type translateDesignatorToFIRType( + mlir::MLIRContext *ctxt, common::IntrinsicTypeDefaultKinds const &defaults, + const evaluate::Designator> &) { + return getFIRType(ctxt, defaults, TC); +} + +/// Translate a SomeExpr to an mlir::Type. +mlir::Type +translateSomeExprToFIRType(mlir::MLIRContext *ctxt, + common::IntrinsicTypeDefaultKinds const &defaults, + const SomeExpr *expr); + +/// Translate a Fortran::semantics::Symbol to an mlir::Type. +mlir::Type +translateSymbolToFIRType(mlir::MLIRContext *ctxt, + common::IntrinsicTypeDefaultKinds const &defaults, + const SymbolRef symbol); + +/// Translate a Fortran::lower::pft::Variable to an mlir::Type. +mlir::Type +translateVariableToFIRType(mlir::MLIRContext *ctxt, + common::IntrinsicTypeDefaultKinds const &defaults, + const pft::Variable &variable); + +/// Translate a REAL of KIND to the mlir::Type. +mlir::Type convertReal(mlir::MLIRContext *ctxt, int KIND); + +// Given a ReferenceType of a base type, returns the ReferenceType to +// the SequenceType of this base type. +// The created SequenceType has one dimension of unknown extent. +// This is useful to do pointer arithmetic using fir::CoordinateOp that requires +// a memory reference to a sequence type. +mlir::Type getSequenceRefType(mlir::Type referenceType); + +} // namespace lower +} // namespace Fortran + +#endif // FORTRAN_LOWER_CONVERT_TYPE_H diff --git a/flang/lib/Lower/CMakeLists.txt b/flang/lib/Lower/CMakeLists.txt --- a/flang/lib/Lower/CMakeLists.txt +++ b/flang/lib/Lower/CMakeLists.txt @@ -1,5 +1,6 @@ add_flang_library(FortranLower + ConvertType.cpp OpenMP.cpp PFTBuilder.cpp diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Lower/ConvertType.cpp @@ -0,0 +1,532 @@ +//===-- ConvertType.cpp ---------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "flang/Lower/ConvertType.h" +#include "flang/Lower/PFTBuilder.h" +#include "flang/Lower/Utils.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Semantics/tools.h" +#include "flang/Semantics/type.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/StandardTypes.h" + +#undef QUOTE +#undef TODO +#define QUOTE(X) #X +#define TODO(S) \ + { \ + emitError(__FILE__ ":" QUOTE(__LINE__) ": type lowering of " S \ + " not implemented"); \ + exit(1); \ + } + +template +bool isConstant(const Fortran::evaluate::Expr &e) { + return Fortran::evaluate::IsConstantExpr(Fortran::lower::SomeExpr{e}); +} + +template +int64_t toConstant(const Fortran::evaluate::Expr &e) { + auto opt = Fortran::evaluate::ToInt64(e); + assert(opt.has_value() && "expression didn't resolve to a constant"); + return opt.value(); +} + +// one argument template, must be specialized +template +mlir::Type genFIRType(mlir::MLIRContext *, int) { + return {}; +} + +// two argument template +template +mlir::Type genFIRType(mlir::MLIRContext *context) { + if constexpr (TC == Fortran::common::TypeCategory::Integer) { + auto bits{Fortran::evaluate::Type::Scalar::bits}; + return mlir::IntegerType::get(bits, context); + } else if constexpr (TC == Fortran::common::TypeCategory::Logical || + TC == Fortran::common::TypeCategory::Character || + TC == Fortran::common::TypeCategory::Complex) { + return genFIRType(context, KIND); + } else { + return {}; + } +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context) { + return mlir::FloatType::getF16(context); +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context) { + return mlir::FloatType::getBF16(context); +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context) { + return mlir::FloatType::getF32(context); +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context) { + return mlir::FloatType::getF64(context); +} + +template <> +mlir::Type genFIRType( + mlir::MLIRContext *context) { + return fir::RealType::get(context, 10); +} + +template <> +mlir::Type genFIRType( + mlir::MLIRContext *context) { + return fir::RealType::get(context, 16); +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context, + int kind) { + if (Fortran::evaluate::IsValidKindOfIntrinsicType( + Fortran::common::TypeCategory::Real, kind)) { + switch (kind) { + case 2: + return genFIRType(context); + case 3: + return genFIRType(context); + case 4: + return genFIRType(context); + case 8: + return genFIRType(context); + case 10: + return genFIRType(context); + case 16: + return genFIRType(context); + } + } + llvm_unreachable("REAL type translation not implemented"); +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context, + int kind) { + if (Fortran::evaluate::IsValidKindOfIntrinsicType( + Fortran::common::TypeCategory::Integer, kind)) { + switch (kind) { + case 1: + return genFIRType(context); + case 2: + return genFIRType(context); + case 4: + return genFIRType(context); + case 8: + return genFIRType(context); + case 16: + return genFIRType(context); + } + } + llvm_unreachable("INTEGER type translation not implemented"); +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context, + int KIND) { + if (Fortran::evaluate::IsValidKindOfIntrinsicType( + Fortran::common::TypeCategory::Logical, KIND)) + return fir::LogicalType::get(context, KIND); + return {}; +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context, + int KIND) { + if (Fortran::evaluate::IsValidKindOfIntrinsicType( + Fortran::common::TypeCategory::Character, KIND)) + return fir::CharacterType::get(context, KIND); + return {}; +} + +template <> +mlir::Type +genFIRType(mlir::MLIRContext *context, + int KIND) { + if (Fortran::evaluate::IsValidKindOfIntrinsicType( + Fortran::common::TypeCategory::Complex, KIND)) + return fir::CplxType::get(context, KIND); + return {}; +} + +namespace { + +/// Discover the type of an Fortran::evaluate::Expr and convert it to an +/// mlir::Type. The type returned may be an MLIR standard or FIR type. +class TypeBuilder { +public: + + /// Constructor. + explicit TypeBuilder( + mlir::MLIRContext *context, + const Fortran::common::IntrinsicTypeDefaultKinds &defaults) + : context{context}, defaults{defaults} {} + + + //===--------------------------------------------------------------------===// + // Generate type entry points + //===--------------------------------------------------------------------===// + + template