diff --git a/flang/include/flang/Lower/ConvertType.h b/flang/include/flang/Lower/ConvertType.h --- a/flang/include/flang/Lower/ConvertType.h +++ b/flang/include/flang/Lower/ConvertType.h @@ -53,6 +53,7 @@ } // namespace semantics namespace lower { +class AbstractConverter; namespace pft { struct Variable; } @@ -65,33 +66,24 @@ int kind); /// Get a FIR type based on a category. -mlir::Type getFIRType(mlir::MLIRContext *ctxt, - common::IntrinsicTypeDefaultKinds const &defaults, +mlir::Type getFIRType(Fortran::lower::AbstractConverter &, 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); +mlir::Type translateDataRefToFIRType(Fortran::lower::AbstractConverter &, + const evaluate::DataRef &dataRef); /// Translate a SomeExpr to an mlir::Type. -mlir::Type -translateSomeExprToFIRType(mlir::MLIRContext *ctxt, - common::IntrinsicTypeDefaultKinds const &defaults, - const SomeExpr *expr); +mlir::Type translateSomeExprToFIRType(Fortran::lower::AbstractConverter &, + 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); +mlir::Type translateSymbolToFIRType(Fortran::lower::AbstractConverter &, + 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); +mlir::Type translateVariableToFIRType(Fortran::lower::AbstractConverter &, + const pft::Variable &variable); /// Translate a REAL of KIND to the mlir::Type. mlir::Type convertReal(mlir::MLIRContext *ctxt, int KIND); diff --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Lower/ConvertVariable.h @@ -0,0 +1,35 @@ +//===- Lower/ConvertVariable.h -- lowering of variables to FIR --*- 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 +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// +/// +/// Instantiation of pft::Variable in FIR/MLIR. +/// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_LOWER_CONVERT_VARIABLE_H +#define FORTRAN_LOWER_CONVERT_VARIABLE_H + +namespace Fortran ::lower { +class AbstractConverter; +class SymMap; +namespace pft { +struct Variable; +} + +/// Instantiate variable \p var and add it to \p symMap. +/// The AbstractConverter builder must be set. +/// The AbstractConverter own symbol mapping is not used during the +/// instantiation and can be different form \p symMap. +void instantiateVariable(AbstractConverter &, const pft::Variable &var, + SymMap &symMap); + +} // namespace Fortran::lower +#endif // FORTRAN_LOWER_CONVERT_VARIABLE_H diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -15,6 +15,7 @@ #include "flang/Lower/CallInterface.h" #include "flang/Lower/ConvertExpr.h" #include "flang/Lower/ConvertType.h" +#include "flang/Lower/ConvertVariable.h" #include "flang/Lower/Mangler.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/Runtime.h" @@ -109,9 +110,8 @@ int kind) override final { return Fortran::lower::getFIRType(&getMLIRContext(), tc, kind); } - mlir::Type genType(const Fortran::lower::pft::Variable &) override final { - TODO_NOLOC("Not implemented genType Variable. Needed for more complex " - "expression lowering"); + mlir::Type genType(const Fortran::lower::pft::Variable &var) override final { + return Fortran::lower::translateVariableToFIRType(*this, var); } void setCurrentPosition(const Fortran::parser::CharBlock &position) { @@ -196,6 +196,12 @@ localSymbols.clear(); } + /// Instantiate variable \p var and add it to the symbol map. + /// See ConvertVariable.cpp. + void instantiateVar(const Fortran::lower::pft::Variable &var) { + Fortran::lower::instantiateVariable(*this, var, localSymbols); + } + /// Prepare to translate a new function void startNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { assert(!builder && "expected nullptr"); @@ -205,6 +211,13 @@ builder = new fir::FirOpBuilder(func, bridge.getKindMap()); assert(builder && "FirOpBuilder did not instantiate"); builder->setInsertionPointToStart(&func.front()); + + for (const Fortran::lower::pft::Variable &var : + funit.getOrderedSymbolTable()) { + const Fortran::semantics::Symbol &sym = var.getSymbol(); + if (!sym.IsFuncResult() || !funit.primaryResult) + instantiateVar(var); + } } /// Lower a procedure (nest). 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 @@ -6,6 +6,7 @@ Coarray.cpp ConvertExpr.cpp ConvertType.cpp + ConvertVariable.cpp Mangler.cpp OpenACC.cpp OpenMP.cpp diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -15,6 +15,7 @@ #include "flang/Evaluate/real.h" #include "flang/Evaluate/traverse.h" #include "flang/Lower/AbstractConverter.h" +#include "flang/Lower/SymbolMap.h" #include "flang/Lower/Todo.h" #include "flang/Semantics/expression.h" #include "flang/Semantics/symbol.h" @@ -36,6 +37,32 @@ // to the correct FIR representation in SSA form. //===----------------------------------------------------------------------===// +/// Generate a load of a value from an address. Beware that this will lose +/// any dynamic type information for polymorphic entities (note that unlimited +/// polymorphic cannot be loaded and must not be provided here). +static fir::ExtendedValue genLoad(fir::FirOpBuilder &builder, + mlir::Location loc, + const fir::ExtendedValue &addr) { + return addr.match( + [](const fir::CharBoxValue &box) -> fir::ExtendedValue { return box; }, + [&](const fir::UnboxedValue &v) -> fir::ExtendedValue { + if (fir::unwrapRefType(fir::getBase(v).getType()) + .isa()) + return v; + return builder.create(loc, fir::getBase(v)); + }, + [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue { + TODO(loc, "genLoad for MutableBoxValue"); + }, + [&](const fir::BoxValue &box) -> fir::ExtendedValue { + TODO(loc, "genLoad for BoxValue"); + }, + [&](const auto &) -> fir::ExtendedValue { + fir::emitFatalError( + loc, "attempting to load whole array or procedure address"); + }); +} + namespace { /// Lowering of Fortran::evaluate::Expr expressions @@ -44,9 +71,10 @@ using ExtValue = fir::ExtendedValue; explicit ScalarExprLowering(mlir::Location loc, - Fortran::lower::AbstractConverter &converter) + Fortran::lower::AbstractConverter &converter, + Fortran::lower::SymMap &symMap) : location{loc}, converter{converter}, - builder{converter.getFirOpBuilder()} {} + builder{converter.getFirOpBuilder()}, symMap{symMap} {} mlir::Location getLoc() { return location; } @@ -64,8 +92,26 @@ return builder.createBool(getLoc(), value); } + /// Returns a reference to a symbol or its box/boxChar descriptor if it has + /// one. + ExtValue gen(Fortran::semantics::SymbolRef sym) { + if (Fortran::lower::SymbolBox val = symMap.lookupSymbol(sym)) + return val.match([&val](auto &) { return val.toExtendedValue(); }); + LLVM_DEBUG(llvm::dbgs() + << "unknown symbol: " << sym << "\nmap: " << symMap << '\n'); + fir::emitFatalError(getLoc(), "symbol is not mapped to any IR value"); + } + + ExtValue genLoad(const ExtValue &exv) { + return ::genLoad(builder, getLoc(), exv); + } + ExtValue genval(Fortran::semantics::SymbolRef sym) { - TODO(getLoc(), "genval SymbolRef"); + ExtValue var = gen(sym); + if (const fir::UnboxedValue *s = var.getUnboxed()) + if (fir::isReferenceLike(s->getType())) + return genLoad(*s); + return var; } ExtValue genval(const Fortran::evaluate::BOZLiteralConstant &) { @@ -306,7 +352,7 @@ template ExtValue genval(const Fortran::evaluate::Designator &des) { - TODO(getLoc(), "genval Designator"); + return std::visit([&](const auto &x) { return genval(x); }, des.u); } template @@ -340,12 +386,13 @@ mlir::Location location; Fortran::lower::AbstractConverter &converter; fir::FirOpBuilder &builder; + Fortran::lower::SymMap &symMap; }; } // namespace fir::ExtendedValue Fortran::lower::createSomeExtendedExpression( mlir::Location loc, Fortran::lower::AbstractConverter &converter, - const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &) { + const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n'); - return ScalarExprLowering{loc, converter}.genval(expr); + return ScalarExprLowering{loc, converter, symMap}.genval(expr); } diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp --- a/flang/lib/Lower/ConvertType.cpp +++ b/flang/lib/Lower/ConvertType.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "flang/Lower/ConvertType.h" +#include "flang/Lower/AbstractConverter.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/Utils.h" #include "flang/Optimizer/Dialect/FIRType.h" @@ -177,11 +178,8 @@ /// 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} {} + TypeBuilder(Fortran::lower::AbstractConverter &converter) + : converter{converter}, context{&converter.getMLIRContext()} {} //===--------------------------------------------------------------------===// // Generate type entry points @@ -221,7 +219,7 @@ return genVariant(dref); } - mlir::Type gen(const Fortran::lower::pft::Variable &var) { + mlir::Type genVariableType(const Fortran::lower::pft::Variable &var) { return genSymbolHelper(var.getSymbol(), var.isHeapAlloc(), var.isPointer()); } @@ -425,9 +423,7 @@ int defaultKind() { return defaultKind(TC); } - int defaultKind(Fortran::common::TypeCategory TC) { - return defaults.GetDefaultKind(TC); - } + int defaultKind(Fortran::common::TypeCategory TC) { return 0; } fir::SequenceType::Shape seqShapeHelper(Fortran::semantics::SymbolRef symbol, fir::SequenceType::Shape &bounds) { @@ -469,8 +465,8 @@ //===--------------------------------------------------------------------===// + Fortran::lower::AbstractConverter &converter; mlir::MLIRContext *context; - const Fortran::common::IntrinsicTypeDefaultKinds &defaults; }; } // namespace @@ -520,39 +516,32 @@ return genFIRType(context, tc, kind); } -mlir::Type Fortran::lower::getFIRType( - mlir::MLIRContext *context, - const Fortran::common::IntrinsicTypeDefaultKinds &defaults, - Fortran::common::TypeCategory tc) { - return TypeBuilder{context, defaults}.genFIRTy(tc); +mlir::Type +Fortran::lower::getFIRType(Fortran::lower::AbstractConverter &converter, + Fortran::common::TypeCategory tc) { + return TypeBuilder{converter}.genFIRTy(tc); } mlir::Type Fortran::lower::translateDataRefToFIRType( - mlir::MLIRContext *context, - const Fortran::common::IntrinsicTypeDefaultKinds &defaults, + Fortran::lower::AbstractConverter &converter, const Fortran::evaluate::DataRef &dataRef) { - return TypeBuilder{context, defaults}.gen(dataRef); + return TypeBuilder{converter}.gen(dataRef); } mlir::Type Fortran::lower::translateSomeExprToFIRType( - mlir::MLIRContext *context, - const Fortran::common::IntrinsicTypeDefaultKinds &defaults, - const SomeExpr *expr) { - return TypeBuilder{context, defaults}.gen(*expr); + Fortran::lower::AbstractConverter &converter, const SomeExpr *expr) { + return TypeBuilder{converter}.gen(*expr); } mlir::Type Fortran::lower::translateSymbolToFIRType( - mlir::MLIRContext *context, - const Fortran::common::IntrinsicTypeDefaultKinds &defaults, - const SymbolRef symbol) { - return TypeBuilder{context, defaults}.gen(symbol); + Fortran::lower::AbstractConverter &converter, const SymbolRef symbol) { + return TypeBuilder{converter}.gen(symbol); } mlir::Type Fortran::lower::translateVariableToFIRType( - mlir::MLIRContext *context, - const Fortran::common::IntrinsicTypeDefaultKinds &defaults, + Fortran::lower::AbstractConverter &converter, const Fortran::lower::pft::Variable &var) { - return TypeBuilder{context, defaults}.gen(var); + return TypeBuilder{converter}.genVariableType(var); } mlir::Type Fortran::lower::convertReal(mlir::MLIRContext *context, int kind) { diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -0,0 +1,93 @@ +//===-- ConvertVariable.cpp -- bridge to lower to MLIR --------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#include "flang/Lower/ConvertVariable.h" +#include "flang/Lower/AbstractConverter.h" +#include "flang/Lower/CallInterface.h" +#include "flang/Lower/ConvertExpr.h" +#include "flang/Lower/Mangler.h" +#include "flang/Lower/PFTBuilder.h" +#include "flang/Lower/Support/Utils.h" +#include "flang/Lower/SymbolMap.h" +#include "flang/Lower/Todo.h" +#include "flang/Optimizer/Builder/Character.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Runtime/Derived.h" +#include "flang/Optimizer/Dialect/FIRAttr.h" +#include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Dialect/FIROps.h" +#include "flang/Optimizer/Support/FIRContext.h" +#include "flang/Optimizer/Support/FatalError.h" +#include "flang/Semantics/tools.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "flang-lower-variable" + +//===----------------------------------------------------------------===// +// Local variables instantiation (not for alias) +//===----------------------------------------------------------------===// + +/// Create a stack slot for a local variable. Precondition: the insertion +/// point of the builder must be in the entry block, which is currently being +/// constructed. +static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter, + mlir::Location loc, + const Fortran::lower::pft::Variable &var, + mlir::Value preAlloc, + llvm::ArrayRef shape = {}, + llvm::ArrayRef lenParams = {}) { + if (preAlloc) + return preAlloc; + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + std::string nm = Fortran::lower::mangle::mangleName(var.getSymbol()); + mlir::Type ty = converter.genType(var); + const Fortran::semantics::Symbol &ultimateSymbol = + var.getSymbol().GetUltimate(); + llvm::StringRef symNm = toStringRef(ultimateSymbol.name()); + bool isTarg = var.isTarget(); + // Let the builder do all the heavy lifting. + return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg); +} + +/// Instantiate a local variable. Precondition: Each variable will be visited +/// such that if its properties depend on other variables, the variables upon +/// which its properties depend will already have been visited. +static void instantiateLocal(Fortran::lower::AbstractConverter &converter, + const Fortran::lower::pft::Variable &var, + Fortran::lower::SymMap &symMap) { + assert(!var.isAlias()); + const Fortran::semantics::Symbol &sym = var.getSymbol(); + if (symMap.lookupSymbol(sym)) + return; + const mlir::Location loc = converter.genLocation(sym.name()); + mlir::Value local = createNewLocal(converter, loc, var, {}); + symMap.addSymbol(sym, local); +} + +void Fortran::lower::instantiateVariable(AbstractConverter &converter, + const pft::Variable &var, + SymMap &symMap) { + const Fortran::semantics::Symbol &sym = var.getSymbol(); + const mlir::Location loc = converter.genLocation(sym.name()); + if (var.isAggregateStore()) { + TODO(loc, "instantiateVariable AggregateStore"); + } else if (Fortran::semantics::FindCommonBlockContaining( + var.getSymbol().GetUltimate())) { + TODO(loc, "instantiateVariable Common"); + } else if (var.isAlias()) { + TODO(loc, "instantiateVariable Alias"); + } else if (var.isGlobal()) { + TODO(loc, "instantiateVariable Global"); + } else { + instantiateLocal(converter, var, symMap); + } +}