Skip to content

Commit

Permalink
[flang] Handle module in lowering pass
Browse files Browse the repository at this point in the history
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@nvidia.com>
Co-authored-by: Jean Perier <jperier@nvidia.com>
  • Loading branch information
3 people committed Mar 2, 2022
1 parent e0e7bd1 commit 17d7134
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 10 deletions.
6 changes: 6 additions & 0 deletions flang/include/flang/Lower/ConvertVariable.h
Expand Up @@ -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
Expand Down
96 changes: 89 additions & 7 deletions flang/lib/Lower/Bridge.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -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:
Expand Down
25 changes: 25 additions & 0 deletions flang/lib/Lower/ConvertVariable.cpp
Expand Up @@ -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,
Expand Down
11 changes: 8 additions & 3 deletions 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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -74,3 +77,5 @@ subroutine test_simple_local_scalar()
! CHECK: }
x = 42.
end subroutine

end module

0 comments on commit 17d7134

Please sign in to comment.