diff --git a/flang/include/flang/Lower/ConvertExprToHLFIR.h b/flang/include/flang/Lower/ConvertExprToHLFIR.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Lower/ConvertExprToHLFIR.h @@ -0,0 +1,42 @@ +//===-- Lower/ConvertExprToHLFIR.h -- lowering of expressions ----*- 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/ +// +//===----------------------------------------------------------------------===// +/// +/// Implements the conversion from Fortran::evaluate::Expr trees to HLFIR. +/// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_LOWER_CONVERTEXPRTOHLFIR_H +#define FORTRAN_LOWER_CONVERTEXPRTOHLFIR_H + +#include "flang/Lower/Support/Utils.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/HLFIRTools.h" +#include "flang/Optimizer/Dialect/FIRDialect.h" + +namespace mlir { +class Location; +} // namespace mlir + +namespace Fortran::lower { + +class AbstractConverter; +class StatementContext; +class SymMap; + +hlfir::FortranEntity convertExprToHLFIR(mlir::Location loc, + Fortran::lower::AbstractConverter &, + const Fortran::lower::SomeExpr &, + Fortran::lower::SymMap &, + Fortran::lower::StatementContext &); +} // namespace Fortran::lower + +#endif // FORTRAN_LOWER_CONVERTEXPRTOHLFIR_H diff --git a/flang/include/flang/Lower/SymbolMap.h b/flang/include/flang/Lower/SymbolMap.h --- a/flang/include/flang/Lower/SymbolMap.h +++ b/flang/include/flang/Lower/SymbolMap.h @@ -348,6 +348,9 @@ symbolMapStack.back().try_emplace(sym, definingOp); } + llvm::Optional + lookupVariableDefinition(semantics::SymbolRef sym); + private: /// Add `symbol` to the current map and bind a `box`. void makeSym(semantics::SymbolRef symRef, const SymbolBox &box, diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -561,6 +561,10 @@ mlir::Value genCPtrOrCFunptrAddr(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value cPtr, mlir::Type ty); +/// Create a fir.box from a fir::ExtendedValue and wrap it in a fir::BoxValue +/// to keep all the lower bound and explicit parameter information. +fir::BoxValue createBoxValue(fir::FirOpBuilder &builder, mlir::Location loc, + const fir::ExtendedValue &exv); } // namespace fir::factory #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_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/Coarray.h" #include "flang/Lower/ConvertExpr.h" +#include "flang/Lower/ConvertExprToHLFIR.h" #include "flang/Lower/ConvertType.h" #include "flang/Lower/ConvertVariable.h" #include "flang/Lower/HostAssociations.h" @@ -421,11 +422,25 @@ Fortran::lower::StatementContext &context, mlir::Location *locPtr = nullptr) override final { mlir::Location loc = locPtr ? *locPtr : toLocation(); - if (bridge.getLoweringOptions().getLowerToHighLevelFIR()) - TODO(loc, "lower expr to HLFIR address"); + if (bridge.getLoweringOptions().getLowerToHighLevelFIR()) { + hlfir::FortranEntity loweredExpr = Fortran::lower::convertExprToHLFIR( + loc, *this, expr, localSymbols, context); + if (fir::FortranVariableOpInterface variable = + loweredExpr.getIfVariable()) + if (!variable.isBox()) { + auto [exv, exvCleanup] = + hlfir::translateToExtendedValue(loc, getFirOpBuilder(), variable); + if (exvCleanup) + context.attachCleanup(*exvCleanup); + return exv; + } + TODO(loc, "lower expr that is not a scalar or explicit shape array " + "variable to HLFIR address"); + } return Fortran::lower::createSomeExtendedAddress(loc, *this, expr, localSymbols, context); } + fir::ExtendedValue genExprValue(const Fortran::lower::SomeExpr &expr, Fortran::lower::StatementContext &context, @@ -440,8 +455,22 @@ fir::ExtendedValue genExprBox(mlir::Location loc, const Fortran::lower::SomeExpr &expr, Fortran::lower::StatementContext &stmtCtx) override final { - if (bridge.getLoweringOptions().getLowerToHighLevelFIR()) - TODO(loc, "lower expr to HLFIR box"); + if (bridge.getLoweringOptions().getLowerToHighLevelFIR()) { + hlfir::FortranEntity loweredExpr = Fortran::lower::convertExprToHLFIR( + loc, *this, expr, localSymbols, stmtCtx); + if (fir::FortranVariableOpInterface variable = + loweredExpr.getIfVariable()) + if (variable.isBoxValue() || !variable.isBoxAddress()) { + auto &builder = getFirOpBuilder(); + auto [exv, exvCleanup] = + hlfir::translateToExtendedValue(loc, builder, variable); + if (exvCleanup) + stmtCtx.attachCleanup(*exvCleanup); + return fir::factory::createBoxValue(builder, loc, exv); + } + TODO(loc, + "lower expression value or pointer and allocatable to HLFIR box"); + } return Fortran::lower::createBoxValue(loc, *this, expr, localSymbols, stmtCtx); } 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 @@ CallInterface.cpp Coarray.cpp ConvertExpr.cpp + ConvertExprToHLFIR.cpp ConvertType.cpp ConvertVariable.cpp ComponentPath.cpp @@ -28,6 +29,7 @@ FIRBuilder FIRSupport FIRTransforms + HLFIRDialect ${dialect_libs} LINK_LIBS @@ -35,6 +37,7 @@ FIRBuilder FIRSupport FIRTransforms + HLFIRDialect ${dialect_libs} FortranCommon FortranParser diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -0,0 +1,195 @@ +//===-- ConvertExprToHLFIR.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 +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#include "flang/Lower/ConvertExprToHLFIR.h" +#include "flang/Lower/AbstractConverter.h" +#include "flang/Lower/StatementContext.h" +#include "flang/Lower/SymbolMap.h" +#include "flang/Optimizer/Builder/Todo.h" + +namespace { + +/// Lower Designators to HLFIR. +class HlfirDesignatorBuilder { +public: + HlfirDesignatorBuilder(mlir::Location loc, + Fortran::lower::AbstractConverter &converter, + Fortran::lower::SymMap &symMap, + Fortran::lower::StatementContext &stmtCtx) + : converter{converter}, symMap{symMap}, stmtCtx{stmtCtx}, loc{loc} {} + + // Character designators variant contains substrings + using CharacterDesignators = + decltype(Fortran::evaluate::Designator>::u); + hlfir::FortranEntity gen(const CharacterDesignators &designatorVariant) { + return std::visit([&](const auto &x) { return gen(x); }, designatorVariant); + } + // Character designators variant contains complex parts + using RealDesignators = + decltype(Fortran::evaluate::Designator>::u); + hlfir::FortranEntity gen(const RealDesignators &designatorVariant) { + return std::visit([&](const auto &x) { return gen(x); }, designatorVariant); + } + // All other designators are similar + using OtherDesignators = + decltype(Fortran::evaluate::Designator>::u); + hlfir::FortranEntity gen(const OtherDesignators &designatorVariant) { + return std::visit([&](const auto &x) { return gen(x); }, designatorVariant); + } + +private: + hlfir::FortranEntity gen(const Fortran::evaluate::SymbolRef &symbolRef) { + if (llvm::Optional varDef = + getSymMap().lookupVariableDefinition(symbolRef)) + return *varDef; + TODO(getLoc(), "lowering symbol to HLFIR"); + } + hlfir::FortranEntity gen(const Fortran::evaluate::Component &component) { + TODO(getLoc(), "lowering component to HLFIR"); + } + hlfir::FortranEntity gen(const Fortran::evaluate::ArrayRef &arrayRef) { + TODO(getLoc(), "lowering ArrayRef to HLFIR"); + } + hlfir::FortranEntity gen(const Fortran::evaluate::CoarrayRef &coarrayRef) { + TODO(getLoc(), "lowering CoarrayRef to HLFIR"); + } + hlfir::FortranEntity gen(const Fortran::evaluate::ComplexPart &complexPart) { + TODO(getLoc(), "lowering complex part to HLFIR"); + } + hlfir::FortranEntity gen(const Fortran::evaluate::Substring &substring) { + TODO(getLoc(), "lowering substrings to HLFIR"); + } + + mlir::Location getLoc() const { return loc; } + Fortran::lower::AbstractConverter &getConverter() { return converter; } + fir::FirOpBuilder &getBuilder() { return converter.getFirOpBuilder(); } + Fortran::lower::SymMap &getSymMap() { return symMap; } + Fortran::lower::StatementContext &getStmtCtx() { return stmtCtx; } + + Fortran::lower::AbstractConverter &converter; + Fortran::lower::SymMap &symMap; + Fortran::lower::StatementContext &stmtCtx; + mlir::Location loc; +}; + +/// Lower Expr to HLFIR. +class HlfirBuilder { +public: + HlfirBuilder(mlir::Location loc, Fortran::lower::AbstractConverter &converter, + Fortran::lower::SymMap &symMap, + Fortran::lower::StatementContext &stmtCtx) + : converter{converter}, symMap{symMap}, stmtCtx{stmtCtx}, loc{loc} {} + + template + hlfir::FortranEntity gen(const Fortran::evaluate::Expr &expr) { + return std::visit([&](const auto &x) { return gen(x); }, expr.u); + } + +private: + hlfir::FortranEntity gen(const Fortran::evaluate::BOZLiteralConstant &expr) { + fir::emitFatalError(loc, "BOZ literal must be replaced by semantics"); + } + hlfir::FortranEntity gen(const Fortran::evaluate::NullPointer &expr) { + TODO(getLoc(), "lowering NullPointer to HLFIR"); + } + hlfir::FortranEntity gen(const Fortran::evaluate::ProcedureDesignator &expr) { + TODO(getLoc(), "lowering ProcDes to HLFIR"); + } + hlfir::FortranEntity gen(const Fortran::evaluate::ProcedureRef &expr) { + TODO(getLoc(), "lowering ProcRef to HLFIR"); + } + + template + hlfir::FortranEntity gen(const Fortran::evaluate::Designator &designator) { + return HlfirDesignatorBuilder(getLoc(), getConverter(), getSymMap(), + getStmtCtx()) + .gen(designator.u); + } + + template + hlfir::FortranEntity gen(const Fortran::evaluate::FunctionRef &expr) { + TODO(getLoc(), "lowering funcRef to HLFIR"); + } + + template + hlfir::FortranEntity gen(const Fortran::evaluate::Constant &expr) { + TODO(getLoc(), "lowering constant to HLFIR"); + } + + template + hlfir::FortranEntity gen(const Fortran::evaluate::ArrayConstructor &expr) { + TODO(getLoc(), "lowering ArrayCtor to HLFIR"); + } + + template + hlfir::FortranEntity + gen(const Fortran::evaluate::Convert, TC2> + &convert) { + TODO(getLoc(), "lowering convert to HLFIR"); + } + + template + hlfir::FortranEntity gen(const Fortran::evaluate::Operation &op) { + TODO(getLoc(), "lowering unary op to HLFIR"); + } + + template + hlfir::FortranEntity + gen(const Fortran::evaluate::Operation &op) { + TODO(getLoc(), "lowering binary op to HLFIR"); + } + + hlfir::FortranEntity + gen(const Fortran::evaluate::Relational &op) { + return std::visit([&](const auto &x) { return gen(x); }, op.u); + } + + hlfir::FortranEntity gen(const Fortran::evaluate::TypeParamInquiry &) { + TODO(getLoc(), "lowering type parameter inquiry to HLFIR"); + } + + hlfir::FortranEntity gen(const Fortran::evaluate::DescriptorInquiry &desc) { + TODO(getLoc(), "lowering descriptor inquiry to HLFIR"); + } + + hlfir::FortranEntity gen(const Fortran::evaluate::ImpliedDoIndex &var) { + TODO(getLoc(), "lowering implied do index to HLFIR"); + } + + hlfir::FortranEntity gen(const Fortran::evaluate::StructureConstructor &var) { + TODO(getLoc(), "lowering structure constructor to HLFIR"); + } + + mlir::Location getLoc() const { return loc; } + Fortran::lower::AbstractConverter &getConverter() { return converter; } + fir::FirOpBuilder &getBuilder() { return converter.getFirOpBuilder(); } + Fortran::lower::SymMap &getSymMap() { return symMap; } + Fortran::lower::StatementContext &getStmtCtx() { return stmtCtx; } + + Fortran::lower::AbstractConverter &converter; + Fortran::lower::SymMap &symMap; + Fortran::lower::StatementContext &stmtCtx; + mlir::Location loc; +}; + +} // namespace + +hlfir::FortranEntity Fortran::lower::convertExprToHLFIR( + mlir::Location loc, Fortran::lower::AbstractConverter &converter, + const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, + Fortran::lower::StatementContext &stmtCtx) { + return HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); +} diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -1359,7 +1359,7 @@ auto newBase = builder.create( loc, base.getType(), base, shapeOrShift, lenParams, name, attributes); base = newBase; - symMap.addVariableDefinition(sym, newBase); + symMap.addVariableDefinition(sym, newBase, force); return; } diff --git a/flang/lib/Lower/SymbolMap.cpp b/flang/lib/Lower/SymbolMap.cpp --- a/flang/lib/Lower/SymbolMap.cpp +++ b/flang/lib/Lower/SymbolMap.cpp @@ -90,6 +90,22 @@ return {}; } +llvm::Optional +Fortran::lower::SymMap::lookupVariableDefinition(semantics::SymbolRef sym) { + for (auto jmap = symbolMapStack.rbegin(), jend = symbolMapStack.rend(); + jmap != jend; ++jmap) { + auto iter = jmap->find(&*sym); + if (iter != jmap->end()) { + if (const auto *varDef = + std::get_if(&iter->second)) + return *varDef; + else + return llvm::None; + } + } + return llvm::None; +} + llvm::raw_ostream & Fortran::lower::operator<<(llvm::raw_ostream &os, const Fortran::lower::SymbolBox &symBox) { diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -1323,3 +1323,30 @@ return builder.create(loc, builder.getRefType(fieldTy), cPtr, field); } + +fir::BoxValue fir::factory::createBoxValue(fir::FirOpBuilder &builder, + mlir::Location loc, + const fir::ExtendedValue &exv) { + if (auto *boxValue = exv.getBoxOf()) + return *boxValue; + mlir::Value box = builder.createBox(loc, exv); + llvm::SmallVector lbounds; + llvm::SmallVector explicitTypeParams; + exv.match( + [&](const fir::ArrayBoxValue &box) { + lbounds.append(box.getLBounds().begin(), box.getLBounds().end()); + }, + [&](const fir::CharArrayBoxValue &box) { + lbounds.append(box.getLBounds().begin(), box.getLBounds().end()); + explicitTypeParams.emplace_back(box.getLen()); + }, + [&](const fir::CharBoxValue &box) { + explicitTypeParams.emplace_back(box.getLen()); + }, + [&](const fir::MutableBoxValue &x) { + explicitTypeParams.append(x.nonDeferredLenParams().begin(), + x.nonDeferredLenParams().end()); + }, + [](const auto &) {}); + return fir::BoxValue(box, lbounds, explicitTypeParams); +} diff --git a/flang/test/Lower/HLFIR/expr-addr.f90 b/flang/test/Lower/HLFIR/expr-addr.f90 --- a/flang/test/Lower/HLFIR/expr-addr.f90 +++ b/flang/test/Lower/HLFIR/expr-addr.f90 @@ -1,8 +1,12 @@ ! Test lowering of of expressions as address -! RUN: %not_todo_cmd bbc -emit-fir -hlfir -o - %s 2>&1 | FileCheck %s +! RUN: bbc -emit-fir -hlfir -o - %s 2>&1 | FileCheck %s +! CHECK-LABEL: func.func @_QPfoo( +! CHECK-SAME: %[[arg0:.*]]: !fir.ref subroutine foo(x) integer :: x - ! CHECK: not yet implemented: lower expr to HLFIR address read (*,*) x + ! CHECK: %[[x:.]] = fir.declare %[[arg0]] {uniq_name = "_QFfooEx"} : (!fir.ref) -> !fir.ref + ! CHECK: %[[x_cast:.*]] = fir.convert %[[x]] : (!fir.ref) -> !fir.ref + ! CHECK: fir.call @_FortranAioInputInteger(%{{.*}}, %[[x_cast]], %{{.*}}) : (!fir.ref, !fir.ref, i32) -> i1 end subroutine diff --git a/flang/test/Lower/HLFIR/expr-box.f90 b/flang/test/Lower/HLFIR/expr-box.f90 --- a/flang/test/Lower/HLFIR/expr-box.f90 +++ b/flang/test/Lower/HLFIR/expr-box.f90 @@ -1,8 +1,14 @@ ! Test lowering of of expressions as fir.box -! RUN: %not_todo_cmd bbc -emit-fir -hlfir -o - %s 2>&1 | FileCheck %s +! RUN: bbc -hlfir -o - %s 2>&1 | FileCheck %s +! CHECK-LABEL: func.func @_QPfoo( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> subroutine foo(x) - integer :: x(:) - ! CHECK: not yet implemented: generate fir.declare for box + integer :: x(21:30) print *, x +! CHECK-DAG: %[[VAL_3:.*]] = arith.constant 21 : index +! CHECK-DAG: %[[VAL_4:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_5:.*]] = fir.shape_shift %[[VAL_4]], %[[VAL_3]] : (index, index) -> !fir.shapeshift<1> +! CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_0]](%[[VAL_5]]) {uniq_name = "_QFfooEx"} : (!fir.ref>, !fir.shapeshift<1>) -> !fir.ref> +! CHECK: fir.embox %[[VAL_6]](%[[VAL_5]]) : (!fir.ref>, !fir.shapeshift<1>) -> !fir.box> end subroutine