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 
388c22cb84SValentin Clement /// Helper to retrieve a copy of a character literal string from a SomeExpr.
398c22cb84SValentin Clement /// Required to build character global initializers.
408c22cb84SValentin Clement template <int KIND>
418c22cb84SValentin Clement static llvm::Optional<std::tuple<std::string, std::size_t>>
428c22cb84SValentin Clement getCharacterLiteralCopy(
438c22cb84SValentin Clement     const Fortran::evaluate::Expr<
448c22cb84SValentin Clement         Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>
458c22cb84SValentin Clement         &x) {
468c22cb84SValentin Clement   if (const auto *con =
478c22cb84SValentin Clement           Fortran::evaluate::UnwrapConstantValue<Fortran::evaluate::Type<
488c22cb84SValentin Clement               Fortran::common::TypeCategory::Character, KIND>>(x))
498c22cb84SValentin Clement     if (auto val = con->GetScalarValue())
508c22cb84SValentin Clement       return std::tuple<std::string, std::size_t>{
518c22cb84SValentin Clement           std::string{(const char *)val->c_str(),
528c22cb84SValentin Clement                       KIND * (std::size_t)con->LEN()},
538c22cb84SValentin Clement           (std::size_t)con->LEN()};
548c22cb84SValentin Clement   return llvm::None;
558c22cb84SValentin Clement }
568c22cb84SValentin Clement static llvm::Optional<std::tuple<std::string, std::size_t>>
578c22cb84SValentin Clement getCharacterLiteralCopy(
588c22cb84SValentin Clement     const Fortran::evaluate::Expr<Fortran::evaluate::SomeCharacter> &x) {
598c22cb84SValentin Clement   return std::visit([](const auto &e) { return getCharacterLiteralCopy(e); },
608c22cb84SValentin Clement                     x.u);
618c22cb84SValentin Clement }
628c22cb84SValentin Clement static llvm::Optional<std::tuple<std::string, std::size_t>>
638c22cb84SValentin Clement getCharacterLiteralCopy(const Fortran::lower::SomeExpr &x) {
648c22cb84SValentin Clement   if (const auto *e = Fortran::evaluate::UnwrapExpr<
658c22cb84SValentin Clement           Fortran::evaluate::Expr<Fortran::evaluate::SomeCharacter>>(x))
668c22cb84SValentin Clement     return getCharacterLiteralCopy(*e);
678c22cb84SValentin Clement   return llvm::None;
688c22cb84SValentin Clement }
698c22cb84SValentin Clement template <typename A>
708c22cb84SValentin Clement static llvm::Optional<std::tuple<std::string, std::size_t>>
718c22cb84SValentin Clement getCharacterLiteralCopy(const std::optional<A> &x) {
728c22cb84SValentin Clement   if (x)
738c22cb84SValentin Clement     return getCharacterLiteralCopy(*x);
748c22cb84SValentin Clement   return llvm::None;
758c22cb84SValentin Clement }
768c22cb84SValentin Clement 
772a59ead1SValentin Clement /// Helper to lower a scalar expression using a specific symbol mapping.
782a59ead1SValentin Clement static mlir::Value genScalarValue(Fortran::lower::AbstractConverter &converter,
792a59ead1SValentin Clement                                   mlir::Location loc,
802a59ead1SValentin Clement                                   const Fortran::lower::SomeExpr &expr,
812a59ead1SValentin Clement                                   Fortran::lower::SymMap &symMap,
822a59ead1SValentin Clement                                   Fortran::lower::StatementContext &context) {
832a59ead1SValentin Clement   // This does not use the AbstractConverter member function to override the
842a59ead1SValentin Clement   // symbol mapping to be used expression lowering.
852a59ead1SValentin Clement   return fir::getBase(Fortran::lower::createSomeExtendedExpression(
862a59ead1SValentin Clement       loc, converter, expr, symMap, context));
872a59ead1SValentin Clement }
882a59ead1SValentin Clement 
898c22cb84SValentin Clement /// Does this variable have a default initialization?
908c22cb84SValentin Clement static bool hasDefaultInitialization(const Fortran::semantics::Symbol &sym) {
918c22cb84SValentin Clement   if (sym.has<Fortran::semantics::ObjectEntityDetails>() && sym.size())
928c22cb84SValentin Clement     if (!Fortran::semantics::IsAllocatableOrPointer(sym))
938c22cb84SValentin Clement       if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
948c22cb84SValentin Clement         if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
958c22cb84SValentin Clement                 declTypeSpec->AsDerived())
968c22cb84SValentin Clement           return derivedTypeSpec->HasDefaultInitialization();
978c22cb84SValentin Clement   return false;
988c22cb84SValentin Clement }
998c22cb84SValentin Clement 
1008c22cb84SValentin Clement //===----------------------------------------------------------------===//
1018c22cb84SValentin Clement // Global variables instantiation (not for alias and common)
1028c22cb84SValentin Clement //===----------------------------------------------------------------===//
1038c22cb84SValentin Clement 
1048c22cb84SValentin Clement /// Helper to generate expression value inside global initializer.
1058c22cb84SValentin Clement static fir::ExtendedValue
1068c22cb84SValentin Clement genInitializerExprValue(Fortran::lower::AbstractConverter &converter,
1078c22cb84SValentin Clement                         mlir::Location loc,
1088c22cb84SValentin Clement                         const Fortran::lower::SomeExpr &expr,
1098c22cb84SValentin Clement                         Fortran::lower::StatementContext &stmtCtx) {
1108c22cb84SValentin Clement   // Data initializer are constant value and should not depend on other symbols
1118c22cb84SValentin Clement   // given the front-end fold parameter references. In any case, the "current"
1128c22cb84SValentin Clement   // map of the converter should not be used since it holds mapping to
1138c22cb84SValentin Clement   // mlir::Value from another mlir region. If these value are used by accident
1148c22cb84SValentin Clement   // in the initializer, this will lead to segfaults in mlir code.
1158c22cb84SValentin Clement   Fortran::lower::SymMap emptyMap;
1168c22cb84SValentin Clement   return Fortran::lower::createSomeInitializerExpression(loc, converter, expr,
1178c22cb84SValentin Clement                                                          emptyMap, stmtCtx);
1188c22cb84SValentin Clement }
1198c22cb84SValentin Clement 
1208c22cb84SValentin Clement /// Can this symbol constant be placed in read-only memory?
1218c22cb84SValentin Clement static bool isConstant(const Fortran::semantics::Symbol &sym) {
1228c22cb84SValentin Clement   return sym.attrs().test(Fortran::semantics::Attr::PARAMETER) ||
1238c22cb84SValentin Clement          sym.test(Fortran::semantics::Symbol::Flag::ReadOnly);
1248c22cb84SValentin Clement }
1258c22cb84SValentin Clement 
1268c22cb84SValentin Clement /// Create the global op declaration without any initializer
1278c22cb84SValentin Clement static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
1288c22cb84SValentin Clement                                    const Fortran::lower::pft::Variable &var,
1298c22cb84SValentin Clement                                    llvm::StringRef globalName,
1308c22cb84SValentin Clement                                    mlir::StringAttr linkage) {
1318c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1328c22cb84SValentin Clement   if (fir::GlobalOp global = builder.getNamedGlobal(globalName))
1338c22cb84SValentin Clement     return global;
1348c22cb84SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
1358c22cb84SValentin Clement   mlir::Location loc = converter.genLocation(sym.name());
1368c22cb84SValentin Clement   // Resolve potential host and module association before checking that this
1378c22cb84SValentin Clement   // symbol is an object of a function pointer.
1388c22cb84SValentin Clement   const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
1398c22cb84SValentin Clement   if (!ultimate.has<Fortran::semantics::ObjectEntityDetails>() &&
1408c22cb84SValentin Clement       !ultimate.has<Fortran::semantics::ProcEntityDetails>())
1418c22cb84SValentin Clement     mlir::emitError(loc, "lowering global declaration: symbol '")
1428c22cb84SValentin Clement         << toStringRef(sym.name()) << "' has unexpected details\n";
1438c22cb84SValentin Clement   return builder.createGlobal(loc, converter.genType(var), globalName, linkage,
1448c22cb84SValentin Clement                               mlir::Attribute{}, isConstant(ultimate));
1458c22cb84SValentin Clement }
1468c22cb84SValentin Clement 
1478c22cb84SValentin Clement /// Temporary helper to catch todos in initial data target lowering.
1488c22cb84SValentin Clement static bool
1498c22cb84SValentin Clement hasDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol &sym) {
1508c22cb84SValentin Clement   if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
1518c22cb84SValentin Clement     if (const Fortran::semantics::DerivedTypeSpec *derived =
1528c22cb84SValentin Clement             declTy->AsDerived())
1538c22cb84SValentin Clement       return Fortran::semantics::CountLenParameters(*derived) > 0;
1548c22cb84SValentin Clement   return false;
1558c22cb84SValentin Clement }
1568c22cb84SValentin Clement 
1578c22cb84SValentin Clement static mlir::Type unwrapElementType(mlir::Type type) {
1588c22cb84SValentin Clement   if (mlir::Type ty = fir::dyn_cast_ptrOrBoxEleTy(type))
1598c22cb84SValentin Clement     type = ty;
1608c22cb84SValentin Clement   if (auto seqType = type.dyn_cast<fir::SequenceType>())
1618c22cb84SValentin Clement     type = seqType.getEleTy();
1628c22cb84SValentin Clement   return type;
1638c22cb84SValentin Clement }
1648c22cb84SValentin Clement 
1658c22cb84SValentin Clement /// create initial-data-target fir.box in a global initializer region.
1668c22cb84SValentin Clement mlir::Value Fortran::lower::genInitialDataTarget(
1678c22cb84SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
1688c22cb84SValentin Clement     mlir::Type boxType, const Fortran::lower::SomeExpr &initialTarget) {
1698c22cb84SValentin Clement   Fortran::lower::SymMap globalOpSymMap;
1708c22cb84SValentin Clement   Fortran::lower::AggregateStoreMap storeMap;
1718c22cb84SValentin Clement   Fortran::lower::StatementContext stmtCtx;
1728c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1738c22cb84SValentin Clement   if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
1748c22cb84SValentin Clement           initialTarget))
1758c22cb84SValentin Clement     return fir::factory::createUnallocatedBox(builder, loc, boxType,
1768c22cb84SValentin Clement                                               /*nonDeferredParams=*/llvm::None);
1778c22cb84SValentin Clement   // Pointer initial data target, and NULL(mold).
1788c22cb84SValentin Clement   if (const Fortran::semantics::Symbol *sym =
1798c22cb84SValentin Clement           Fortran::evaluate::GetFirstSymbol(initialTarget)) {
1808c22cb84SValentin Clement     // Length parameters processing will need care in global initializer
1818c22cb84SValentin Clement     // context.
1828c22cb84SValentin Clement     if (hasDerivedTypeWithLengthParameters(*sym))
1838c22cb84SValentin Clement       TODO(loc, "initial-data-target with derived type length parameters");
1848c22cb84SValentin Clement 
1858c22cb84SValentin Clement     auto var = Fortran::lower::pft::Variable(*sym, /*global=*/true);
1868c22cb84SValentin Clement     Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
1878c22cb84SValentin Clement                                         storeMap);
1888c22cb84SValentin Clement   }
1898c22cb84SValentin Clement   mlir::Value box;
1908c22cb84SValentin Clement   if (initialTarget.Rank() > 0) {
1918c22cb84SValentin Clement     box = fir::getBase(Fortran::lower::createSomeArrayBox(
1928c22cb84SValentin Clement         converter, initialTarget, globalOpSymMap, stmtCtx));
1938c22cb84SValentin Clement   } else {
1948c22cb84SValentin Clement     fir::ExtendedValue addr = Fortran::lower::createInitializerAddress(
1958c22cb84SValentin Clement         loc, converter, initialTarget, globalOpSymMap, stmtCtx);
1968c22cb84SValentin Clement     box = builder.createBox(loc, addr);
1978c22cb84SValentin Clement   }
1988c22cb84SValentin Clement   // box is a fir.box<T>, not a fir.box<fir.ptr<T>> as it should to be used
1998c22cb84SValentin Clement   // for pointers. A fir.convert should not be used here, because it would
2008c22cb84SValentin Clement   // not actually set the pointer attribute in the descriptor.
2018c22cb84SValentin Clement   // In a normal context, fir.rebox would be used to set the pointer attribute
2028c22cb84SValentin Clement   // while copying the projection from another fir.box. But fir.rebox cannot be
2038c22cb84SValentin Clement   // used in initializer because its current codegen expects that the input
2048c22cb84SValentin Clement   // fir.box is in memory, which is not the case in initializers.
2058c22cb84SValentin Clement   // So, just replace the fir.embox that created addr with one with
2068c22cb84SValentin Clement   // fir.box<fir.ptr<T>> result type.
2078c22cb84SValentin Clement   // Note that the descriptor cannot have been created with fir.rebox because
2088c22cb84SValentin Clement   // the initial-data-target cannot be a fir.box itself (it cannot be
2098c22cb84SValentin Clement   // assumed-shape, deferred-shape, or polymorphic as per C765). However the
2108c22cb84SValentin Clement   // case where the initial data target is a derived type with length parameters
2118c22cb84SValentin Clement   // will most likely be a bit trickier, hence the TODO above.
2128c22cb84SValentin Clement 
2138c22cb84SValentin Clement   mlir::Operation *op = box.getDefiningOp();
2148c22cb84SValentin Clement   if (!op || !mlir::isa<fir::EmboxOp>(*op))
2158c22cb84SValentin Clement     fir::emitFatalError(
2168c22cb84SValentin Clement         loc, "fir.box must be created with embox in global initializers");
2178c22cb84SValentin Clement   mlir::Type targetEleTy = unwrapElementType(box.getType());
2188c22cb84SValentin Clement   if (!fir::isa_char(targetEleTy))
2198c22cb84SValentin Clement     return builder.create<fir::EmboxOp>(loc, boxType, op->getOperands(),
2208c22cb84SValentin Clement                                         op->getAttrs());
2218c22cb84SValentin Clement 
2228c22cb84SValentin Clement   // Handle the character case length particularities: embox takes a length
2238c22cb84SValentin Clement   // value argument when the result type has unknown length, but not when the
2248c22cb84SValentin Clement   // result type has constant length. The type of the initial target must be
2258c22cb84SValentin Clement   // constant length, but the one of the pointer may not be. In this case, a
2268c22cb84SValentin Clement   // length operand must be added.
2278c22cb84SValentin Clement   auto targetLen = targetEleTy.cast<fir::CharacterType>().getLen();
2288c22cb84SValentin Clement   auto ptrLen = unwrapElementType(boxType).cast<fir::CharacterType>().getLen();
2298c22cb84SValentin Clement   if (ptrLen == targetLen)
2308c22cb84SValentin Clement     // Nothing to do
2318c22cb84SValentin Clement     return builder.create<fir::EmboxOp>(loc, boxType, op->getOperands(),
2328c22cb84SValentin Clement                                         op->getAttrs());
2338c22cb84SValentin Clement   auto embox = mlir::cast<fir::EmboxOp>(*op);
2348c22cb84SValentin Clement   auto ptrType = boxType.cast<fir::BoxType>().getEleTy();
2358c22cb84SValentin Clement   mlir::Value memref = builder.createConvert(loc, ptrType, embox.getMemref());
2368c22cb84SValentin Clement   if (targetLen == fir::CharacterType::unknownLen())
2378c22cb84SValentin Clement     // Drop the length argument.
2388c22cb84SValentin Clement     return builder.create<fir::EmboxOp>(loc, boxType, memref, embox.getShape(),
2398c22cb84SValentin Clement                                         embox.getSlice());
2408c22cb84SValentin Clement   // targetLen is constant and ptrLen is unknown. Add a length argument.
2418c22cb84SValentin Clement   mlir::Value targetLenValue =
2428c22cb84SValentin Clement       builder.createIntegerConstant(loc, builder.getIndexType(), targetLen);
2438c22cb84SValentin Clement   return builder.create<fir::EmboxOp>(loc, boxType, memref, embox.getShape(),
2448c22cb84SValentin Clement                                       embox.getSlice(),
2458c22cb84SValentin Clement                                       mlir::ValueRange{targetLenValue});
2468c22cb84SValentin Clement }
2478c22cb84SValentin Clement 
2488c22cb84SValentin Clement static mlir::Value genDefaultInitializerValue(
2498c22cb84SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
2508c22cb84SValentin Clement     const Fortran::semantics::Symbol &sym, mlir::Type symTy,
2518c22cb84SValentin Clement     Fortran::lower::StatementContext &stmtCtx) {
2528c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
2538c22cb84SValentin Clement   mlir::Type scalarType = symTy;
2548c22cb84SValentin Clement   fir::SequenceType sequenceType;
2558c22cb84SValentin Clement   if (auto ty = symTy.dyn_cast<fir::SequenceType>()) {
2568c22cb84SValentin Clement     sequenceType = ty;
2578c22cb84SValentin Clement     scalarType = ty.getEleTy();
2588c22cb84SValentin Clement   }
2598c22cb84SValentin Clement   // Build a scalar default value of the symbol type, looping through the
2608c22cb84SValentin Clement   // components to build each component initial value.
2618c22cb84SValentin Clement   auto recTy = scalarType.cast<fir::RecordType>();
2628c22cb84SValentin Clement   auto fieldTy = fir::FieldType::get(scalarType.getContext());
2638c22cb84SValentin Clement   mlir::Value initialValue = builder.create<fir::UndefOp>(loc, scalarType);
2648c22cb84SValentin Clement   const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
2658c22cb84SValentin Clement   assert(declTy && "var with default initialization must have a type");
2668c22cb84SValentin Clement   Fortran::semantics::OrderedComponentIterator components(
2678c22cb84SValentin Clement       declTy->derivedTypeSpec());
2688c22cb84SValentin Clement   for (const auto &component : components) {
2698c22cb84SValentin Clement     // Skip parent components, the sub-components of parent types are part of
2708c22cb84SValentin Clement     // components and will be looped through right after.
2718c22cb84SValentin Clement     if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
2728c22cb84SValentin Clement       continue;
2738c22cb84SValentin Clement     mlir::Value componentValue;
2748c22cb84SValentin Clement     llvm::StringRef name = toStringRef(component.name());
2758c22cb84SValentin Clement     mlir::Type componentTy = recTy.getType(name);
2768c22cb84SValentin Clement     assert(componentTy && "component not found in type");
2778c22cb84SValentin Clement     if (const auto *object{
2788c22cb84SValentin Clement             component.detailsIf<Fortran::semantics::ObjectEntityDetails>()}) {
2798c22cb84SValentin Clement       if (const auto &init = object->init()) {
2808c22cb84SValentin Clement         // Component has explicit initialization.
2818c22cb84SValentin Clement         if (Fortran::semantics::IsPointer(component))
2828c22cb84SValentin Clement           // Initial data target.
2838c22cb84SValentin Clement           componentValue =
2848c22cb84SValentin Clement               genInitialDataTarget(converter, loc, componentTy, *init);
2858c22cb84SValentin Clement         else
2868c22cb84SValentin Clement           // Initial value.
2878c22cb84SValentin Clement           componentValue = fir::getBase(
2888c22cb84SValentin Clement               genInitializerExprValue(converter, loc, *init, stmtCtx));
2898c22cb84SValentin Clement       } else if (Fortran::semantics::IsAllocatableOrPointer(component)) {
2908c22cb84SValentin Clement         // Pointer or allocatable without initialization.
2918c22cb84SValentin Clement         // Create deallocated/disassociated value.
2928c22cb84SValentin Clement         // From a standard point of view, pointer without initialization do not
2938c22cb84SValentin Clement         // need to be disassociated, but for sanity and simplicity, do it in
2948c22cb84SValentin Clement         // global constructor since this has no runtime cost.
2958c22cb84SValentin Clement         componentValue = fir::factory::createUnallocatedBox(
2968c22cb84SValentin Clement             builder, loc, componentTy, llvm::None);
2978c22cb84SValentin Clement       } else if (hasDefaultInitialization(component)) {
2988c22cb84SValentin Clement         // Component type has default initialization.
2998c22cb84SValentin Clement         componentValue = genDefaultInitializerValue(converter, loc, component,
3008c22cb84SValentin Clement                                                     componentTy, stmtCtx);
3018c22cb84SValentin Clement       } else {
3028c22cb84SValentin Clement         // Component has no initial value.
3038c22cb84SValentin Clement         componentValue = builder.create<fir::UndefOp>(loc, componentTy);
3048c22cb84SValentin Clement       }
3058c22cb84SValentin Clement     } else if (const auto *proc{
3068c22cb84SValentin Clement                    component
3078c22cb84SValentin Clement                        .detailsIf<Fortran::semantics::ProcEntityDetails>()}) {
3088c22cb84SValentin Clement       if (proc->init().has_value())
3098c22cb84SValentin Clement         TODO(loc, "procedure pointer component default initialization");
3108c22cb84SValentin Clement       else
3118c22cb84SValentin Clement         componentValue = builder.create<fir::UndefOp>(loc, componentTy);
3128c22cb84SValentin Clement     }
3138c22cb84SValentin Clement     assert(componentValue && "must have been computed");
3148c22cb84SValentin Clement     componentValue = builder.createConvert(loc, componentTy, componentValue);
3158c22cb84SValentin Clement     // FIXME: type parameters must come from the derived-type-spec
3168c22cb84SValentin Clement     auto field = builder.create<fir::FieldIndexOp>(
3178c22cb84SValentin Clement         loc, fieldTy, name, scalarType,
3188c22cb84SValentin Clement         /*typeParams=*/mlir::ValueRange{} /*TODO*/);
3198c22cb84SValentin Clement     initialValue = builder.create<fir::InsertValueOp>(
3208c22cb84SValentin Clement         loc, recTy, initialValue, componentValue,
3218c22cb84SValentin Clement         builder.getArrayAttr(field.getAttributes()));
3228c22cb84SValentin Clement   }
3238c22cb84SValentin Clement 
3248c22cb84SValentin Clement   if (sequenceType) {
3258c22cb84SValentin Clement     // For arrays, duplicate the scalar value to all elements with an
3268c22cb84SValentin Clement     // fir.insert_range covering the whole array.
3278c22cb84SValentin Clement     auto arrayInitialValue = builder.create<fir::UndefOp>(loc, sequenceType);
3288c22cb84SValentin Clement     llvm::SmallVector<int64_t> rangeBounds;
3298c22cb84SValentin Clement     for (int64_t extent : sequenceType.getShape()) {
3308c22cb84SValentin Clement       if (extent == fir::SequenceType::getUnknownExtent())
3318c22cb84SValentin Clement         TODO(loc,
3328c22cb84SValentin Clement              "default initial value of array component with length parameters");
3338c22cb84SValentin Clement       rangeBounds.push_back(0);
3348c22cb84SValentin Clement       rangeBounds.push_back(extent - 1);
3358c22cb84SValentin Clement     }
3368c22cb84SValentin Clement     return builder.create<fir::InsertOnRangeOp>(
3378c22cb84SValentin Clement         loc, sequenceType, arrayInitialValue, initialValue,
3388c22cb84SValentin Clement         builder.getIndexVectorAttr(rangeBounds));
3398c22cb84SValentin Clement   }
3408c22cb84SValentin Clement   return initialValue;
3418c22cb84SValentin Clement }
3428c22cb84SValentin Clement 
3438c22cb84SValentin Clement /// Does this global already have an initializer ?
3448c22cb84SValentin Clement static bool globalIsInitialized(fir::GlobalOp global) {
3458c22cb84SValentin Clement   return !global.getRegion().empty() || global.getInitVal();
3468c22cb84SValentin Clement }
3478c22cb84SValentin Clement 
3488c22cb84SValentin Clement /// Call \p genInit to generate code inside \p global initializer region.
3498c22cb84SValentin Clement static void
3508c22cb84SValentin Clement createGlobalInitialization(fir::FirOpBuilder &builder, fir::GlobalOp global,
3518c22cb84SValentin Clement                            std::function<void(fir::FirOpBuilder &)> genInit) {
3528c22cb84SValentin Clement   mlir::Region &region = global.getRegion();
3538c22cb84SValentin Clement   region.push_back(new mlir::Block);
3548c22cb84SValentin Clement   mlir::Block &block = region.back();
3558c22cb84SValentin Clement   auto insertPt = builder.saveInsertionPoint();
3568c22cb84SValentin Clement   builder.setInsertionPointToStart(&block);
3578c22cb84SValentin Clement   genInit(builder);
3588c22cb84SValentin Clement   builder.restoreInsertionPoint(insertPt);
3598c22cb84SValentin Clement }
3608c22cb84SValentin Clement 
3618c22cb84SValentin Clement /// Create the global op and its init if it has one
3628c22cb84SValentin Clement static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
3638c22cb84SValentin Clement                                   const Fortran::lower::pft::Variable &var,
3648c22cb84SValentin Clement                                   llvm::StringRef globalName,
3658c22cb84SValentin Clement                                   mlir::StringAttr linkage) {
3668c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
3678c22cb84SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
3688c22cb84SValentin Clement   mlir::Location loc = converter.genLocation(sym.name());
3698c22cb84SValentin Clement   bool isConst = isConstant(sym);
3708c22cb84SValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(globalName);
3718c22cb84SValentin Clement   mlir::Type symTy = converter.genType(var);
3728c22cb84SValentin Clement 
3738c22cb84SValentin Clement   if (global && globalIsInitialized(global))
3748c22cb84SValentin Clement     return global;
3758c22cb84SValentin Clement   // If this is an array, check to see if we can use a dense attribute
3768c22cb84SValentin Clement   // with a tensor mlir type.  This optimization currently only supports
3778c22cb84SValentin Clement   // rank-1 Fortran arrays of integer, real, or logical. The tensor
3788c22cb84SValentin Clement   // type does not support nested structures which are needed for
3798c22cb84SValentin Clement   // complex numbers.
3808c22cb84SValentin Clement   // To get multidimensional arrays to work, we will have to use column major
3818c22cb84SValentin Clement   // array ordering with the tensor type (so it matches column major ordering
3828c22cb84SValentin Clement   // with the Fortran fir.array).  By default, tensor types assume row major
3838c22cb84SValentin Clement   // ordering. How to create this tensor type is to be determined.
3848c22cb84SValentin Clement   if (symTy.isa<fir::SequenceType>() && sym.Rank() == 1 &&
3858c22cb84SValentin Clement       !Fortran::semantics::IsAllocatableOrPointer(sym)) {
3868c22cb84SValentin Clement     mlir::Type eleTy = symTy.cast<fir::SequenceType>().getEleTy();
3878c22cb84SValentin Clement     if (eleTy.isa<mlir::IntegerType, mlir::FloatType, fir::LogicalType>()) {
3888c22cb84SValentin Clement       const auto *details =
3898c22cb84SValentin Clement           sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
3908c22cb84SValentin Clement       if (details->init()) {
3918c22cb84SValentin Clement         global = Fortran::lower::createDenseGlobal(
3928c22cb84SValentin Clement             loc, symTy, globalName, linkage, isConst, details->init().value(),
3938c22cb84SValentin Clement             converter);
3948c22cb84SValentin Clement         if (global) {
3958c22cb84SValentin Clement           global.setVisibility(mlir::SymbolTable::Visibility::Public);
3968c22cb84SValentin Clement           return global;
3978c22cb84SValentin Clement         }
3988c22cb84SValentin Clement       }
3998c22cb84SValentin Clement     }
4008c22cb84SValentin Clement   }
4018c22cb84SValentin Clement   if (!global)
4028c22cb84SValentin Clement     global = builder.createGlobal(loc, symTy, globalName, linkage,
4038c22cb84SValentin Clement                                   mlir::Attribute{}, isConst);
4048c22cb84SValentin Clement   if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
4058c22cb84SValentin Clement     const auto *details =
4068c22cb84SValentin Clement         sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
4078c22cb84SValentin Clement     if (details && details->init()) {
4088c22cb84SValentin Clement       auto expr = *details->init();
4098c22cb84SValentin Clement       createGlobalInitialization(builder, global, [&](fir::FirOpBuilder &b) {
4108c22cb84SValentin Clement         mlir::Value box =
4118c22cb84SValentin Clement             Fortran::lower::genInitialDataTarget(converter, loc, symTy, expr);
4128c22cb84SValentin Clement         b.create<fir::HasValueOp>(loc, box);
4138c22cb84SValentin Clement       });
4148c22cb84SValentin Clement     } else {
4158c22cb84SValentin Clement       // Create unallocated/disassociated descriptor if no explicit init
4168c22cb84SValentin Clement       createGlobalInitialization(builder, global, [&](fir::FirOpBuilder &b) {
4178c22cb84SValentin Clement         mlir::Value box =
4188c22cb84SValentin Clement             fir::factory::createUnallocatedBox(b, loc, symTy, llvm::None);
4198c22cb84SValentin Clement         b.create<fir::HasValueOp>(loc, box);
4208c22cb84SValentin Clement       });
4218c22cb84SValentin Clement     }
4228c22cb84SValentin Clement 
4238c22cb84SValentin Clement   } else if (const auto *details =
4248c22cb84SValentin Clement                  sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
4258c22cb84SValentin Clement     if (details->init()) {
4268c22cb84SValentin Clement       if (fir::isa_char(symTy)) {
4278c22cb84SValentin Clement         // CHARACTER literal
4288c22cb84SValentin Clement         if (auto chLit = getCharacterLiteralCopy(details->init().value())) {
4298c22cb84SValentin Clement           mlir::StringAttr init =
4308c22cb84SValentin Clement               builder.getStringAttr(std::get<std::string>(*chLit));
4318c22cb84SValentin Clement           global->setAttr(global.getInitValAttrName(), init);
4328c22cb84SValentin Clement         } else {
4338c22cb84SValentin Clement           fir::emitFatalError(loc, "CHARACTER has unexpected initial value");
4348c22cb84SValentin Clement         }
4358c22cb84SValentin Clement       } else {
4368c22cb84SValentin Clement         createGlobalInitialization(
4378c22cb84SValentin Clement             builder, global, [&](fir::FirOpBuilder &builder) {
4388c22cb84SValentin Clement               Fortran::lower::StatementContext stmtCtx(
4398c22cb84SValentin Clement                   /*cleanupProhibited=*/true);
4408c22cb84SValentin Clement               fir::ExtendedValue initVal = genInitializerExprValue(
4418c22cb84SValentin Clement                   converter, loc, details->init().value(), stmtCtx);
4428c22cb84SValentin Clement               mlir::Value castTo =
4438c22cb84SValentin Clement                   builder.createConvert(loc, symTy, fir::getBase(initVal));
4448c22cb84SValentin Clement               builder.create<fir::HasValueOp>(loc, castTo);
4458c22cb84SValentin Clement             });
4468c22cb84SValentin Clement       }
4478c22cb84SValentin Clement     } else if (hasDefaultInitialization(sym)) {
4488c22cb84SValentin Clement       createGlobalInitialization(
4498c22cb84SValentin Clement           builder, global, [&](fir::FirOpBuilder &builder) {
4508c22cb84SValentin Clement             Fortran::lower::StatementContext stmtCtx(
4518c22cb84SValentin Clement                 /*cleanupProhibited=*/true);
4528c22cb84SValentin Clement             mlir::Value initVal =
4538c22cb84SValentin Clement                 genDefaultInitializerValue(converter, loc, sym, symTy, stmtCtx);
4548c22cb84SValentin Clement             mlir::Value castTo = builder.createConvert(loc, symTy, initVal);
4558c22cb84SValentin Clement             builder.create<fir::HasValueOp>(loc, castTo);
4568c22cb84SValentin Clement           });
4578c22cb84SValentin Clement     }
4588c22cb84SValentin Clement   } else if (sym.has<Fortran::semantics::CommonBlockDetails>()) {
4598c22cb84SValentin Clement     mlir::emitError(loc, "COMMON symbol processed elsewhere");
4608c22cb84SValentin Clement   } else {
4618c22cb84SValentin Clement     TODO(loc, "global"); // Procedure pointer or something else
4628c22cb84SValentin Clement   }
4638c22cb84SValentin Clement   // Creates undefined initializer for globals without initializers
4648c22cb84SValentin Clement   if (!globalIsInitialized(global))
4658c22cb84SValentin Clement     createGlobalInitialization(
4668c22cb84SValentin Clement         builder, global, [&](fir::FirOpBuilder &builder) {
4678c22cb84SValentin Clement           builder.create<fir::HasValueOp>(
4688c22cb84SValentin Clement               loc, builder.create<fir::UndefOp>(loc, symTy));
4698c22cb84SValentin Clement         });
4708c22cb84SValentin Clement   // Set public visibility to prevent global definition to be optimized out
4718c22cb84SValentin Clement   // even if they have no initializer and are unused in this compilation unit.
4728c22cb84SValentin Clement   global.setVisibility(mlir::SymbolTable::Visibility::Public);
4738c22cb84SValentin Clement   return global;
4748c22cb84SValentin Clement }
4758c22cb84SValentin Clement 
4768c22cb84SValentin Clement /// Return linkage attribute for \p var.
4778c22cb84SValentin Clement static mlir::StringAttr
4788c22cb84SValentin Clement getLinkageAttribute(fir::FirOpBuilder &builder,
4798c22cb84SValentin Clement                     const Fortran::lower::pft::Variable &var) {
4808c22cb84SValentin Clement   if (var.isModuleVariable())
4818c22cb84SValentin Clement     return {}; // external linkage
4828c22cb84SValentin Clement   // Otherwise, the variable is owned by a procedure and must not be visible in
4838c22cb84SValentin Clement   // other compilation units.
4848c22cb84SValentin Clement   return builder.createInternalLinkage();
4858c22cb84SValentin Clement }
4868c22cb84SValentin Clement 
4878c22cb84SValentin Clement /// Instantiate a global variable. If it hasn't already been processed, add
4888c22cb84SValentin Clement /// the global to the ModuleOp as a new uniqued symbol and initialize it with
4898c22cb84SValentin Clement /// the correct value. It will be referenced on demand using `fir.addr_of`.
4908c22cb84SValentin Clement static void instantiateGlobal(Fortran::lower::AbstractConverter &converter,
4918c22cb84SValentin Clement                               const Fortran::lower::pft::Variable &var,
4928c22cb84SValentin Clement                               Fortran::lower::SymMap &symMap) {
4938c22cb84SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
4948c22cb84SValentin Clement   assert(!var.isAlias() && "must be handled in instantiateAlias");
4958c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
4968c22cb84SValentin Clement   std::string globalName = Fortran::lower::mangle::mangleName(sym);
4978c22cb84SValentin Clement   mlir::Location loc = converter.genLocation(sym.name());
4988c22cb84SValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(globalName);
4998c22cb84SValentin Clement   mlir::StringAttr linkage = getLinkageAttribute(builder, var);
5008c22cb84SValentin Clement   if (var.isModuleVariable()) {
5018c22cb84SValentin Clement     // A module global was or will be defined when lowering the module. Emit
5028c22cb84SValentin Clement     // only a declaration if the global does not exist at that point.
5038c22cb84SValentin Clement     global = declareGlobal(converter, var, globalName, linkage);
5048c22cb84SValentin Clement   } else {
5058c22cb84SValentin Clement     global = defineGlobal(converter, var, globalName, linkage);
5068c22cb84SValentin Clement   }
5078c22cb84SValentin Clement   auto addrOf = builder.create<fir::AddrOfOp>(loc, global.resultType(),
5088c22cb84SValentin Clement                                               global.getSymbol());
5098c22cb84SValentin Clement   Fortran::lower::StatementContext stmtCtx;
5108c22cb84SValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx, addrOf);
5118c22cb84SValentin Clement }
5128c22cb84SValentin Clement 
5132c2e5a5dSValentin Clement //===----------------------------------------------------------------===//
5142c2e5a5dSValentin Clement // Local variables instantiation (not for alias)
5152c2e5a5dSValentin Clement //===----------------------------------------------------------------===//
5162c2e5a5dSValentin Clement 
5172c2e5a5dSValentin Clement /// Create a stack slot for a local variable. Precondition: the insertion
5182c2e5a5dSValentin Clement /// point of the builder must be in the entry block, which is currently being
5192c2e5a5dSValentin Clement /// constructed.
5202c2e5a5dSValentin Clement static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
5212c2e5a5dSValentin Clement                                   mlir::Location loc,
5222c2e5a5dSValentin Clement                                   const Fortran::lower::pft::Variable &var,
5232c2e5a5dSValentin Clement                                   mlir::Value preAlloc,
5242c2e5a5dSValentin Clement                                   llvm::ArrayRef<mlir::Value> shape = {},
5252c2e5a5dSValentin Clement                                   llvm::ArrayRef<mlir::Value> lenParams = {}) {
5262c2e5a5dSValentin Clement   if (preAlloc)
5272c2e5a5dSValentin Clement     return preAlloc;
5282c2e5a5dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
5292c2e5a5dSValentin Clement   std::string nm = Fortran::lower::mangle::mangleName(var.getSymbol());
5302c2e5a5dSValentin Clement   mlir::Type ty = converter.genType(var);
5312c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &ultimateSymbol =
5322c2e5a5dSValentin Clement       var.getSymbol().GetUltimate();
5332c2e5a5dSValentin Clement   llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
5342c2e5a5dSValentin Clement   bool isTarg = var.isTarget();
5352c2e5a5dSValentin Clement   // Let the builder do all the heavy lifting.
5362c2e5a5dSValentin Clement   return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg);
5372c2e5a5dSValentin Clement }
5382c2e5a5dSValentin Clement 
5392c2e5a5dSValentin Clement /// Instantiate a local variable. Precondition: Each variable will be visited
5402c2e5a5dSValentin Clement /// such that if its properties depend on other variables, the variables upon
5412c2e5a5dSValentin Clement /// which its properties depend will already have been visited.
5422c2e5a5dSValentin Clement static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
5432c2e5a5dSValentin Clement                              const Fortran::lower::pft::Variable &var,
5442c2e5a5dSValentin Clement                              Fortran::lower::SymMap &symMap) {
5452c2e5a5dSValentin Clement   assert(!var.isAlias());
5462a59ead1SValentin Clement   Fortran::lower::StatementContext stmtCtx;
5472a59ead1SValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx);
5482a59ead1SValentin Clement }
5492a59ead1SValentin Clement 
5502a59ead1SValentin Clement /// Helper to decide if a dummy argument must be tracked in an BoxValue.
5512a59ead1SValentin Clement static bool lowerToBoxValue(const Fortran::semantics::Symbol &sym,
5522a59ead1SValentin Clement                             mlir::Value dummyArg) {
5532a59ead1SValentin Clement   // Only dummy arguments coming as fir.box can be tracked in an BoxValue.
5542a59ead1SValentin Clement   if (!dummyArg || !dummyArg.getType().isa<fir::BoxType>())
5552a59ead1SValentin Clement     return false;
5562a59ead1SValentin Clement   // Non contiguous arrays must be tracked in an BoxValue.
5572a59ead1SValentin Clement   if (sym.Rank() > 0 && !sym.attrs().test(Fortran::semantics::Attr::CONTIGUOUS))
5582a59ead1SValentin Clement     return true;
5592a59ead1SValentin Clement   // Assumed rank and optional fir.box cannot yet be read while lowering the
5602a59ead1SValentin Clement   // specifications.
5612a59ead1SValentin Clement   if (Fortran::evaluate::IsAssumedRank(sym) ||
5622a59ead1SValentin Clement       Fortran::semantics::IsOptional(sym))
5632a59ead1SValentin Clement     return true;
5642a59ead1SValentin Clement   // Polymorphic entity should be tracked through a fir.box that has the
5652a59ead1SValentin Clement   // dynamic type info.
5662a59ead1SValentin Clement   if (const Fortran::semantics::DeclTypeSpec *type = sym.GetType())
5672a59ead1SValentin Clement     if (type->IsPolymorphic())
5682a59ead1SValentin Clement       return true;
5692a59ead1SValentin Clement   return false;
5702a59ead1SValentin Clement }
5712a59ead1SValentin Clement 
5722a59ead1SValentin Clement /// Compute extent from lower and upper bound.
5732a59ead1SValentin Clement static mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc,
5742a59ead1SValentin Clement                                  mlir::Value lb, mlir::Value ub) {
5752a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
5762a59ead1SValentin Clement   // Let the folder deal with the common `ub - <const> + 1` case.
5772a59ead1SValentin Clement   auto diff = builder.create<mlir::arith::SubIOp>(loc, idxTy, ub, lb);
5782a59ead1SValentin Clement   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
5792a59ead1SValentin Clement   return builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one);
5802a59ead1SValentin Clement }
5812a59ead1SValentin Clement 
5822a59ead1SValentin Clement /// Lower explicit lower bounds into \p result. Does nothing if this is not an
5832a59ead1SValentin Clement /// array, or if the lower bounds are deferred, or all implicit or one.
5842a59ead1SValentin Clement static void lowerExplicitLowerBounds(
5852a59ead1SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
5862a59ead1SValentin Clement     const Fortran::lower::BoxAnalyzer &box,
5872a59ead1SValentin Clement     llvm::SmallVectorImpl<mlir::Value> &result, Fortran::lower::SymMap &symMap,
5882a59ead1SValentin Clement     Fortran::lower::StatementContext &stmtCtx) {
5892a59ead1SValentin Clement   if (!box.isArray() || box.lboundIsAllOnes())
5902a59ead1SValentin Clement     return;
5912a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
5922a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
5932a59ead1SValentin Clement   if (box.isStaticArray()) {
5942a59ead1SValentin Clement     for (int64_t lb : box.staticLBound())
5952a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, lb));
5962a59ead1SValentin Clement     return;
5972a59ead1SValentin Clement   }
5982a59ead1SValentin Clement   for (const Fortran::semantics::ShapeSpec *spec : box.dynamicBound()) {
5992a59ead1SValentin Clement     if (auto low = spec->lbound().GetExplicit()) {
6002a59ead1SValentin Clement       auto expr = Fortran::lower::SomeExpr{*low};
6012a59ead1SValentin Clement       mlir::Value lb = builder.createConvert(
6022a59ead1SValentin Clement           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
6032a59ead1SValentin Clement       result.emplace_back(lb);
6042a59ead1SValentin Clement     } else if (!spec->lbound().isColon()) {
6052a59ead1SValentin Clement       // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
6062a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, 1));
6072a59ead1SValentin Clement     }
6082a59ead1SValentin Clement   }
6092a59ead1SValentin Clement   assert(result.empty() || result.size() == box.dynamicBound().size());
6102a59ead1SValentin Clement }
6112a59ead1SValentin Clement 
6122a59ead1SValentin Clement /// Lower explicit extents into \p result if this is an explicit-shape or
6132a59ead1SValentin Clement /// assumed-size array. Does nothing if this is not an explicit-shape or
6142a59ead1SValentin Clement /// assumed-size array.
6152a59ead1SValentin Clement static void lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
6162a59ead1SValentin Clement                                  mlir::Location loc,
6172a59ead1SValentin Clement                                  const Fortran::lower::BoxAnalyzer &box,
6182a59ead1SValentin Clement                                  llvm::ArrayRef<mlir::Value> lowerBounds,
6192a59ead1SValentin Clement                                  llvm::SmallVectorImpl<mlir::Value> &result,
6202a59ead1SValentin Clement                                  Fortran::lower::SymMap &symMap,
6212a59ead1SValentin Clement                                  Fortran::lower::StatementContext &stmtCtx) {
6222a59ead1SValentin Clement   if (!box.isArray())
6232a59ead1SValentin Clement     return;
6242a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
6252a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
6262a59ead1SValentin Clement   if (box.isStaticArray()) {
6272a59ead1SValentin Clement     for (int64_t extent : box.staticShape())
6282a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, extent));
6292a59ead1SValentin Clement     return;
6302a59ead1SValentin Clement   }
6312a59ead1SValentin Clement   for (const auto &spec : llvm::enumerate(box.dynamicBound())) {
6322a59ead1SValentin Clement     if (auto up = spec.value()->ubound().GetExplicit()) {
6332a59ead1SValentin Clement       auto expr = Fortran::lower::SomeExpr{*up};
6342a59ead1SValentin Clement       mlir::Value ub = builder.createConvert(
6352a59ead1SValentin Clement           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
6362a59ead1SValentin Clement       if (lowerBounds.empty())
6372a59ead1SValentin Clement         result.emplace_back(ub);
6382a59ead1SValentin Clement       else
6392a59ead1SValentin Clement         result.emplace_back(
6402a59ead1SValentin Clement             computeExtent(builder, loc, lowerBounds[spec.index()], ub));
6412a59ead1SValentin Clement     } else if (spec.value()->ubound().isStar()) {
6422a59ead1SValentin Clement       // Assumed extent is undefined. Must be provided by user's code.
6432a59ead1SValentin Clement       result.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
6442a59ead1SValentin Clement     }
6452a59ead1SValentin Clement   }
6462a59ead1SValentin Clement   assert(result.empty() || result.size() == box.dynamicBound().size());
6472a59ead1SValentin Clement }
6482a59ead1SValentin Clement 
6492a59ead1SValentin Clement /// Treat negative values as undefined. Assumed size arrays will return -1 from
6502a59ead1SValentin Clement /// the front end for example. Using negative values can produce hard to find
6512a59ead1SValentin Clement /// bugs much further along in the compilation.
6522a59ead1SValentin Clement static mlir::Value genExtentValue(fir::FirOpBuilder &builder,
6532a59ead1SValentin Clement                                   mlir::Location loc, mlir::Type idxTy,
6542a59ead1SValentin Clement                                   long frontEndExtent) {
6552a59ead1SValentin Clement   if (frontEndExtent >= 0)
6562a59ead1SValentin Clement     return builder.createIntegerConstant(loc, idxTy, frontEndExtent);
6572a59ead1SValentin Clement   return builder.create<fir::UndefOp>(loc, idxTy);
6582a59ead1SValentin Clement }
6592a59ead1SValentin Clement 
6602a59ead1SValentin Clement /// Lower specification expressions and attributes of variable \p var and
6612a59ead1SValentin Clement /// add it to the symbol map.
6622a59ead1SValentin Clement /// For global and aliases, the address must be pre-computed and provided
6632a59ead1SValentin Clement /// in \p preAlloc.
6642a59ead1SValentin Clement /// Dummy arguments must have already been mapped to mlir block arguments
6652a59ead1SValentin Clement /// their mapping may be updated here.
6662a59ead1SValentin Clement void Fortran::lower::mapSymbolAttributes(
6672a59ead1SValentin Clement     AbstractConverter &converter, const Fortran::lower::pft::Variable &var,
6682a59ead1SValentin Clement     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
6692a59ead1SValentin Clement     mlir::Value preAlloc) {
6702a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
6712c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
6722a59ead1SValentin Clement   const mlir::Location loc = converter.genLocation(sym.name());
6732a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
674da7c77b8SValentin Clement   const bool isDummy = Fortran::semantics::IsDummy(sym);
675da7c77b8SValentin Clement   const bool isResult = Fortran::semantics::IsFunctionResult(sym);
6762a59ead1SValentin Clement   const bool replace = isDummy || isResult;
6772a59ead1SValentin Clement   fir::factory::CharacterExprHelper charHelp{builder, loc};
6782a59ead1SValentin Clement   Fortran::lower::BoxAnalyzer ba;
6792a59ead1SValentin Clement   ba.analyze(sym);
680da7c77b8SValentin Clement 
6812a59ead1SValentin Clement   // First deal with pointers an allocatables, because their handling here
6822a59ead1SValentin Clement   // is the same regardless of their rank.
6832a59ead1SValentin Clement   if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
6842a59ead1SValentin Clement     // Get address of fir.box describing the entity.
6852a59ead1SValentin Clement     // global
6862a59ead1SValentin Clement     mlir::Value boxAlloc = preAlloc;
6872a59ead1SValentin Clement     // dummy or passed result
6882a59ead1SValentin Clement     if (!boxAlloc)
6892a59ead1SValentin Clement       if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
6902a59ead1SValentin Clement         boxAlloc = symbox.getAddr();
6912a59ead1SValentin Clement     // local
6922a59ead1SValentin Clement     if (!boxAlloc)
6932a59ead1SValentin Clement       boxAlloc = createNewLocal(converter, loc, var, preAlloc);
6942a59ead1SValentin Clement     // Lower non deferred parameters.
6952a59ead1SValentin Clement     llvm::SmallVector<mlir::Value> nonDeferredLenParams;
6962a59ead1SValentin Clement     if (ba.isChar()) {
6972a59ead1SValentin Clement       TODO(loc, "mapSymbolAttributes allocatble or pointer char");
6982a59ead1SValentin Clement     } else if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) {
6992a59ead1SValentin Clement       if (const Fortran::semantics::DerivedTypeSpec *derived =
7002a59ead1SValentin Clement               declTy->AsDerived())
7012a59ead1SValentin Clement         if (Fortran::semantics::CountLenParameters(*derived) != 0)
7022a59ead1SValentin Clement           TODO(loc,
7032a59ead1SValentin Clement                "derived type allocatable or pointer with length parameters");
7042a59ead1SValentin Clement     }
7052a59ead1SValentin Clement     fir::MutableBoxValue box = Fortran::lower::createMutableBox(
7062a59ead1SValentin Clement         converter, loc, var, boxAlloc, nonDeferredLenParams);
7072a59ead1SValentin Clement     symMap.addAllocatableOrPointer(var.getSymbol(), box, replace);
7082a59ead1SValentin Clement     return;
7092a59ead1SValentin Clement   }
7102a59ead1SValentin Clement 
7112a59ead1SValentin Clement   if (isDummy) {
7122a59ead1SValentin Clement     mlir::Value dummyArg = symMap.lookupSymbol(sym).getAddr();
7132a59ead1SValentin Clement     if (lowerToBoxValue(sym, dummyArg)) {
7142a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> lbounds;
7152a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> extents;
7162a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> explicitParams;
7172a59ead1SValentin Clement       // Lower lower bounds, explicit type parameters and explicit
7182a59ead1SValentin Clement       // extents if any.
7192a59ead1SValentin Clement       if (ba.isChar())
7202a59ead1SValentin Clement         TODO(loc, "lowerToBoxValue character");
7212a59ead1SValentin Clement       // TODO: derived type length parameters.
7222a59ead1SValentin Clement       lowerExplicitLowerBounds(converter, loc, ba, lbounds, symMap, stmtCtx);
7232a59ead1SValentin Clement       lowerExplicitExtents(converter, loc, ba, lbounds, extents, symMap,
7242a59ead1SValentin Clement                            stmtCtx);
7252a59ead1SValentin Clement       symMap.addBoxSymbol(sym, dummyArg, lbounds, explicitParams, extents,
7262a59ead1SValentin Clement                           replace);
7272a59ead1SValentin Clement       return;
7282a59ead1SValentin Clement     }
7292a59ead1SValentin Clement   }
7302a59ead1SValentin Clement 
731*d88dfd2bSValentin Clement   // Helper to generate scalars for the symbol properties.
732*d88dfd2bSValentin Clement   auto genValue = [&](const Fortran::lower::SomeExpr &expr) {
733*d88dfd2bSValentin Clement     return genScalarValue(converter, loc, expr, symMap, stmtCtx);
734*d88dfd2bSValentin Clement   };
735*d88dfd2bSValentin Clement 
736*d88dfd2bSValentin Clement   // For symbols reaching this point, all properties are constant and can be
737*d88dfd2bSValentin Clement   // read/computed already into ssa values.
738*d88dfd2bSValentin Clement 
739*d88dfd2bSValentin Clement   // The origin must be \vec{1}.
740*d88dfd2bSValentin Clement   auto populateShape = [&](auto &shapes, const auto &bounds, mlir::Value box) {
741*d88dfd2bSValentin Clement     for (auto iter : llvm::enumerate(bounds)) {
742*d88dfd2bSValentin Clement       auto *spec = iter.value();
743*d88dfd2bSValentin Clement       assert(spec->lbound().GetExplicit() &&
744*d88dfd2bSValentin Clement              "lbound must be explicit with constant value 1");
745*d88dfd2bSValentin Clement       if (auto high = spec->ubound().GetExplicit()) {
746*d88dfd2bSValentin Clement         Fortran::lower::SomeExpr highEx{*high};
747*d88dfd2bSValentin Clement         mlir::Value ub = genValue(highEx);
748*d88dfd2bSValentin Clement         shapes.emplace_back(builder.createConvert(loc, idxTy, ub));
749*d88dfd2bSValentin Clement       } else if (spec->ubound().isColon()) {
750*d88dfd2bSValentin Clement         assert(box && "assumed bounds require a descriptor");
751*d88dfd2bSValentin Clement         mlir::Value dim =
752*d88dfd2bSValentin Clement             builder.createIntegerConstant(loc, idxTy, iter.index());
753*d88dfd2bSValentin Clement         auto dimInfo =
754*d88dfd2bSValentin Clement             builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
755*d88dfd2bSValentin Clement         shapes.emplace_back(dimInfo.getResult(1));
756*d88dfd2bSValentin Clement       } else if (spec->ubound().isStar()) {
757*d88dfd2bSValentin Clement         shapes.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
758*d88dfd2bSValentin Clement       } else {
759*d88dfd2bSValentin Clement         llvm::report_fatal_error("unknown bound category");
760*d88dfd2bSValentin Clement       }
761*d88dfd2bSValentin Clement     }
762*d88dfd2bSValentin Clement   };
763*d88dfd2bSValentin Clement 
764*d88dfd2bSValentin Clement   // The origin is not \vec{1}.
765*d88dfd2bSValentin Clement   auto populateLBoundsExtents = [&](auto &lbounds, auto &extents,
766*d88dfd2bSValentin Clement                                     const auto &bounds, mlir::Value box) {
767*d88dfd2bSValentin Clement     for (auto iter : llvm::enumerate(bounds)) {
768*d88dfd2bSValentin Clement       auto *spec = iter.value();
769*d88dfd2bSValentin Clement       fir::BoxDimsOp dimInfo;
770*d88dfd2bSValentin Clement       mlir::Value ub, lb;
771*d88dfd2bSValentin Clement       if (spec->lbound().isColon() || spec->ubound().isColon()) {
772*d88dfd2bSValentin Clement         // This is an assumed shape because allocatables and pointers extents
773*d88dfd2bSValentin Clement         // are not constant in the scope and are not read here.
774*d88dfd2bSValentin Clement         assert(box && "deferred bounds require a descriptor");
775*d88dfd2bSValentin Clement         mlir::Value dim =
776*d88dfd2bSValentin Clement             builder.createIntegerConstant(loc, idxTy, iter.index());
777*d88dfd2bSValentin Clement         dimInfo =
778*d88dfd2bSValentin Clement             builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
779*d88dfd2bSValentin Clement         extents.emplace_back(dimInfo.getResult(1));
780*d88dfd2bSValentin Clement         if (auto low = spec->lbound().GetExplicit()) {
781*d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*low};
782*d88dfd2bSValentin Clement           mlir::Value lb = builder.createConvert(loc, idxTy, genValue(expr));
783*d88dfd2bSValentin Clement           lbounds.emplace_back(lb);
784*d88dfd2bSValentin Clement         } else {
785*d88dfd2bSValentin Clement           // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
786*d88dfd2bSValentin Clement           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, 1));
787*d88dfd2bSValentin Clement         }
788*d88dfd2bSValentin Clement       } else {
789*d88dfd2bSValentin Clement         if (auto low = spec->lbound().GetExplicit()) {
790*d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*low};
791*d88dfd2bSValentin Clement           lb = builder.createConvert(loc, idxTy, genValue(expr));
792*d88dfd2bSValentin Clement         } else {
793*d88dfd2bSValentin Clement           TODO(loc, "assumed rank lowering");
794*d88dfd2bSValentin Clement         }
795*d88dfd2bSValentin Clement 
796*d88dfd2bSValentin Clement         if (auto high = spec->ubound().GetExplicit()) {
797*d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*high};
798*d88dfd2bSValentin Clement           ub = builder.createConvert(loc, idxTy, genValue(expr));
799*d88dfd2bSValentin Clement           lbounds.emplace_back(lb);
800*d88dfd2bSValentin Clement           extents.emplace_back(computeExtent(builder, loc, lb, ub));
801*d88dfd2bSValentin Clement         } else {
802*d88dfd2bSValentin Clement           // An assumed size array. The extent is not computed.
803*d88dfd2bSValentin Clement           assert(spec->ubound().isStar() && "expected assumed size");
804*d88dfd2bSValentin Clement           lbounds.emplace_back(lb);
805*d88dfd2bSValentin Clement           extents.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
806*d88dfd2bSValentin Clement         }
807*d88dfd2bSValentin Clement       }
808*d88dfd2bSValentin Clement     }
809*d88dfd2bSValentin Clement   };
810*d88dfd2bSValentin Clement 
8112a59ead1SValentin Clement   // For symbols reaching this point, all properties are constant and can be
8122a59ead1SValentin Clement   // read/computed already into ssa values.
8132a59ead1SValentin Clement 
8142a59ead1SValentin Clement   ba.match(
8152a59ead1SValentin Clement       //===--------------------------------------------------------------===//
8162a59ead1SValentin Clement       // Trivial case.
8172a59ead1SValentin Clement       //===--------------------------------------------------------------===//
8182a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarSym &) {
819da7c77b8SValentin Clement         if (isDummy) {
820da7c77b8SValentin Clement           // This is an argument.
821da7c77b8SValentin Clement           if (!symMap.lookupSymbol(sym))
822da7c77b8SValentin Clement             mlir::emitError(loc, "symbol \"")
823da7c77b8SValentin Clement                 << toStringRef(sym.name()) << "\" must already be in map";
824da7c77b8SValentin Clement           return;
825da7c77b8SValentin Clement         } else if (isResult) {
826da7c77b8SValentin Clement           // Some Fortran results may be passed by argument (e.g. derived
827da7c77b8SValentin Clement           // types)
828da7c77b8SValentin Clement           if (symMap.lookupSymbol(sym))
829da7c77b8SValentin Clement             return;
830da7c77b8SValentin Clement         }
831da7c77b8SValentin Clement         // Otherwise, it's a local variable or function result.
8322a59ead1SValentin Clement         mlir::Value local = createNewLocal(converter, loc, var, preAlloc);
8332c2e5a5dSValentin Clement         symMap.addSymbol(sym, local);
8342a59ead1SValentin Clement       },
8352a59ead1SValentin Clement 
8362a59ead1SValentin Clement       //===--------------------------------------------------------------===//
8372a59ead1SValentin Clement       // The non-trivial cases are when we have an argument or local that has
8382a59ead1SValentin Clement       // a repetition value. Arguments might be passed as simple pointers and
8392a59ead1SValentin Clement       // need to be cast to a multi-dimensional array with constant bounds
8402a59ead1SValentin Clement       // (possibly with a missing column), bounds computed in the callee
8412a59ead1SValentin Clement       // (here), or with bounds from the caller (boxed somewhere else). Locals
8422a59ead1SValentin Clement       // have the same properties except they are never boxed arguments from
8432a59ead1SValentin Clement       // the caller and never having a missing column size.
8442a59ead1SValentin Clement       //===--------------------------------------------------------------===//
8452a59ead1SValentin Clement 
8462a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarStaticChar &x) {
84737e84d9bSValentin Clement         // type is a CHARACTER, determine the LEN value
84837e84d9bSValentin Clement         auto charLen = x.charLen();
84937e84d9bSValentin Clement         if (replace) {
85037e84d9bSValentin Clement           Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym);
85137e84d9bSValentin Clement           std::pair<mlir::Value, mlir::Value> unboxchar =
85237e84d9bSValentin Clement               charHelp.createUnboxChar(symBox.getAddr());
85337e84d9bSValentin Clement           mlir::Value boxAddr = unboxchar.first;
85437e84d9bSValentin Clement           // Set/override LEN with a constant
85537e84d9bSValentin Clement           mlir::Value len = builder.createIntegerConstant(loc, idxTy, charLen);
85637e84d9bSValentin Clement           symMap.addCharSymbol(sym, boxAddr, len, true);
85737e84d9bSValentin Clement           return;
85837e84d9bSValentin Clement         }
85937e84d9bSValentin Clement         mlir::Value len = builder.createIntegerConstant(loc, idxTy, charLen);
86037e84d9bSValentin Clement         if (preAlloc) {
86137e84d9bSValentin Clement           symMap.addCharSymbol(sym, preAlloc, len);
86237e84d9bSValentin Clement           return;
86337e84d9bSValentin Clement         }
86437e84d9bSValentin Clement         mlir::Value local = createNewLocal(converter, loc, var, preAlloc);
86537e84d9bSValentin Clement         symMap.addCharSymbol(sym, local, len);
8662a59ead1SValentin Clement       },
8672a59ead1SValentin Clement 
8682a59ead1SValentin Clement       //===--------------------------------------------------------------===//
8692a59ead1SValentin Clement 
8702a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarDynamicChar &x) {
871f9704f0cSValentin Clement         TODO(loc, "ScalarDynamicChar variable lowering");
8722a59ead1SValentin Clement       },
8732a59ead1SValentin Clement 
8742a59ead1SValentin Clement       //===--------------------------------------------------------------===//
8752a59ead1SValentin Clement 
8762a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArray &x) {
8772a59ead1SValentin Clement         // object shape is constant, not a character
8782a59ead1SValentin Clement         mlir::Type castTy = builder.getRefType(converter.genType(var));
8792a59ead1SValentin Clement         mlir::Value addr = symMap.lookupSymbol(sym).getAddr();
8802a59ead1SValentin Clement         if (addr)
8812a59ead1SValentin Clement           addr = builder.createConvert(loc, castTy, addr);
8822a59ead1SValentin Clement         if (x.lboundAllOnes()) {
8832a59ead1SValentin Clement           // if lower bounds are all ones, build simple shaped object
8842a59ead1SValentin Clement           llvm::SmallVector<mlir::Value> shape;
8852a59ead1SValentin Clement           for (int64_t i : x.shapes)
8862a59ead1SValentin Clement             shape.push_back(genExtentValue(builder, loc, idxTy, i));
8872a59ead1SValentin Clement           mlir::Value local =
8882a59ead1SValentin Clement               isDummy ? addr : createNewLocal(converter, loc, var, preAlloc);
8892a59ead1SValentin Clement           symMap.addSymbolWithShape(sym, local, shape, isDummy);
8902a59ead1SValentin Clement           return;
8912a59ead1SValentin Clement         }
8922a59ead1SValentin Clement         // If object is an array process the lower bound and extent values by
8932a59ead1SValentin Clement         // constructing constants and populating the lbounds and extents.
8942a59ead1SValentin Clement         llvm::SmallVector<mlir::Value> extents;
8952a59ead1SValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
8962a59ead1SValentin Clement         for (auto [fst, snd] : llvm::zip(x.lbounds, x.shapes)) {
8972a59ead1SValentin Clement           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, fst));
8982a59ead1SValentin Clement           extents.emplace_back(genExtentValue(builder, loc, idxTy, snd));
8992a59ead1SValentin Clement         }
9002a59ead1SValentin Clement         mlir::Value local =
9012a59ead1SValentin Clement             isDummy ? addr
9022a59ead1SValentin Clement                     : createNewLocal(converter, loc, var, preAlloc, extents);
9032a59ead1SValentin Clement         assert(isDummy || Fortran::lower::isExplicitShape(sym));
9042a59ead1SValentin Clement         symMap.addSymbolWithBounds(sym, local, extents, lbounds, isDummy);
9052a59ead1SValentin Clement       },
9062a59ead1SValentin Clement 
9072a59ead1SValentin Clement       //===--------------------------------------------------------------===//
9082a59ead1SValentin Clement 
9092a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArray &x) {
910*d88dfd2bSValentin Clement         // cast to the known constant parts from the declaration
911*d88dfd2bSValentin Clement         mlir::Type varType = converter.genType(var);
912*d88dfd2bSValentin Clement         mlir::Value addr = symMap.lookupSymbol(sym).getAddr();
913*d88dfd2bSValentin Clement         mlir::Value argBox;
914*d88dfd2bSValentin Clement         mlir::Type castTy = builder.getRefType(varType);
915*d88dfd2bSValentin Clement         if (addr) {
916*d88dfd2bSValentin Clement           if (auto boxTy = addr.getType().dyn_cast<fir::BoxType>()) {
917*d88dfd2bSValentin Clement             argBox = addr;
918*d88dfd2bSValentin Clement             mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
919*d88dfd2bSValentin Clement             addr = builder.create<fir::BoxAddrOp>(loc, refTy, argBox);
920*d88dfd2bSValentin Clement           }
921*d88dfd2bSValentin Clement           addr = builder.createConvert(loc, castTy, addr);
922*d88dfd2bSValentin Clement         }
923*d88dfd2bSValentin Clement         if (x.lboundAllOnes()) {
924*d88dfd2bSValentin Clement           // if lower bounds are all ones, build simple shaped object
925*d88dfd2bSValentin Clement           llvm::SmallVector<mlir::Value> shapes;
926*d88dfd2bSValentin Clement           populateShape(shapes, x.bounds, argBox);
927*d88dfd2bSValentin Clement           if (isDummy) {
928*d88dfd2bSValentin Clement             symMap.addSymbolWithShape(sym, addr, shapes, true);
929*d88dfd2bSValentin Clement             return;
930*d88dfd2bSValentin Clement           }
931*d88dfd2bSValentin Clement           // local array with computed bounds
932*d88dfd2bSValentin Clement           assert(Fortran::lower::isExplicitShape(sym) ||
933*d88dfd2bSValentin Clement                  Fortran::semantics::IsAllocatableOrPointer(sym));
934*d88dfd2bSValentin Clement           mlir::Value local =
935*d88dfd2bSValentin Clement               createNewLocal(converter, loc, var, preAlloc, shapes);
936*d88dfd2bSValentin Clement           symMap.addSymbolWithShape(sym, local, shapes);
937*d88dfd2bSValentin Clement           return;
938*d88dfd2bSValentin Clement         }
939*d88dfd2bSValentin Clement         // if object is an array process the lower bound and extent values
940*d88dfd2bSValentin Clement         llvm::SmallVector<mlir::Value> extents;
941*d88dfd2bSValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
942*d88dfd2bSValentin Clement         populateLBoundsExtents(lbounds, extents, x.bounds, argBox);
943*d88dfd2bSValentin Clement         if (isDummy) {
944*d88dfd2bSValentin Clement           symMap.addSymbolWithBounds(sym, addr, extents, lbounds, true);
945*d88dfd2bSValentin Clement           return;
946*d88dfd2bSValentin Clement         }
947*d88dfd2bSValentin Clement         // local array with computed bounds
948*d88dfd2bSValentin Clement         assert(Fortran::lower::isExplicitShape(sym));
949*d88dfd2bSValentin Clement         mlir::Value local =
950*d88dfd2bSValentin Clement             createNewLocal(converter, loc, var, preAlloc, extents);
951*d88dfd2bSValentin Clement         symMap.addSymbolWithBounds(sym, local, extents, lbounds);
9522a59ead1SValentin Clement       },
9532a59ead1SValentin Clement 
9542a59ead1SValentin Clement       //===--------------------------------------------------------------===//
9552a59ead1SValentin Clement 
9562a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArrayStaticChar &x) {
957f9704f0cSValentin Clement         TODO(loc, "StaticArrayStaticChar variable lowering");
9582a59ead1SValentin Clement       },
9592a59ead1SValentin Clement 
9602a59ead1SValentin Clement       //===--------------------------------------------------------------===//
9612a59ead1SValentin Clement 
9622a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArrayDynamicChar &x) {
963f9704f0cSValentin Clement         TODO(loc, "StaticArrayDynamicChar variable lowering");
9642a59ead1SValentin Clement       },
9652a59ead1SValentin Clement 
9662a59ead1SValentin Clement       //===--------------------------------------------------------------===//
9672a59ead1SValentin Clement 
9682a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArrayStaticChar &x) {
969f9704f0cSValentin Clement         TODO(loc, "DynamicArrayStaticChar variable lowering");
9702a59ead1SValentin Clement       },
9712a59ead1SValentin Clement 
9722a59ead1SValentin Clement       //===--------------------------------------------------------------===//
9732a59ead1SValentin Clement 
9742a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArrayDynamicChar &x) {
975f9704f0cSValentin Clement         TODO(loc, "DynamicArrayDynamicChar variable lowering");
9762a59ead1SValentin Clement       },
9772a59ead1SValentin Clement 
9782a59ead1SValentin Clement       //===--------------------------------------------------------------===//
9792a59ead1SValentin Clement 
9802a59ead1SValentin Clement       [&](const Fortran::lower::BoxAnalyzer::None &) {
9812a59ead1SValentin Clement         mlir::emitError(loc, "symbol analysis failed on ")
9822a59ead1SValentin Clement             << toStringRef(sym.name());
9832a59ead1SValentin Clement       });
9842c2e5a5dSValentin Clement }
9852c2e5a5dSValentin Clement 
9862c2e5a5dSValentin Clement void Fortran::lower::instantiateVariable(AbstractConverter &converter,
9872c2e5a5dSValentin Clement                                          const pft::Variable &var,
9888c22cb84SValentin Clement                                          SymMap &symMap,
9898c22cb84SValentin Clement                                          AggregateStoreMap &storeMap) {
9902c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
9912c2e5a5dSValentin Clement   const mlir::Location loc = converter.genLocation(sym.name());
9922c2e5a5dSValentin Clement   if (var.isAggregateStore()) {
9932c2e5a5dSValentin Clement     TODO(loc, "instantiateVariable AggregateStore");
9942c2e5a5dSValentin Clement   } else if (Fortran::semantics::FindCommonBlockContaining(
9952c2e5a5dSValentin Clement                  var.getSymbol().GetUltimate())) {
9962c2e5a5dSValentin Clement     TODO(loc, "instantiateVariable Common");
9972c2e5a5dSValentin Clement   } else if (var.isAlias()) {
9982c2e5a5dSValentin Clement     TODO(loc, "instantiateVariable Alias");
9992c2e5a5dSValentin Clement   } else if (var.isGlobal()) {
10008c22cb84SValentin Clement     instantiateGlobal(converter, var, symMap);
10012c2e5a5dSValentin Clement   } else {
10022c2e5a5dSValentin Clement     instantiateLocal(converter, var, symMap);
10032c2e5a5dSValentin Clement   }
10042c2e5a5dSValentin Clement }
1005d0b70a07SValentin Clement 
1006d0b70a07SValentin Clement void Fortran::lower::mapCallInterfaceSymbols(
1007d0b70a07SValentin Clement     AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
1008d0b70a07SValentin Clement     SymMap &symMap) {
10098c22cb84SValentin Clement   Fortran::lower::AggregateStoreMap storeMap;
1010d0b70a07SValentin Clement   const Fortran::semantics::Symbol &result = caller.getResultSymbol();
1011d0b70a07SValentin Clement   for (Fortran::lower::pft::Variable var :
1012d0b70a07SValentin Clement        Fortran::lower::pft::buildFuncResultDependencyList(result)) {
1013d0b70a07SValentin Clement     if (var.isAggregateStore()) {
10148c22cb84SValentin Clement       instantiateVariable(converter, var, symMap, storeMap);
1015d0b70a07SValentin Clement     } else {
1016d0b70a07SValentin Clement       const Fortran::semantics::Symbol &sym = var.getSymbol();
1017d0b70a07SValentin Clement       const auto *hostDetails =
1018d0b70a07SValentin Clement           sym.detailsIf<Fortran::semantics::HostAssocDetails>();
1019d0b70a07SValentin Clement       if (hostDetails && !var.isModuleVariable()) {
1020d0b70a07SValentin Clement         // The callee is an internal procedure `A` whose result properties
1021d0b70a07SValentin Clement         // depend on host variables. The caller may be the host, or another
1022d0b70a07SValentin Clement         // internal procedure `B` contained in the same host.  In the first
1023d0b70a07SValentin Clement         // case, the host symbol is obviously mapped, in the second case, it
1024d0b70a07SValentin Clement         // must also be mapped because
1025d0b70a07SValentin Clement         // HostAssociations::internalProcedureBindings that was called when
1026d0b70a07SValentin Clement         // lowering `B` will have mapped all host symbols of captured variables
1027d0b70a07SValentin Clement         // to the tuple argument containing the composite of all host associated
1028d0b70a07SValentin Clement         // variables, whether or not the host symbol is actually referred to in
1029d0b70a07SValentin Clement         // `B`. Hence it is possible to simply lookup the variable associated to
1030d0b70a07SValentin Clement         // the host symbol without having to go back to the tuple argument.
1031d0b70a07SValentin Clement         Fortran::lower::SymbolBox hostValue =
1032d0b70a07SValentin Clement             symMap.lookupSymbol(hostDetails->symbol());
1033d0b70a07SValentin Clement         assert(hostValue && "callee host symbol must be mapped on caller side");
1034d0b70a07SValentin Clement         symMap.addSymbol(sym, hostValue.toExtendedValue());
1035d0b70a07SValentin Clement         // The SymbolBox associated to the host symbols is complete, skip
1036d0b70a07SValentin Clement         // instantiateVariable that would try to allocate a new storage.
1037d0b70a07SValentin Clement         continue;
1038d0b70a07SValentin Clement       }
1039d0b70a07SValentin Clement       if (Fortran::semantics::IsDummy(sym) && sym.owner() == result.owner()) {
1040d0b70a07SValentin Clement         // Get the argument for the dummy argument symbols of the current call.
1041d0b70a07SValentin Clement         symMap.addSymbol(sym, caller.getArgumentValue(sym));
1042d0b70a07SValentin Clement         // All the properties of the dummy variable may not come from the actual
1043d0b70a07SValentin Clement         // argument, let instantiateVariable handle this.
1044d0b70a07SValentin Clement       }
1045d0b70a07SValentin Clement       // If this is neither a host associated or dummy symbol, it must be a
1046d0b70a07SValentin Clement       // module or common block variable to satisfy specification expression
1047d0b70a07SValentin Clement       // requirements in 10.1.11, instantiateVariable will get its address and
1048d0b70a07SValentin Clement       // properties.
10498c22cb84SValentin Clement       instantiateVariable(converter, var, symMap, storeMap);
1050d0b70a07SValentin Clement     }
1051d0b70a07SValentin Clement   }
1052d0b70a07SValentin Clement }
1053