[flang] Add kernel to lower expressions to HLFIR

This patch adds the kernel to lower evaluate::Expr to HLFIR to a
hlfir::FortranEntity (a single mlir::Value that can be interpreted as
a Fortran variable or the value of a Fortram expression).

It implements lowering of simple name designators ("x") and starts
adding a translation layer in AbstractConverter::genExprBox and
AbstractConverter::genExprAddr so that the new expression lowering
can be used without any changes for now in the current statement and
construct lowering.

Differential Revision: https://reviews.llvm.org/D136453
This commit is contained in:
Jean Perier 2022-10-24 15:35:19 +02:00
parent b7c922607c
commit c14ef2d762
11 changed files with 340 additions and 10 deletions

View File

@ -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

View File

@ -348,6 +348,9 @@ public:
symbolMapStack.back().try_emplace(sym, definingOp);
}
llvm::Optional<fir::FortranVariableOpInterface>
lookupVariableDefinition(semantics::SymbolRef sym);
private:
/// Add `symbol` to the current map and bind a `box`.
void makeSym(semantics::SymbolRef symRef, const SymbolBox &box,

View File

@ -561,6 +561,10 @@ mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc,
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

View File

@ -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"
@ -416,16 +417,35 @@ public:
return iter->second;
}
fir::ExtendedValue
translateToExtendedValue(mlir::Location loc, hlfir::FortranEntity entity,
Fortran::lower::StatementContext &context) {
auto [exv, exvCleanup] =
hlfir::translateToExtendedValue(loc, getFirOpBuilder(), entity);
if (exvCleanup)
context.attachCleanup(*exvCleanup);
return exv;
}
fir::ExtendedValue
genExprAddr(const Fortran::lower::SomeExpr &expr,
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())
return translateToExtendedValue(loc, loweredExpr, context);
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 +460,18 @@ public:
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 exv = translateToExtendedValue(loc, loweredExpr, stmtCtx);
return fir::factory::createBoxValue(getFirOpBuilder(), loc, exv);
}
TODO(loc,
"lower expression value or pointer and allocatable to HLFIR box");
}
return Fortran::lower::createBoxValue(loc, *this, expr, localSymbols,
stmtCtx);
}

View File

@ -6,6 +6,7 @@ add_flang_library(FortranLower
CallInterface.cpp
Coarray.cpp
ConvertExpr.cpp
ConvertExprToHLFIR.cpp
ConvertType.cpp
ConvertVariable.cpp
ComponentPath.cpp
@ -28,6 +29,7 @@ add_flang_library(FortranLower
FIRBuilder
FIRSupport
FIRTransforms
HLFIRDialect
${dialect_libs}
LINK_LIBS
@ -35,6 +37,7 @@ add_flang_library(FortranLower
FIRBuilder
FIRSupport
FIRTransforms
HLFIRDialect
${dialect_libs}
FortranCommon
FortranParser

View File

@ -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<Fortran::evaluate::Type<
Fortran::evaluate::TypeCategory::Character, 1>>::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<Fortran::evaluate::Type<
Fortran::evaluate::TypeCategory::Real, 4>>::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<Fortran::evaluate::Type<
Fortran::evaluate::TypeCategory::Integer, 4>>::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<fir::FortranVariableOpInterface> 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 <typename T>
hlfir::FortranEntity gen(const Fortran::evaluate::Expr<T> &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 <typename T>
hlfir::FortranEntity gen(const Fortran::evaluate::Designator<T> &designator) {
return HlfirDesignatorBuilder(getLoc(), getConverter(), getSymMap(),
getStmtCtx())
.gen(designator.u);
}
template <typename T>
hlfir::FortranEntity gen(const Fortran::evaluate::FunctionRef<T> &expr) {
TODO(getLoc(), "lowering funcRef to HLFIR");
}
template <typename T>
hlfir::FortranEntity gen(const Fortran::evaluate::Constant<T> &expr) {
TODO(getLoc(), "lowering constant to HLFIR");
}
template <typename T>
hlfir::FortranEntity gen(const Fortran::evaluate::ArrayConstructor<T> &expr) {
TODO(getLoc(), "lowering ArrayCtor to HLFIR");
}
template <Fortran::common::TypeCategory TC1, int KIND,
Fortran::common::TypeCategory TC2>
hlfir::FortranEntity
gen(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, TC2>
&convert) {
TODO(getLoc(), "lowering convert to HLFIR");
}
template <typename D, typename R, typename O>
hlfir::FortranEntity gen(const Fortran::evaluate::Operation<D, R, O> &op) {
TODO(getLoc(), "lowering unary op to HLFIR");
}
template <typename D, typename R, typename LO, typename RO>
hlfir::FortranEntity
gen(const Fortran::evaluate::Operation<D, R, LO, RO> &op) {
TODO(getLoc(), "lowering binary op to HLFIR");
}
hlfir::FortranEntity
gen(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &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);
}

View File

@ -1359,7 +1359,7 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
auto newBase = builder.create<fir::DeclareOp>(
loc, base.getType(), base, shapeOrShift, lenParams, name, attributes);
base = newBase;
symMap.addVariableDefinition(sym, newBase);
symMap.addVariableDefinition(sym, newBase, force);
return;
}

View File

@ -90,6 +90,22 @@ Fortran::lower::SymMap::lookupImpliedDo(Fortran::lower::SymMap::AcDoVar var) {
return {};
}
llvm::Optional<fir::FortranVariableOpInterface>
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<fir::FortranVariableOpInterface>(&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) {

View File

@ -1323,3 +1323,30 @@ mlir::Value fir::factory::genCPtrOrCFunptrAddr(fir::FirOpBuilder &builder,
return builder.create<fir::CoordinateOp>(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<fir::BoxValue>())
return *boxValue;
mlir::Value box = builder.createBox(loc, exv);
llvm::SmallVector<mlir::Value> lbounds;
llvm::SmallVector<mlir::Value> 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);
}

View File

@ -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<i32>
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<i32>) -> !fir.ref<i32>
! CHECK: %[[x_cast:.*]] = fir.convert %[[x]] : (!fir.ref<i32>) -> !fir.ref<i64>
! CHECK: fir.call @_FortranAioInputInteger(%{{.*}}, %[[x_cast]], %{{.*}}) : (!fir.ref<i8>, !fir.ref<i64>, i32) -> i1
end subroutine

View File

@ -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<!fir.array<10xi32>>
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.array<10xi32>>, !fir.shapeshift<1>) -> !fir.ref<!fir.array<10xi32>>
! CHECK: fir.embox %[[VAL_6]](%[[VAL_5]]) : (!fir.ref<!fir.array<10xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<10xi32>>
end subroutine