[flang-commits] [flang] 8febe67 - [flang] Lower statement function references in HLFIR

Jean Perier via flang-commits flang-commits at lists.llvm.org
Mon Dec 19 02:12:17 PST 2022


Author: Jean Perier
Date: 2022-12-19T11:11:37+01:00
New Revision: 8febe67851458645f93efa33d72717b732007ca7

URL: https://github.com/llvm/llvm-project/commit/8febe67851458645f93efa33d72717b732007ca7
DIFF: https://github.com/llvm/llvm-project/commit/8febe67851458645f93efa33d72717b732007ca7.diff

LOG: [flang] Lower statement function references in HLFIR

Enable lowering of statement function references in HLFIR.  This follows
the same principle as statement function lowering with the current
lowering:
- Actual arguments are lowered and mapped to the statement function
  dummy symbols.
- "HostAssociated" symbols are mapped to their host values (these are
  the symbols referred to inside the statement function expressions that
  are not statement function dummies. e.g: `x` in `stmt_func(i) =
  x(i)`).
- The statement function expression is evaluated.

evaluate::SetLength has to be lowered to deal with statement functions
returning characters since the front-end is generating one to ensure the
statement function expression value is trimmed/padded to match the statement
function declared type.

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

Added: 
    flang/test/Lower/HLFIR/statement-functions.f90

Modified: 
    flang/include/flang/Lower/ConvertVariable.h
    flang/lib/Lower/Bridge.cpp
    flang/lib/Lower/ConvertCall.cpp
    flang/lib/Lower/ConvertExprToHLFIR.cpp
    flang/lib/Lower/ConvertVariable.cpp
    flang/lib/Lower/SymbolMap.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h
index 0d3964282e5d..0e2932fa1ab8 100644
--- a/flang/include/flang/Lower/ConvertVariable.h
+++ b/flang/include/flang/Lower/ConvertVariable.h
@@ -70,6 +70,9 @@ void defineCommonBlocks(
 /// instantiateVariable cannot be called.
 void mapSymbolAttributes(AbstractConverter &, const pft::Variable &, SymMap &,
                          StatementContext &, mlir::Value preAlloc = {});
+void mapSymbolAttributes(AbstractConverter &, const semantics::SymbolRef &,
+                         SymMap &, StatementContext &,
+                         mlir::Value preAlloc = {});
 
 /// Instantiate the variables that appear in the specification expressions
 /// of the result of a function call. The instantiated variables are added

diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index f29f785da6af..1d9755e22785 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -449,7 +449,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
 
   void copySymbolBinding(Fortran::lower::SymbolRef src,
                          Fortran::lower::SymbolRef target) override final {
-    localSymbols.addSymbol(target, lookupSymbol(src).toExtendedValue());
+    if (bridge.getLoweringOptions().getLowerToHighLevelFIR())
+      localSymbols.addVariableDefinition(
+          target, localSymbols.lookupVariableDefinition(src).value());
+    else
+      localSymbols.addSymbol(target, lookupSymbol(src).toExtendedValue());
   }
 
   /// Add the symbol binding to the inner-most level of the symbol map and

diff  --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index ef7fdf264945..5ccb8a9e6561 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -406,6 +406,82 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
   return callResult;
 }
 
+static hlfir::EntityWithAttributes genStmtFunctionRef(
+    mlir::Location loc, Fortran::lower::AbstractConverter &converter,
+    Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
+    const Fortran::evaluate::ProcedureRef &procRef) {
+  const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol();
+  assert(symbol && "expected symbol in ProcedureRef of statement functions");
+  const auto &details = symbol->get<Fortran::semantics::SubprogramDetails>();
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+
+  // Statement functions have their own scope, we just need to associate
+  // the dummy symbols to argument expressions. There are no
+  // optional/alternate return arguments. Statement functions cannot be
+  // recursive (directly or indirectly) so it is safe to add dummy symbols to
+  // the local map here.
+  symMap.pushScope();
+  llvm::SmallVector<hlfir::AssociateOp> exprAssociations;
+  for (auto [arg, bind] : llvm::zip(details.dummyArgs(), procRef.arguments())) {
+    assert(arg && "alternate return in statement function");
+    assert(bind && "optional argument in statement function");
+    const auto *expr = bind->UnwrapExpr();
+    // TODO: assumed type in statement function, that surprisingly seems
+    // allowed, probably because nobody thought of restricting this usage.
+    // gfortran/ifort compiles this.
+    assert(expr && "assumed type used as statement function argument");
+    // As per Fortran 2018 C1580, statement function arguments can only be
+    // scalars.
+    // The only care is to use the dummy character explicit length if any
+    // instead of the actual argument length (that can be bigger).
+    hlfir::EntityWithAttributes loweredArg = Fortran::lower::convertExprToHLFIR(
+        loc, converter, *expr, symMap, stmtCtx);
+    fir::FortranVariableOpInterface variableIface = loweredArg.getIfVariable();
+    if (!variableIface) {
+      // So far only FortranVariableOpInterface can be mapped to symbols.
+      // Create an hlfir.associate to create a variable from a potential
+      // value argument.
+      mlir::Type argType = converter.genType(*arg);
+      auto associate = hlfir::genAssociateExpr(
+          loc, builder, loweredArg, argType, toStringRef(arg->name()));
+      exprAssociations.push_back(associate);
+      variableIface = associate;
+    }
+    const Fortran::semantics::DeclTypeSpec *type = arg->GetType();
+    if (type &&
+        type->category() == Fortran::semantics::DeclTypeSpec::Character) {
+      // Instantiate character as if it was a normal dummy argument so that the
+      // statement function dummy character length is applied and dealt with
+      // correctly.
+      symMap.addSymbol(*arg, variableIface.getBase());
+      Fortran::lower::mapSymbolAttributes(converter, *arg, symMap, stmtCtx);
+    } else {
+      // No need to create an extra hlfir.declare otherwise for
+      // numerical and logical scalar dummies.
+      symMap.addVariableDefinition(*arg, variableIface);
+    }
+  }
+
+  // Explicitly map statement function host associated symbols to their
+  // parent scope lowered symbol box.
+  for (const Fortran::semantics::SymbolRef &sym :
+       Fortran::evaluate::CollectSymbols(*details.stmtFunction()))
+    if (const auto *details =
+            sym->detailsIf<Fortran::semantics::HostAssocDetails>())
+      converter.copySymbolBinding(details->symbol(), sym);
+
+  hlfir::Entity result = Fortran::lower::convertExprToHLFIR(
+      loc, converter, details.stmtFunction().value(), symMap, stmtCtx);
+  symMap.popScope();
+  // The result must not be a variable.
+  result = hlfir::loadTrivialScalar(loc, builder, result);
+  if (result.isVariable())
+    result = hlfir::Entity{builder.create<hlfir::AsExprOp>(loc, result)};
+  for (auto associate : exprAssociations)
+    builder.create<hlfir::EndAssociateOp>(loc, associate);
+  return hlfir::EntityWithAttributes{result};
+}
+
 /// Is this a call to an elemental procedure with at least one array argument?
 static bool
 isElementalProcWithArrayArgs(const Fortran::evaluate::ProcedureRef &procRef) {
@@ -454,7 +530,7 @@ class CallBuilder {
       return genIntrinsicRef(procRef, resultType, *specific);
     }
     if (isStatementFunctionCall(procRef))
-      TODO(loc, "lowering Statement function call to HLFIR");
+      return genStmtFunctionRef(loc, converter, symMap, stmtCtx, procRef);
 
     Fortran::lower::CallerInterface caller(procRef, converter);
     mlir::FunctionType callSiteType = caller.genFunctionType();

diff  --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 589e7d0579ad..7a772a1213a1 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -511,13 +511,15 @@ template <int KIND>
 struct BinaryOp<Fortran::evaluate::SetLength<KIND>> {
   using Op = Fortran::evaluate::SetLength<KIND>;
   static hlfir::EntityWithAttributes gen(mlir::Location loc,
-                                         fir::FirOpBuilder &, const Op &,
-                                         hlfir::Entity, hlfir::Entity) {
-    TODO(loc, "SetLength lowering to HLFIR");
+                                         fir::FirOpBuilder &builder, const Op &,
+                                         hlfir::Entity string,
+                                         hlfir::Entity length) {
+    return hlfir::EntityWithAttributes{
+        builder.create<hlfir::SetLengthOp>(loc, string, length)};
   }
   static void
-  genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &builder,
-                      hlfir::Entity lhs, hlfir::Entity rhs,
+  genResultTypeParams(mlir::Location, fir::FirOpBuilder &, hlfir::Entity,
+                      hlfir::Entity rhs,
                       llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) {
     resultTypeParams.push_back(rhs);
   }

diff  --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index d11a6a301c0a..d2224494e24e 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -1890,6 +1890,14 @@ void Fortran::lower::mapCallInterfaceSymbols(
   }
 }
 
+void Fortran::lower::mapSymbolAttributes(
+    AbstractConverter &converter, const Fortran::semantics::SymbolRef &symbol,
+    Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
+    mlir::Value preAlloc) {
+  mapSymbolAttributes(converter, pft::Variable{symbol}, symMap, stmtCtx,
+                      preAlloc);
+}
+
 void Fortran::lower::createRuntimeTypeInfoGlobal(
     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
     const Fortran::semantics::Symbol &typeInfoSym) {

diff  --git a/flang/lib/Lower/SymbolMap.cpp b/flang/lib/Lower/SymbolMap.cpp
index d15bb6a8efb8..a8f59ee3852e 100644
--- a/flang/lib/Lower/SymbolMap.cpp
+++ b/flang/lib/Lower/SymbolMap.cpp
@@ -92,7 +92,8 @@ Fortran::lower::SymMap::lookupImpliedDo(Fortran::lower::SymMap::AcDoVar var) {
 }
 
 llvm::Optional<fir::FortranVariableOpInterface>
-Fortran::lower::SymMap::lookupVariableDefinition(semantics::SymbolRef sym) {
+Fortran::lower::SymMap::lookupVariableDefinition(semantics::SymbolRef symRef) {
+  Fortran::semantics::SymbolRef sym = symRef.get().GetUltimate();
   for (auto jmap = symbolMapStack.rbegin(), jend = symbolMapStack.rend();
        jmap != jend; ++jmap) {
     auto iter = jmap->find(&*sym);

diff  --git a/flang/test/Lower/HLFIR/statement-functions.f90 b/flang/test/Lower/HLFIR/statement-functions.f90
new file mode 100644
index 000000000000..246334278b0b
--- /dev/null
+++ b/flang/test/Lower/HLFIR/statement-functions.f90
@@ -0,0 +1,35 @@
+! Test lowering of statement functions to HLFIR
+! RUN: bbc -emit-fir -hlfir -o - %s 2>&1 | FileCheck %s
+
+subroutine numeric_test(x)
+  integer :: x(:), i, stmt_func
+  stmt_func(i) = x(i)
+  call bar(stmt_func(42))
+end subroutine
+! CHECK-LABEL: func.func @_QPnumeric_test(
+! CHECK:  %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0:[^)]*]] {{.*}}x"
+! CHECK:  %[[VAL_6:.*]] = arith.constant 42 : i32
+! CHECK:  %[[VAL_7:.*]]:3 = hlfir.associate %[[VAL_6]] {uniq_name = "i"} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
+! CHECK:  %[[VAL_8:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref<i32>
+! CHECK:  %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i32) -> i64
+! CHECK:  %[[VAL_10:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_9]])  : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
+! CHECK:  %[[VAL_11:.*]] = fir.load %[[VAL_10]] : !fir.ref<i32>
+
+subroutine char_test(c, n)
+  character(*) :: c
+  character(n) :: char_stmt_func_dummy_arg
+  character(10) :: stmt_func
+  stmt_func(char_stmt_func_dummy_arg) = char_stmt_func_dummy_arg
+  call bar2(stmt_func(c))
+end subroutine
+! CHECK-LABEL: func.func @_QPchar_test(
+! CHECK:  %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3:.*]]#0 typeparams %[[VAL_3]]#1 {{.*}}c"
+! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_2:[^ ]*]] {{.*}}n"
+! CHECK:  %[[VAL_13:.*]]:2 = fir.unboxchar %[[VAL_4]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+! CHECK:  %[[VAL_14:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
+! CHECK:  %[[VAL_15:.*]] = arith.constant 0 : i32
+! CHECK:  %[[VAL_16:.*]] = arith.cmpi sgt, %[[VAL_14]], %[[VAL_15]] : i32
+! CHECK:  %[[VAL_17:.*]] = arith.select %[[VAL_16]], %[[VAL_14]], %[[VAL_15]] : i32
+! CHECK:  %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_13]]#0 typeparams %[[VAL_17]] {uniq_name = "_QFstmt_funcEchar_stmt_func_dummy_arg"} : (!fir.ref<!fir.char<1,?>>, i32) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK:  %[[VAL_19:.*]] = arith.constant 10 : i64
+! CHECK:  %[[VAL_20:.*]] = hlfir.set_length %[[VAL_18]]#0 len %[[VAL_19]] : (!fir.boxchar<1>, i64) -> !hlfir.expr<!fir.char<1,10>>


        


More information about the flang-commits mailing list