llvm-project/flang/lib/Lower/ConvertVariable.cpp
Valentin Clement d0b70a070a
[flang] Lower function and subroutine calls
This patch introduce basic function/subroutine calls.
Because of the state of lowering only simple scalar arguments
can be used in the calls. This will be enhanced in follow up
patches with arrays, allocatable, pointer ans so on.

```
subroutine sub1()
end

subroutine sub2()
  call sub1()
end
```

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

Reviewed By: schweitz

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

Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
Co-authored-by: Jean Perier <jperier@nvidia.com>
Co-authored-by: V Donaldson <vdonaldson@nvidia.com>
2022-02-23 19:50:06 +01:00

157 lines
7.1 KiB
C++

//===-- ConvertVariable.cpp -- bridge to lower to MLIR --------------------===//
//
// 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/ConvertVariable.h"
#include "flang/Lower/AbstractConverter.h"
#include "flang/Lower/CallInterface.h"
#include "flang/Lower/ConvertExpr.h"
#include "flang/Lower/Mangler.h"
#include "flang/Lower/PFTBuilder.h"
#include "flang/Lower/Support/Utils.h"
#include "flang/Lower/SymbolMap.h"
#include "flang/Lower/Todo.h"
#include "flang/Optimizer/Builder/Character.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/Runtime/Derived.h"
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Support/FIRContext.h"
#include "flang/Optimizer/Support/FatalError.h"
#include "flang/Semantics/tools.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "flang-lower-variable"
//===----------------------------------------------------------------===//
// Local variables instantiation (not for alias)
//===----------------------------------------------------------------===//
/// Create a stack slot for a local variable. Precondition: the insertion
/// point of the builder must be in the entry block, which is currently being
/// constructed.
static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
mlir::Location loc,
const Fortran::lower::pft::Variable &var,
mlir::Value preAlloc,
llvm::ArrayRef<mlir::Value> shape = {},
llvm::ArrayRef<mlir::Value> lenParams = {}) {
if (preAlloc)
return preAlloc;
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
std::string nm = Fortran::lower::mangle::mangleName(var.getSymbol());
mlir::Type ty = converter.genType(var);
const Fortran::semantics::Symbol &ultimateSymbol =
var.getSymbol().GetUltimate();
llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
bool isTarg = var.isTarget();
// Let the builder do all the heavy lifting.
return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg);
}
/// Instantiate a local variable. Precondition: Each variable will be visited
/// such that if its properties depend on other variables, the variables upon
/// which its properties depend will already have been visited.
static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
const Fortran::lower::pft::Variable &var,
Fortran::lower::SymMap &symMap) {
assert(!var.isAlias());
const Fortran::semantics::Symbol &sym = var.getSymbol();
const bool isDummy = Fortran::semantics::IsDummy(sym);
const bool isResult = Fortran::semantics::IsFunctionResult(sym);
if (symMap.lookupSymbol(sym))
return;
const mlir::Location loc = converter.genLocation(sym.name());
if (isDummy) {
// This is an argument.
if (!symMap.lookupSymbol(sym))
mlir::emitError(loc, "symbol \"")
<< toStringRef(sym.name()) << "\" must already be in map";
return;
} else if (isResult) {
// Some Fortran results may be passed by argument (e.g. derived
// types)
if (symMap.lookupSymbol(sym))
return;
}
// Otherwise, it's a local variable or function result.
mlir::Value local = createNewLocal(converter, loc, var, {});
symMap.addSymbol(sym, local);
}
void Fortran::lower::instantiateVariable(AbstractConverter &converter,
const pft::Variable &var,
SymMap &symMap) {
const Fortran::semantics::Symbol &sym = var.getSymbol();
const mlir::Location loc = converter.genLocation(sym.name());
if (var.isAggregateStore()) {
TODO(loc, "instantiateVariable AggregateStore");
} else if (Fortran::semantics::FindCommonBlockContaining(
var.getSymbol().GetUltimate())) {
TODO(loc, "instantiateVariable Common");
} else if (var.isAlias()) {
TODO(loc, "instantiateVariable Alias");
} else if (var.isGlobal()) {
TODO(loc, "instantiateVariable Global");
} else {
instantiateLocal(converter, var, symMap);
}
}
void Fortran::lower::mapCallInterfaceSymbols(
AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
SymMap &symMap) {
const Fortran::semantics::Symbol &result = caller.getResultSymbol();
for (Fortran::lower::pft::Variable var :
Fortran::lower::pft::buildFuncResultDependencyList(result)) {
if (var.isAggregateStore()) {
instantiateVariable(converter, var, symMap);
} else {
const Fortran::semantics::Symbol &sym = var.getSymbol();
const auto *hostDetails =
sym.detailsIf<Fortran::semantics::HostAssocDetails>();
if (hostDetails && !var.isModuleVariable()) {
// The callee is an internal procedure `A` whose result properties
// depend on host variables. The caller may be the host, or another
// internal procedure `B` contained in the same host. In the first
// case, the host symbol is obviously mapped, in the second case, it
// must also be mapped because
// HostAssociations::internalProcedureBindings that was called when
// lowering `B` will have mapped all host symbols of captured variables
// to the tuple argument containing the composite of all host associated
// variables, whether or not the host symbol is actually referred to in
// `B`. Hence it is possible to simply lookup the variable associated to
// the host symbol without having to go back to the tuple argument.
Fortran::lower::SymbolBox hostValue =
symMap.lookupSymbol(hostDetails->symbol());
assert(hostValue && "callee host symbol must be mapped on caller side");
symMap.addSymbol(sym, hostValue.toExtendedValue());
// The SymbolBox associated to the host symbols is complete, skip
// instantiateVariable that would try to allocate a new storage.
continue;
}
if (Fortran::semantics::IsDummy(sym) && sym.owner() == result.owner()) {
// Get the argument for the dummy argument symbols of the current call.
symMap.addSymbol(sym, caller.getArgumentValue(sym));
// All the properties of the dummy variable may not come from the actual
// argument, let instantiateVariable handle this.
}
// If this is neither a host associated or dummy symbol, it must be a
// module or common block variable to satisfy specification expression
// requirements in 10.1.11, instantiateVariable will get its address and
// properties.
instantiateVariable(converter, var, symMap);
}
}
}