[flang-commits] [flang] 17d7134 - [flang] Handle module in lowering pass

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Wed Mar 2 09:26:58 PST 2022


Author: Valentin Clement
Date: 2022-03-02T18:26:43+01:00
New Revision: 17d71347b2ede797346b0a499665cf51e593b150

URL: https://github.com/llvm/llvm-project/commit/17d71347b2ede797346b0a499665cf51e593b150
DIFF: https://github.com/llvm/llvm-project/commit/17d71347b2ede797346b0a499665cf51e593b150.diff

LOG: [flang] Handle module in lowering pass

This patch enables the lowering of basic modules and functions/subroutines
in modules.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: PeteSteinfeld

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

Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Co-authored-by: Jean Perier <jperier at nvidia.com>

Added: 
    

Modified: 
    flang/include/flang/Lower/ConvertVariable.h
    flang/lib/Lower/Bridge.cpp
    flang/lib/Lower/ConvertVariable.cpp
    flang/test/Lower/allocatable-assignment.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h
index f01b52a1873d0..0c1c69faa2aba 100644
--- a/flang/include/flang/Lower/ConvertVariable.h
+++ b/flang/include/flang/Lower/ConvertVariable.h
@@ -44,6 +44,12 @@ using AggregateStoreMap = llvm::DenseMap<AggregateStoreKey, mlir::Value>;
 void instantiateVariable(AbstractConverter &, const pft::Variable &var,
                          SymMap &symMap, AggregateStoreMap &storeMap);
 
+/// Create a fir::GlobalOp given a module variable definition. This is intended
+/// to be used when lowering a module definition, not when lowering variables
+/// used from a module. For used variables instantiateVariable must directly be
+/// called.
+void defineModuleVariable(AbstractConverter &, const pft::Variable &var);
+
 /// Lower a symbol attributes given an optional storage \p and add it to the
 /// provided symbol map. If \preAlloc is not provided, a temporary storage will
 /// be allocated. This is a low level function that should only be used if

diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 210d0fbadbdb9..78206c0b20f7a 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -28,6 +28,7 @@
 #include "flang/Optimizer/Builder/Character.h"
 #include "flang/Optimizer/Builder/MutableBox.h"
 #include "flang/Optimizer/Support/FIRContext.h"
+#include "flang/Optimizer/Support/InternalNames.h"
 #include "flang/Runtime/iostat.h"
 #include "flang/Semantics/tools.h"
 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
@@ -57,24 +58,70 @@ class FirConverter : public Fortran::lower::AbstractConverter {
 
   /// Convert the PFT to FIR.
   void run(Fortran::lower::pft::Program &pft) {
+    // Primary translation pass.
+    //  - Declare all functions that have definitions so that definition
+    //    signatures prevail over call site signatures.
+    //  - Define module variables and OpenMP/OpenACC declarative construct so
+    //    that they are available before lowering any function that may use
+    //    them.
+    for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
+      std::visit(Fortran::common::visitors{
+                     [&](Fortran::lower::pft::FunctionLikeUnit &f) {
+                       declareFunction(f);
+                     },
+                     [&](Fortran::lower::pft::ModuleLikeUnit &m) {
+                       lowerModuleDeclScope(m);
+                       for (Fortran::lower::pft::FunctionLikeUnit &f :
+                            m.nestedFunctions)
+                         declareFunction(f);
+                     },
+                     [&](Fortran::lower::pft::BlockDataUnit &b) {},
+                     [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {
+                       setCurrentPosition(
+                           d.get<Fortran::parser::CompilerDirective>().source);
+                       mlir::emitWarning(toLocation(),
+                                         "ignoring all compiler directives");
+                     },
+                 },
+                 u);
+    }
+
     // Primary translation pass.
     for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
       std::visit(
           Fortran::common::visitors{
               [&](Fortran::lower::pft::FunctionLikeUnit &f) { lowerFunc(f); },
-              [&](Fortran::lower::pft::ModuleLikeUnit &m) {},
+              [&](Fortran::lower::pft::ModuleLikeUnit &m) { lowerMod(m); },
               [&](Fortran::lower::pft::BlockDataUnit &b) {},
-              [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {
-                setCurrentPosition(
-                    d.get<Fortran::parser::CompilerDirective>().source);
-                mlir::emitWarning(toLocation(),
-                                  "ignoring all compiler directives");
-              },
+              [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
           },
           u);
     }
   }
 
+  /// Declare a function.
+  void declareFunction(Fortran::lower::pft::FunctionLikeUnit &funit) {
+    setCurrentPosition(funit.getStartingSourceLoc());
+    for (int entryIndex = 0, last = funit.entryPointList.size();
+         entryIndex < last; ++entryIndex) {
+      funit.setActiveEntry(entryIndex);
+      // Calling CalleeInterface ctor will build a declaration mlir::FuncOp with
+      // no other side effects.
+      // TODO: when doing some compiler profiling on real apps, it may be worth
+      // to check it's better to save the CalleeInterface instead of recomputing
+      // it later when lowering the body. CalleeInterface ctor should be linear
+      // with the number of arguments, so it is not awful to do it that way for
+      // now, but the linear coefficient might be non negligible. Until
+      // measured, stick to the solution that impacts the code less.
+      Fortran::lower::CalleeInterface{funit, *this};
+    }
+    funit.setActiveEntry(0);
+
+    // Declare internal procedures
+    for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions)
+      declareFunction(f);
+  }
+
   //===--------------------------------------------------------------------===//
   // AbstractConverter overrides
   //===--------------------------------------------------------------------===//
@@ -407,6 +454,41 @@ class FirConverter : public Fortran::lower::AbstractConverter {
       lowerFunc(f); // internal procedure
   }
 
+  /// Lower module variable definitions to fir::globalOp and OpenMP/OpenACC
+  /// declarative construct.
+  void lowerModuleDeclScope(Fortran::lower::pft::ModuleLikeUnit &mod) {
+    // FIXME: get rid of the bogus function context and instantiate the
+    // globals directly into the module.
+    MLIRContext *context = &getMLIRContext();
+    setCurrentPosition(mod.getStartingSourceLoc());
+    mlir::FuncOp func = fir::FirOpBuilder::createFunction(
+        mlir::UnknownLoc::get(context), getModuleOp(),
+        fir::NameUniquer::doGenerated("ModuleSham"),
+        mlir::FunctionType::get(context, llvm::None, llvm::None));
+    func.addEntryBlock();
+    builder = new fir::FirOpBuilder(func, bridge.getKindMap());
+    for (const Fortran::lower::pft::Variable &var :
+         mod.getOrderedSymbolTable()) {
+      // Only define the variables owned by this module.
+      const Fortran::semantics::Scope *owningScope = var.getOwningScope();
+      if (!owningScope || mod.getScope() == *owningScope)
+        Fortran::lower::defineModuleVariable(*this, var);
+    }
+    for (auto &eval : mod.evaluationList)
+      genFIR(eval);
+    if (mlir::Region *region = func.getCallableRegion())
+      region->dropAllReferences();
+    func.erase();
+    delete builder;
+    builder = nullptr;
+  }
+
+  /// Lower functions contained in a module.
+  void lowerMod(Fortran::lower::pft::ModuleLikeUnit &mod) {
+    for (Fortran::lower::pft::FunctionLikeUnit &f : mod.nestedFunctions)
+      lowerFunc(f);
+  }
+
   mlir::Value hostAssocTupleValue() override final { return hostAssocTuple; }
 
 private:

diff  --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 46636bd26577c..3341feae7c4fb 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -1005,6 +1005,31 @@ void Fortran::lower::mapSymbolAttributes(
       });
 }
 
+void Fortran::lower::defineModuleVariable(
+    AbstractConverter &converter, const Fortran::lower::pft::Variable &var) {
+  // Use empty linkage for module variables, which makes them available
+  // for use in another unit.
+  mlir::StringAttr externalLinkage;
+  if (!var.isGlobal())
+    fir::emitFatalError(converter.getCurrentLocation(),
+                        "attempting to lower module variable as local");
+  // Define aggregate storages for equivalenced objects.
+  if (var.isAggregateStore()) {
+    const mlir::Location loc = converter.genLocation(var.getSymbol().name());
+    TODO(loc, "defineModuleVariable aggregateStore");
+  }
+  const Fortran::semantics::Symbol &sym = var.getSymbol();
+  if (Fortran::semantics::FindCommonBlockContaining(var.getSymbol())) {
+    const mlir::Location loc = converter.genLocation(sym.name());
+    TODO(loc, "defineModuleVariable common block");
+  } else if (var.isAlias()) {
+    // Do nothing. Mapping will be done on user side.
+  } else {
+    std::string globalName = Fortran::lower::mangle::mangleName(sym);
+    defineGlobal(converter, var, globalName, externalLinkage);
+  }
+}
+
 void Fortran::lower::instantiateVariable(AbstractConverter &converter,
                                          const pft::Variable &var,
                                          SymMap &symMap,

diff  --git a/flang/test/Lower/allocatable-assignment.f90 b/flang/test/Lower/allocatable-assignment.f90
index 94a21ca82f864..e151d305f229c 100644
--- a/flang/test/Lower/allocatable-assignment.f90
+++ b/flang/test/Lower/allocatable-assignment.f90
@@ -1,11 +1,14 @@
 ! Test allocatable assignments
 ! RUN: bbc -emit-fir %s -o - | FileCheck %s
 
+module alloc_assign
+contains
+
 ! -----------------------------------------------------------------------------
 !            Test simple scalar RHS
 ! -----------------------------------------------------------------------------
 
-! CHECK-LABEL: func @_QPtest_simple_scalar(
+! CHECK-LABEL: func @_QMalloc_assignPtest_simple_scalar(
 ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<f32>>>{{.*}}) {
 subroutine test_simple_scalar(x)
   real, allocatable  :: x
@@ -40,10 +43,10 @@ subroutine test_simple_scalar(x)
   x = 42.
 end subroutine
 
-! CHECK-LABEL: func @_QPtest_simple_local_scalar() {
+! CHECK-LABEL: func @_QMalloc_assignPtest_simple_local_scalar() {
 subroutine test_simple_local_scalar()
   real, allocatable  :: x
-! CHECK:  %[[VAL_1:.*]] = fir.alloca !fir.heap<f32> {uniq_name = "_QFtest_simple_local_scalarEx.addr"}
+! CHECK:  %[[VAL_1:.*]] = fir.alloca !fir.heap<f32> {uniq_name = "_QMalloc_assignFtest_simple_local_scalarEx.addr"}
 ! CHECK:  %[[VAL_2:.*]] = fir.zero_bits !fir.heap<f32>
 ! CHECK:  fir.store %[[VAL_2]] to %[[VAL_1]] : !fir.ref<!fir.heap<f32>>
 ! CHECK:  %[[VAL_3:.*]] = arith.constant 4.200000e+01 : f32
@@ -74,3 +77,5 @@ subroutine test_simple_local_scalar()
 ! CHECK:  }
   x = 42.
 end subroutine
+
+end module


        


More information about the flang-commits mailing list