12c2e5a5dSValentin Clement //===-- ConvertVariable.cpp -- bridge to lower to MLIR --------------------===//
22c2e5a5dSValentin Clement //
32c2e5a5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42c2e5a5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
52c2e5a5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62c2e5a5dSValentin Clement //
72c2e5a5dSValentin Clement //===----------------------------------------------------------------------===//
82c2e5a5dSValentin Clement //
92c2e5a5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
102c2e5a5dSValentin Clement //
112c2e5a5dSValentin Clement //===----------------------------------------------------------------------===//
122c2e5a5dSValentin Clement 
132c2e5a5dSValentin Clement #include "flang/Lower/ConvertVariable.h"
142c2e5a5dSValentin Clement #include "flang/Lower/AbstractConverter.h"
152a59ead1SValentin Clement #include "flang/Lower/Allocatable.h"
162a59ead1SValentin Clement #include "flang/Lower/BoxAnalyzer.h"
172c2e5a5dSValentin Clement #include "flang/Lower/CallInterface.h"
182c2e5a5dSValentin Clement #include "flang/Lower/ConvertExpr.h"
192c2e5a5dSValentin Clement #include "flang/Lower/Mangler.h"
202c2e5a5dSValentin Clement #include "flang/Lower/PFTBuilder.h"
212a59ead1SValentin Clement #include "flang/Lower/StatementContext.h"
222c2e5a5dSValentin Clement #include "flang/Lower/Support/Utils.h"
232c2e5a5dSValentin Clement #include "flang/Lower/SymbolMap.h"
242c2e5a5dSValentin Clement #include "flang/Lower/Todo.h"
252c2e5a5dSValentin Clement #include "flang/Optimizer/Builder/Character.h"
262c2e5a5dSValentin Clement #include "flang/Optimizer/Builder/FIRBuilder.h"
272c2e5a5dSValentin Clement #include "flang/Optimizer/Builder/Runtime/Derived.h"
282c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
292c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIRDialect.h"
302c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
312c2e5a5dSValentin Clement #include "flang/Optimizer/Support/FIRContext.h"
322c2e5a5dSValentin Clement #include "flang/Optimizer/Support/FatalError.h"
332c2e5a5dSValentin Clement #include "flang/Semantics/tools.h"
342c2e5a5dSValentin Clement #include "llvm/Support/Debug.h"
352c2e5a5dSValentin Clement 
362c2e5a5dSValentin Clement #define DEBUG_TYPE "flang-lower-variable"
372c2e5a5dSValentin Clement 
382a59ead1SValentin Clement /// Helper to lower a scalar expression using a specific symbol mapping.
392a59ead1SValentin Clement static mlir::Value genScalarValue(Fortran::lower::AbstractConverter &converter,
402a59ead1SValentin Clement                                   mlir::Location loc,
412a59ead1SValentin Clement                                   const Fortran::lower::SomeExpr &expr,
422a59ead1SValentin Clement                                   Fortran::lower::SymMap &symMap,
432a59ead1SValentin Clement                                   Fortran::lower::StatementContext &context) {
442a59ead1SValentin Clement   // This does not use the AbstractConverter member function to override the
452a59ead1SValentin Clement   // symbol mapping to be used expression lowering.
462a59ead1SValentin Clement   return fir::getBase(Fortran::lower::createSomeExtendedExpression(
472a59ead1SValentin Clement       loc, converter, expr, symMap, context));
482a59ead1SValentin Clement }
492a59ead1SValentin Clement 
502c2e5a5dSValentin Clement //===----------------------------------------------------------------===//
512c2e5a5dSValentin Clement // Local variables instantiation (not for alias)
522c2e5a5dSValentin Clement //===----------------------------------------------------------------===//
532c2e5a5dSValentin Clement 
542c2e5a5dSValentin Clement /// Create a stack slot for a local variable. Precondition: the insertion
552c2e5a5dSValentin Clement /// point of the builder must be in the entry block, which is currently being
562c2e5a5dSValentin Clement /// constructed.
572c2e5a5dSValentin Clement static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
582c2e5a5dSValentin Clement                                   mlir::Location loc,
592c2e5a5dSValentin Clement                                   const Fortran::lower::pft::Variable &var,
602c2e5a5dSValentin Clement                                   mlir::Value preAlloc,
612c2e5a5dSValentin Clement                                   llvm::ArrayRef<mlir::Value> shape = {},
622c2e5a5dSValentin Clement                                   llvm::ArrayRef<mlir::Value> lenParams = {}) {
632c2e5a5dSValentin Clement   if (preAlloc)
642c2e5a5dSValentin Clement     return preAlloc;
652c2e5a5dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
662c2e5a5dSValentin Clement   std::string nm = Fortran::lower::mangle::mangleName(var.getSymbol());
672c2e5a5dSValentin Clement   mlir::Type ty = converter.genType(var);
682c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &ultimateSymbol =
692c2e5a5dSValentin Clement       var.getSymbol().GetUltimate();
702c2e5a5dSValentin Clement   llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
712c2e5a5dSValentin Clement   bool isTarg = var.isTarget();
722c2e5a5dSValentin Clement   // Let the builder do all the heavy lifting.
732c2e5a5dSValentin Clement   return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg);
742c2e5a5dSValentin Clement }
752c2e5a5dSValentin Clement 
762c2e5a5dSValentin Clement /// Instantiate a local variable. Precondition: Each variable will be visited
772c2e5a5dSValentin Clement /// such that if its properties depend on other variables, the variables upon
782c2e5a5dSValentin Clement /// which its properties depend will already have been visited.
792c2e5a5dSValentin Clement static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
802c2e5a5dSValentin Clement                              const Fortran::lower::pft::Variable &var,
812c2e5a5dSValentin Clement                              Fortran::lower::SymMap &symMap) {
822c2e5a5dSValentin Clement   assert(!var.isAlias());
832a59ead1SValentin Clement   Fortran::lower::StatementContext stmtCtx;
842a59ead1SValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx);
852a59ead1SValentin Clement }
862a59ead1SValentin Clement 
872a59ead1SValentin Clement /// Helper to decide if a dummy argument must be tracked in an BoxValue.
882a59ead1SValentin Clement static bool lowerToBoxValue(const Fortran::semantics::Symbol &sym,
892a59ead1SValentin Clement                             mlir::Value dummyArg) {
902a59ead1SValentin Clement   // Only dummy arguments coming as fir.box can be tracked in an BoxValue.
912a59ead1SValentin Clement   if (!dummyArg || !dummyArg.getType().isa<fir::BoxType>())
922a59ead1SValentin Clement     return false;
932a59ead1SValentin Clement   // Non contiguous arrays must be tracked in an BoxValue.
942a59ead1SValentin Clement   if (sym.Rank() > 0 && !sym.attrs().test(Fortran::semantics::Attr::CONTIGUOUS))
952a59ead1SValentin Clement     return true;
962a59ead1SValentin Clement   // Assumed rank and optional fir.box cannot yet be read while lowering the
972a59ead1SValentin Clement   // specifications.
982a59ead1SValentin Clement   if (Fortran::evaluate::IsAssumedRank(sym) ||
992a59ead1SValentin Clement       Fortran::semantics::IsOptional(sym))
1002a59ead1SValentin Clement     return true;
1012a59ead1SValentin Clement   // Polymorphic entity should be tracked through a fir.box that has the
1022a59ead1SValentin Clement   // dynamic type info.
1032a59ead1SValentin Clement   if (const Fortran::semantics::DeclTypeSpec *type = sym.GetType())
1042a59ead1SValentin Clement     if (type->IsPolymorphic())
1052a59ead1SValentin Clement       return true;
1062a59ead1SValentin Clement   return false;
1072a59ead1SValentin Clement }
1082a59ead1SValentin Clement 
1092a59ead1SValentin Clement /// Compute extent from lower and upper bound.
1102a59ead1SValentin Clement static mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc,
1112a59ead1SValentin Clement                                  mlir::Value lb, mlir::Value ub) {
1122a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
1132a59ead1SValentin Clement   // Let the folder deal with the common `ub - <const> + 1` case.
1142a59ead1SValentin Clement   auto diff = builder.create<mlir::arith::SubIOp>(loc, idxTy, ub, lb);
1152a59ead1SValentin Clement   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
1162a59ead1SValentin Clement   return builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one);
1172a59ead1SValentin Clement }
1182a59ead1SValentin Clement 
1192a59ead1SValentin Clement /// Lower explicit lower bounds into \p result. Does nothing if this is not an
1202a59ead1SValentin Clement /// array, or if the lower bounds are deferred, or all implicit or one.
1212a59ead1SValentin Clement static void lowerExplicitLowerBounds(
1222a59ead1SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
1232a59ead1SValentin Clement     const Fortran::lower::BoxAnalyzer &box,
1242a59ead1SValentin Clement     llvm::SmallVectorImpl<mlir::Value> &result, Fortran::lower::SymMap &symMap,
1252a59ead1SValentin Clement     Fortran::lower::StatementContext &stmtCtx) {
1262a59ead1SValentin Clement   if (!box.isArray() || box.lboundIsAllOnes())
1272a59ead1SValentin Clement     return;
1282a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1292a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
1302a59ead1SValentin Clement   if (box.isStaticArray()) {
1312a59ead1SValentin Clement     for (int64_t lb : box.staticLBound())
1322a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, lb));
1332a59ead1SValentin Clement     return;
1342a59ead1SValentin Clement   }
1352a59ead1SValentin Clement   for (const Fortran::semantics::ShapeSpec *spec : box.dynamicBound()) {
1362a59ead1SValentin Clement     if (auto low = spec->lbound().GetExplicit()) {
1372a59ead1SValentin Clement       auto expr = Fortran::lower::SomeExpr{*low};
1382a59ead1SValentin Clement       mlir::Value lb = builder.createConvert(
1392a59ead1SValentin Clement           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
1402a59ead1SValentin Clement       result.emplace_back(lb);
1412a59ead1SValentin Clement     } else if (!spec->lbound().isColon()) {
1422a59ead1SValentin Clement       // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
1432a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, 1));
1442a59ead1SValentin Clement     }
1452a59ead1SValentin Clement   }
1462a59ead1SValentin Clement   assert(result.empty() || result.size() == box.dynamicBound().size());
1472a59ead1SValentin Clement }
1482a59ead1SValentin Clement 
1492a59ead1SValentin Clement /// Lower explicit extents into \p result if this is an explicit-shape or
1502a59ead1SValentin Clement /// assumed-size array. Does nothing if this is not an explicit-shape or
1512a59ead1SValentin Clement /// assumed-size array.
1522a59ead1SValentin Clement static void lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
1532a59ead1SValentin Clement                                  mlir::Location loc,
1542a59ead1SValentin Clement                                  const Fortran::lower::BoxAnalyzer &box,
1552a59ead1SValentin Clement                                  llvm::ArrayRef<mlir::Value> lowerBounds,
1562a59ead1SValentin Clement                                  llvm::SmallVectorImpl<mlir::Value> &result,
1572a59ead1SValentin Clement                                  Fortran::lower::SymMap &symMap,
1582a59ead1SValentin Clement                                  Fortran::lower::StatementContext &stmtCtx) {
1592a59ead1SValentin Clement   if (!box.isArray())
1602a59ead1SValentin Clement     return;
1612a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1622a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
1632a59ead1SValentin Clement   if (box.isStaticArray()) {
1642a59ead1SValentin Clement     for (int64_t extent : box.staticShape())
1652a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, extent));
1662a59ead1SValentin Clement     return;
1672a59ead1SValentin Clement   }
1682a59ead1SValentin Clement   for (const auto &spec : llvm::enumerate(box.dynamicBound())) {
1692a59ead1SValentin Clement     if (auto up = spec.value()->ubound().GetExplicit()) {
1702a59ead1SValentin Clement       auto expr = Fortran::lower::SomeExpr{*up};
1712a59ead1SValentin Clement       mlir::Value ub = builder.createConvert(
1722a59ead1SValentin Clement           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
1732a59ead1SValentin Clement       if (lowerBounds.empty())
1742a59ead1SValentin Clement         result.emplace_back(ub);
1752a59ead1SValentin Clement       else
1762a59ead1SValentin Clement         result.emplace_back(
1772a59ead1SValentin Clement             computeExtent(builder, loc, lowerBounds[spec.index()], ub));
1782a59ead1SValentin Clement     } else if (spec.value()->ubound().isStar()) {
1792a59ead1SValentin Clement       // Assumed extent is undefined. Must be provided by user's code.
1802a59ead1SValentin Clement       result.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
1812a59ead1SValentin Clement     }
1822a59ead1SValentin Clement   }
1832a59ead1SValentin Clement   assert(result.empty() || result.size() == box.dynamicBound().size());
1842a59ead1SValentin Clement }
1852a59ead1SValentin Clement 
1862a59ead1SValentin Clement /// Treat negative values as undefined. Assumed size arrays will return -1 from
1872a59ead1SValentin Clement /// the front end for example. Using negative values can produce hard to find
1882a59ead1SValentin Clement /// bugs much further along in the compilation.
1892a59ead1SValentin Clement static mlir::Value genExtentValue(fir::FirOpBuilder &builder,
1902a59ead1SValentin Clement                                   mlir::Location loc, mlir::Type idxTy,
1912a59ead1SValentin Clement                                   long frontEndExtent) {
1922a59ead1SValentin Clement   if (frontEndExtent >= 0)
1932a59ead1SValentin Clement     return builder.createIntegerConstant(loc, idxTy, frontEndExtent);
1942a59ead1SValentin Clement   return builder.create<fir::UndefOp>(loc, idxTy);
1952a59ead1SValentin Clement }
1962a59ead1SValentin Clement 
1972a59ead1SValentin Clement /// Lower specification expressions and attributes of variable \p var and
1982a59ead1SValentin Clement /// add it to the symbol map.
1992a59ead1SValentin Clement /// For global and aliases, the address must be pre-computed and provided
2002a59ead1SValentin Clement /// in \p preAlloc.
2012a59ead1SValentin Clement /// Dummy arguments must have already been mapped to mlir block arguments
2022a59ead1SValentin Clement /// their mapping may be updated here.
2032a59ead1SValentin Clement void Fortran::lower::mapSymbolAttributes(
2042a59ead1SValentin Clement     AbstractConverter &converter, const Fortran::lower::pft::Variable &var,
2052a59ead1SValentin Clement     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
2062a59ead1SValentin Clement     mlir::Value preAlloc) {
2072a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
2082c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
2092a59ead1SValentin Clement   const mlir::Location loc = converter.genLocation(sym.name());
2102a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
211da7c77b8SValentin Clement   const bool isDummy = Fortran::semantics::IsDummy(sym);
212da7c77b8SValentin Clement   const bool isResult = Fortran::semantics::IsFunctionResult(sym);
2132a59ead1SValentin Clement   const bool replace = isDummy || isResult;
2142a59ead1SValentin Clement   fir::factory::CharacterExprHelper charHelp{builder, loc};
2152a59ead1SValentin Clement   Fortran::lower::BoxAnalyzer ba;
2162a59ead1SValentin Clement   ba.analyze(sym);
217da7c77b8SValentin Clement 
2182a59ead1SValentin Clement   // First deal with pointers an allocatables, because their handling here
2192a59ead1SValentin Clement   // is the same regardless of their rank.
2202a59ead1SValentin Clement   if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
2212a59ead1SValentin Clement     // Get address of fir.box describing the entity.
2222a59ead1SValentin Clement     // global
2232a59ead1SValentin Clement     mlir::Value boxAlloc = preAlloc;
2242a59ead1SValentin Clement     // dummy or passed result
2252a59ead1SValentin Clement     if (!boxAlloc)
2262a59ead1SValentin Clement       if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
2272a59ead1SValentin Clement         boxAlloc = symbox.getAddr();
2282a59ead1SValentin Clement     // local
2292a59ead1SValentin Clement     if (!boxAlloc)
2302a59ead1SValentin Clement       boxAlloc = createNewLocal(converter, loc, var, preAlloc);
2312a59ead1SValentin Clement     // Lower non deferred parameters.
2322a59ead1SValentin Clement     llvm::SmallVector<mlir::Value> nonDeferredLenParams;
2332a59ead1SValentin Clement     if (ba.isChar()) {
2342a59ead1SValentin Clement       TODO(loc, "mapSymbolAttributes allocatble or pointer char");
2352a59ead1SValentin Clement     } else if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) {
2362a59ead1SValentin Clement       if (const Fortran::semantics::DerivedTypeSpec *derived =
2372a59ead1SValentin Clement               declTy->AsDerived())
2382a59ead1SValentin Clement         if (Fortran::semantics::CountLenParameters(*derived) != 0)
2392a59ead1SValentin Clement           TODO(loc,
2402a59ead1SValentin Clement                "derived type allocatable or pointer with length parameters");
2412a59ead1SValentin Clement     }
2422a59ead1SValentin Clement     fir::MutableBoxValue box = Fortran::lower::createMutableBox(
2432a59ead1SValentin Clement         converter, loc, var, boxAlloc, nonDeferredLenParams);
2442a59ead1SValentin Clement     symMap.addAllocatableOrPointer(var.getSymbol(), box, replace);
2452a59ead1SValentin Clement     return;
2462a59ead1SValentin Clement   }
2472a59ead1SValentin Clement 
2482a59ead1SValentin Clement   if (isDummy) {
2492a59ead1SValentin Clement     mlir::Value dummyArg = symMap.lookupSymbol(sym).getAddr();
2502a59ead1SValentin Clement     if (lowerToBoxValue(sym, dummyArg)) {
2512a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> lbounds;
2522a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> extents;
2532a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> explicitParams;
2542a59ead1SValentin Clement       // Lower lower bounds, explicit type parameters and explicit
2552a59ead1SValentin Clement       // extents if any.
2562a59ead1SValentin Clement       if (ba.isChar())
2572a59ead1SValentin Clement         TODO(loc, "lowerToBoxValue character");
2582a59ead1SValentin Clement       // TODO: derived type length parameters.
2592a59ead1SValentin Clement       lowerExplicitLowerBounds(converter, loc, ba, lbounds, symMap, stmtCtx);
2602a59ead1SValentin Clement       lowerExplicitExtents(converter, loc, ba, lbounds, extents, symMap,
2612a59ead1SValentin Clement                            stmtCtx);
2622a59ead1SValentin Clement       symMap.addBoxSymbol(sym, dummyArg, lbounds, explicitParams, extents,
2632a59ead1SValentin Clement                           replace);
2642a59ead1SValentin Clement       return;
2652a59ead1SValentin Clement     }
2662a59ead1SValentin Clement   }
2672a59ead1SValentin Clement 
2682a59ead1SValentin Clement   // For symbols reaching this point, all properties are constant and can be
2692a59ead1SValentin Clement   // read/computed already into ssa values.
2702a59ead1SValentin Clement 
2712a59ead1SValentin Clement   ba.match(
2722a59ead1SValentin Clement       //===--------------------------------------------------------------===//
2732a59ead1SValentin Clement       // Trivial case.
2742a59ead1SValentin Clement       //===--------------------------------------------------------------===//
2752a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarSym &) {
276da7c77b8SValentin Clement         if (isDummy) {
277da7c77b8SValentin Clement           // This is an argument.
278da7c77b8SValentin Clement           if (!symMap.lookupSymbol(sym))
279da7c77b8SValentin Clement             mlir::emitError(loc, "symbol \"")
280da7c77b8SValentin Clement                 << toStringRef(sym.name()) << "\" must already be in map";
281da7c77b8SValentin Clement           return;
282da7c77b8SValentin Clement         } else if (isResult) {
283da7c77b8SValentin Clement           // Some Fortran results may be passed by argument (e.g. derived
284da7c77b8SValentin Clement           // types)
285da7c77b8SValentin Clement           if (symMap.lookupSymbol(sym))
286da7c77b8SValentin Clement             return;
287da7c77b8SValentin Clement         }
288da7c77b8SValentin Clement         // Otherwise, it's a local variable or function result.
2892a59ead1SValentin Clement         mlir::Value local = createNewLocal(converter, loc, var, preAlloc);
2902c2e5a5dSValentin Clement         symMap.addSymbol(sym, local);
2912a59ead1SValentin Clement       },
2922a59ead1SValentin Clement 
2932a59ead1SValentin Clement       //===--------------------------------------------------------------===//
2942a59ead1SValentin Clement       // The non-trivial cases are when we have an argument or local that has
2952a59ead1SValentin Clement       // a repetition value. Arguments might be passed as simple pointers and
2962a59ead1SValentin Clement       // need to be cast to a multi-dimensional array with constant bounds
2972a59ead1SValentin Clement       // (possibly with a missing column), bounds computed in the callee
2982a59ead1SValentin Clement       // (here), or with bounds from the caller (boxed somewhere else). Locals
2992a59ead1SValentin Clement       // have the same properties except they are never boxed arguments from
3002a59ead1SValentin Clement       // the caller and never having a missing column size.
3012a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3022a59ead1SValentin Clement 
3032a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarStaticChar &x) {
304*f9704f0cSValentin Clement         TODO(loc, "ScalarStaticChar variable lowering");
3052a59ead1SValentin Clement       },
3062a59ead1SValentin Clement 
3072a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3082a59ead1SValentin Clement 
3092a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarDynamicChar &x) {
310*f9704f0cSValentin Clement         TODO(loc, "ScalarDynamicChar variable lowering");
3112a59ead1SValentin Clement       },
3122a59ead1SValentin Clement 
3132a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3142a59ead1SValentin Clement 
3152a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArray &x) {
3162a59ead1SValentin Clement         // object shape is constant, not a character
3172a59ead1SValentin Clement         mlir::Type castTy = builder.getRefType(converter.genType(var));
3182a59ead1SValentin Clement         mlir::Value addr = symMap.lookupSymbol(sym).getAddr();
3192a59ead1SValentin Clement         if (addr)
3202a59ead1SValentin Clement           addr = builder.createConvert(loc, castTy, addr);
3212a59ead1SValentin Clement         if (x.lboundAllOnes()) {
3222a59ead1SValentin Clement           // if lower bounds are all ones, build simple shaped object
3232a59ead1SValentin Clement           llvm::SmallVector<mlir::Value> shape;
3242a59ead1SValentin Clement           for (int64_t i : x.shapes)
3252a59ead1SValentin Clement             shape.push_back(genExtentValue(builder, loc, idxTy, i));
3262a59ead1SValentin Clement           mlir::Value local =
3272a59ead1SValentin Clement               isDummy ? addr : createNewLocal(converter, loc, var, preAlloc);
3282a59ead1SValentin Clement           symMap.addSymbolWithShape(sym, local, shape, isDummy);
3292a59ead1SValentin Clement           return;
3302a59ead1SValentin Clement         }
3312a59ead1SValentin Clement         // If object is an array process the lower bound and extent values by
3322a59ead1SValentin Clement         // constructing constants and populating the lbounds and extents.
3332a59ead1SValentin Clement         llvm::SmallVector<mlir::Value> extents;
3342a59ead1SValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
3352a59ead1SValentin Clement         for (auto [fst, snd] : llvm::zip(x.lbounds, x.shapes)) {
3362a59ead1SValentin Clement           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, fst));
3372a59ead1SValentin Clement           extents.emplace_back(genExtentValue(builder, loc, idxTy, snd));
3382a59ead1SValentin Clement         }
3392a59ead1SValentin Clement         mlir::Value local =
3402a59ead1SValentin Clement             isDummy ? addr
3412a59ead1SValentin Clement                     : createNewLocal(converter, loc, var, preAlloc, extents);
3422a59ead1SValentin Clement         assert(isDummy || Fortran::lower::isExplicitShape(sym));
3432a59ead1SValentin Clement         symMap.addSymbolWithBounds(sym, local, extents, lbounds, isDummy);
3442a59ead1SValentin Clement       },
3452a59ead1SValentin Clement 
3462a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3472a59ead1SValentin Clement 
3482a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArray &x) {
349*f9704f0cSValentin Clement         TODO(loc, "DynamicArray variable lowering");
3502a59ead1SValentin Clement       },
3512a59ead1SValentin Clement 
3522a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3532a59ead1SValentin Clement 
3542a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArrayStaticChar &x) {
355*f9704f0cSValentin Clement         TODO(loc, "StaticArrayStaticChar variable lowering");
3562a59ead1SValentin Clement       },
3572a59ead1SValentin Clement 
3582a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3592a59ead1SValentin Clement 
3602a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArrayDynamicChar &x) {
361*f9704f0cSValentin Clement         TODO(loc, "StaticArrayDynamicChar variable lowering");
3622a59ead1SValentin Clement       },
3632a59ead1SValentin Clement 
3642a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3652a59ead1SValentin Clement 
3662a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArrayStaticChar &x) {
367*f9704f0cSValentin Clement         TODO(loc, "DynamicArrayStaticChar variable lowering");
3682a59ead1SValentin Clement       },
3692a59ead1SValentin Clement 
3702a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3712a59ead1SValentin Clement 
3722a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArrayDynamicChar &x) {
373*f9704f0cSValentin Clement         TODO(loc, "DynamicArrayDynamicChar variable lowering");
3742a59ead1SValentin Clement       },
3752a59ead1SValentin Clement 
3762a59ead1SValentin Clement       //===--------------------------------------------------------------===//
3772a59ead1SValentin Clement 
3782a59ead1SValentin Clement       [&](const Fortran::lower::BoxAnalyzer::None &) {
3792a59ead1SValentin Clement         mlir::emitError(loc, "symbol analysis failed on ")
3802a59ead1SValentin Clement             << toStringRef(sym.name());
3812a59ead1SValentin Clement       });
3822c2e5a5dSValentin Clement }
3832c2e5a5dSValentin Clement 
3842c2e5a5dSValentin Clement void Fortran::lower::instantiateVariable(AbstractConverter &converter,
3852c2e5a5dSValentin Clement                                          const pft::Variable &var,
3862c2e5a5dSValentin Clement                                          SymMap &symMap) {
3872c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
3882c2e5a5dSValentin Clement   const mlir::Location loc = converter.genLocation(sym.name());
3892c2e5a5dSValentin Clement   if (var.isAggregateStore()) {
3902c2e5a5dSValentin Clement     TODO(loc, "instantiateVariable AggregateStore");
3912c2e5a5dSValentin Clement   } else if (Fortran::semantics::FindCommonBlockContaining(
3922c2e5a5dSValentin Clement                  var.getSymbol().GetUltimate())) {
3932c2e5a5dSValentin Clement     TODO(loc, "instantiateVariable Common");
3942c2e5a5dSValentin Clement   } else if (var.isAlias()) {
3952c2e5a5dSValentin Clement     TODO(loc, "instantiateVariable Alias");
3962c2e5a5dSValentin Clement   } else if (var.isGlobal()) {
3972c2e5a5dSValentin Clement     TODO(loc, "instantiateVariable Global");
3982c2e5a5dSValentin Clement   } else {
3992c2e5a5dSValentin Clement     instantiateLocal(converter, var, symMap);
4002c2e5a5dSValentin Clement   }
4012c2e5a5dSValentin Clement }
402d0b70a07SValentin Clement 
403d0b70a07SValentin Clement void Fortran::lower::mapCallInterfaceSymbols(
404d0b70a07SValentin Clement     AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
405d0b70a07SValentin Clement     SymMap &symMap) {
406d0b70a07SValentin Clement   const Fortran::semantics::Symbol &result = caller.getResultSymbol();
407d0b70a07SValentin Clement   for (Fortran::lower::pft::Variable var :
408d0b70a07SValentin Clement        Fortran::lower::pft::buildFuncResultDependencyList(result)) {
409d0b70a07SValentin Clement     if (var.isAggregateStore()) {
410d0b70a07SValentin Clement       instantiateVariable(converter, var, symMap);
411d0b70a07SValentin Clement     } else {
412d0b70a07SValentin Clement       const Fortran::semantics::Symbol &sym = var.getSymbol();
413d0b70a07SValentin Clement       const auto *hostDetails =
414d0b70a07SValentin Clement           sym.detailsIf<Fortran::semantics::HostAssocDetails>();
415d0b70a07SValentin Clement       if (hostDetails && !var.isModuleVariable()) {
416d0b70a07SValentin Clement         // The callee is an internal procedure `A` whose result properties
417d0b70a07SValentin Clement         // depend on host variables. The caller may be the host, or another
418d0b70a07SValentin Clement         // internal procedure `B` contained in the same host.  In the first
419d0b70a07SValentin Clement         // case, the host symbol is obviously mapped, in the second case, it
420d0b70a07SValentin Clement         // must also be mapped because
421d0b70a07SValentin Clement         // HostAssociations::internalProcedureBindings that was called when
422d0b70a07SValentin Clement         // lowering `B` will have mapped all host symbols of captured variables
423d0b70a07SValentin Clement         // to the tuple argument containing the composite of all host associated
424d0b70a07SValentin Clement         // variables, whether or not the host symbol is actually referred to in
425d0b70a07SValentin Clement         // `B`. Hence it is possible to simply lookup the variable associated to
426d0b70a07SValentin Clement         // the host symbol without having to go back to the tuple argument.
427d0b70a07SValentin Clement         Fortran::lower::SymbolBox hostValue =
428d0b70a07SValentin Clement             symMap.lookupSymbol(hostDetails->symbol());
429d0b70a07SValentin Clement         assert(hostValue && "callee host symbol must be mapped on caller side");
430d0b70a07SValentin Clement         symMap.addSymbol(sym, hostValue.toExtendedValue());
431d0b70a07SValentin Clement         // The SymbolBox associated to the host symbols is complete, skip
432d0b70a07SValentin Clement         // instantiateVariable that would try to allocate a new storage.
433d0b70a07SValentin Clement         continue;
434d0b70a07SValentin Clement       }
435d0b70a07SValentin Clement       if (Fortran::semantics::IsDummy(sym) && sym.owner() == result.owner()) {
436d0b70a07SValentin Clement         // Get the argument for the dummy argument symbols of the current call.
437d0b70a07SValentin Clement         symMap.addSymbol(sym, caller.getArgumentValue(sym));
438d0b70a07SValentin Clement         // All the properties of the dummy variable may not come from the actual
439d0b70a07SValentin Clement         // argument, let instantiateVariable handle this.
440d0b70a07SValentin Clement       }
441d0b70a07SValentin Clement       // If this is neither a host associated or dummy symbol, it must be a
442d0b70a07SValentin Clement       // module or common block variable to satisfy specification expression
443d0b70a07SValentin Clement       // requirements in 10.1.11, instantiateVariable will get its address and
444d0b70a07SValentin Clement       // properties.
445d0b70a07SValentin Clement       instantiateVariable(converter, var, symMap);
446d0b70a07SValentin Clement     }
447d0b70a07SValentin Clement   }
448d0b70a07SValentin Clement }
449