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"
19a1425019SValentin Clement #include "flang/Lower/IntrinsicCall.h"
202c2e5a5dSValentin Clement #include "flang/Lower/Mangler.h"
212c2e5a5dSValentin Clement #include "flang/Lower/PFTBuilder.h"
222a59ead1SValentin Clement #include "flang/Lower/StatementContext.h"
232c2e5a5dSValentin Clement #include "flang/Lower/Support/Utils.h"
242c2e5a5dSValentin Clement #include "flang/Lower/SymbolMap.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"
285b66cc10SValentin Clement #include "flang/Optimizer/Builder/Todo.h"
292c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
302c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIRDialect.h"
312c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
322c2e5a5dSValentin Clement #include "flang/Optimizer/Support/FIRContext.h"
332c2e5a5dSValentin Clement #include "flang/Optimizer/Support/FatalError.h"
34a1425019SValentin Clement #include "flang/Semantics/runtime-type-info.h"
352c2e5a5dSValentin Clement #include "flang/Semantics/tools.h"
362c2e5a5dSValentin Clement #include "llvm/Support/Debug.h"
372c2e5a5dSValentin Clement 
382c2e5a5dSValentin Clement #define DEBUG_TYPE "flang-lower-variable"
392c2e5a5dSValentin Clement 
402a59ead1SValentin Clement /// Helper to lower a scalar expression using a specific symbol mapping.
genScalarValue(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::lower::SomeExpr & expr,Fortran::lower::SymMap & symMap,Fortran::lower::StatementContext & context)412a59ead1SValentin Clement static mlir::Value genScalarValue(Fortran::lower::AbstractConverter &converter,
422a59ead1SValentin Clement                                   mlir::Location loc,
432a59ead1SValentin Clement                                   const Fortran::lower::SomeExpr &expr,
442a59ead1SValentin Clement                                   Fortran::lower::SymMap &symMap,
452a59ead1SValentin Clement                                   Fortran::lower::StatementContext &context) {
462a59ead1SValentin Clement   // This does not use the AbstractConverter member function to override the
472a59ead1SValentin Clement   // symbol mapping to be used expression lowering.
482a59ead1SValentin Clement   return fir::getBase(Fortran::lower::createSomeExtendedExpression(
492a59ead1SValentin Clement       loc, converter, expr, symMap, context));
502a59ead1SValentin Clement }
518c22cb84SValentin Clement /// Does this variable have a default initialization?
hasDefaultInitialization(const Fortran::semantics::Symbol & sym)528c22cb84SValentin Clement static bool hasDefaultInitialization(const Fortran::semantics::Symbol &sym) {
538c22cb84SValentin Clement   if (sym.has<Fortran::semantics::ObjectEntityDetails>() && sym.size())
548c22cb84SValentin Clement     if (!Fortran::semantics::IsAllocatableOrPointer(sym))
558c22cb84SValentin Clement       if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
568c22cb84SValentin Clement         if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
578c22cb84SValentin Clement                 declTypeSpec->AsDerived())
588c22cb84SValentin Clement           return derivedTypeSpec->HasDefaultInitialization();
598c22cb84SValentin Clement   return false;
608c22cb84SValentin Clement }
618c22cb84SValentin Clement 
628c22cb84SValentin Clement //===----------------------------------------------------------------===//
638c22cb84SValentin Clement // Global variables instantiation (not for alias and common)
648c22cb84SValentin Clement //===----------------------------------------------------------------===//
658c22cb84SValentin Clement 
668c22cb84SValentin Clement /// Helper to generate expression value inside global initializer.
678c22cb84SValentin Clement static fir::ExtendedValue
genInitializerExprValue(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::lower::SomeExpr & expr,Fortran::lower::StatementContext & stmtCtx)688c22cb84SValentin Clement genInitializerExprValue(Fortran::lower::AbstractConverter &converter,
698c22cb84SValentin Clement                         mlir::Location loc,
708c22cb84SValentin Clement                         const Fortran::lower::SomeExpr &expr,
718c22cb84SValentin Clement                         Fortran::lower::StatementContext &stmtCtx) {
728c22cb84SValentin Clement   // Data initializer are constant value and should not depend on other symbols
738c22cb84SValentin Clement   // given the front-end fold parameter references. In any case, the "current"
748c22cb84SValentin Clement   // map of the converter should not be used since it holds mapping to
758c22cb84SValentin Clement   // mlir::Value from another mlir region. If these value are used by accident
768c22cb84SValentin Clement   // in the initializer, this will lead to segfaults in mlir code.
778c22cb84SValentin Clement   Fortran::lower::SymMap emptyMap;
788c22cb84SValentin Clement   return Fortran::lower::createSomeInitializerExpression(loc, converter, expr,
798c22cb84SValentin Clement                                                          emptyMap, stmtCtx);
808c22cb84SValentin Clement }
818c22cb84SValentin Clement 
828c22cb84SValentin Clement /// Can this symbol constant be placed in read-only memory?
isConstant(const Fortran::semantics::Symbol & sym)838c22cb84SValentin Clement static bool isConstant(const Fortran::semantics::Symbol &sym) {
848c22cb84SValentin Clement   return sym.attrs().test(Fortran::semantics::Attr::PARAMETER) ||
858c22cb84SValentin Clement          sym.test(Fortran::semantics::Symbol::Flag::ReadOnly);
868c22cb84SValentin Clement }
878c22cb84SValentin Clement 
88a1425019SValentin Clement /// Is this a compiler generated symbol to describe derived types ?
isRuntimeTypeInfoData(const Fortran::semantics::Symbol & sym)89a1425019SValentin Clement static bool isRuntimeTypeInfoData(const Fortran::semantics::Symbol &sym) {
90a1425019SValentin Clement   // So far, use flags to detect if this symbol were generated during
91a1425019SValentin Clement   // semantics::BuildRuntimeDerivedTypeTables(). Scope cannot be used since the
92a1425019SValentin Clement   // symbols are injected in the user scopes defining the described derived
93a1425019SValentin Clement   // types. A robustness improvement for this test could be to get hands on the
94a1425019SValentin Clement   // semantics::RuntimeDerivedTypeTables and to check if the symbol names
95a1425019SValentin Clement   // belongs to this structure.
96a1425019SValentin Clement   return sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated) &&
97a1425019SValentin Clement          sym.test(Fortran::semantics::Symbol::Flag::ReadOnly);
98a1425019SValentin Clement }
99a1425019SValentin Clement 
100a1425019SValentin Clement static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
101a1425019SValentin Clement                                   const Fortran::lower::pft::Variable &var,
102a1425019SValentin Clement                                   llvm::StringRef globalName,
103a1425019SValentin Clement                                   mlir::StringAttr linkage);
104a1425019SValentin Clement 
genLocation(Fortran::lower::AbstractConverter & converter,const Fortran::semantics::Symbol & sym)105*53804e42SValentin Clement static mlir::Location genLocation(Fortran::lower::AbstractConverter &converter,
106*53804e42SValentin Clement                                   const Fortran::semantics::Symbol &sym) {
107*53804e42SValentin Clement   // Compiler generated name cannot be used as source location, their name
108*53804e42SValentin Clement   // is not pointing to the source files.
109*53804e42SValentin Clement   if (!sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated))
110*53804e42SValentin Clement     return converter.genLocation(sym.name());
111*53804e42SValentin Clement   return converter.getCurrentLocation();
112*53804e42SValentin Clement }
113*53804e42SValentin Clement 
1148c22cb84SValentin Clement /// Create the global op declaration without any initializer
declareGlobal(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var,llvm::StringRef globalName,mlir::StringAttr linkage)1158c22cb84SValentin Clement static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
1168c22cb84SValentin Clement                                    const Fortran::lower::pft::Variable &var,
1178c22cb84SValentin Clement                                    llvm::StringRef globalName,
1188c22cb84SValentin Clement                                    mlir::StringAttr linkage) {
1198c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1208c22cb84SValentin Clement   if (fir::GlobalOp global = builder.getNamedGlobal(globalName))
1218c22cb84SValentin Clement     return global;
122a1425019SValentin Clement   // Always define linkonce data since it may be optimized out from the module
123a1425019SValentin Clement   // that actually owns the variable if it does not refers to it.
124a1425019SValentin Clement   if (linkage == builder.createLinkOnceODRLinkage() ||
125a1425019SValentin Clement       linkage == builder.createLinkOnceLinkage())
126a1425019SValentin Clement     return defineGlobal(converter, var, globalName, linkage);
1278c22cb84SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
128*53804e42SValentin Clement   mlir::Location loc = genLocation(converter, sym);
1298c22cb84SValentin Clement   // Resolve potential host and module association before checking that this
1308c22cb84SValentin Clement   // symbol is an object of a function pointer.
1318c22cb84SValentin Clement   const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
1328c22cb84SValentin Clement   if (!ultimate.has<Fortran::semantics::ObjectEntityDetails>() &&
1331e1f60c6SV Donaldson       !Fortran::semantics::IsProcedurePointer(ultimate))
13439377d52SValentin Clement     mlir::emitError(loc, "processing global declaration: symbol '")
1358c22cb84SValentin Clement         << toStringRef(sym.name()) << "' has unexpected details\n";
1368c22cb84SValentin Clement   return builder.createGlobal(loc, converter.genType(var), globalName, linkage,
1378c22cb84SValentin Clement                               mlir::Attribute{}, isConstant(ultimate));
1388c22cb84SValentin Clement }
1398c22cb84SValentin Clement 
1408c22cb84SValentin Clement /// Temporary helper to catch todos in initial data target lowering.
1418c22cb84SValentin Clement static bool
hasDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol & sym)1428c22cb84SValentin Clement hasDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol &sym) {
1438c22cb84SValentin Clement   if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
1448c22cb84SValentin Clement     if (const Fortran::semantics::DerivedTypeSpec *derived =
1458c22cb84SValentin Clement             declTy->AsDerived())
1468c22cb84SValentin Clement       return Fortran::semantics::CountLenParameters(*derived) > 0;
1478c22cb84SValentin Clement   return false;
1488c22cb84SValentin Clement }
1498c22cb84SValentin Clement 
unwrapElementType(mlir::Type type)1508c22cb84SValentin Clement static mlir::Type unwrapElementType(mlir::Type type) {
1518c22cb84SValentin Clement   if (mlir::Type ty = fir::dyn_cast_ptrOrBoxEleTy(type))
1528c22cb84SValentin Clement     type = ty;
1538c22cb84SValentin Clement   if (auto seqType = type.dyn_cast<fir::SequenceType>())
1548c22cb84SValentin Clement     type = seqType.getEleTy();
1558c22cb84SValentin Clement   return type;
1568c22cb84SValentin Clement }
1578c22cb84SValentin Clement 
genExtAddrInInitializer(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::lower::SomeExpr & addr)15872276bdaSValentin Clement fir::ExtendedValue Fortran::lower::genExtAddrInInitializer(
15972276bdaSValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
16072276bdaSValentin Clement     const Fortran::lower::SomeExpr &addr) {
16172276bdaSValentin Clement   Fortran::lower::SymMap globalOpSymMap;
16272276bdaSValentin Clement   Fortran::lower::AggregateStoreMap storeMap;
16372276bdaSValentin Clement   Fortran::lower::StatementContext stmtCtx;
16472276bdaSValentin Clement   if (const Fortran::semantics::Symbol *sym =
16572276bdaSValentin Clement           Fortran::evaluate::GetFirstSymbol(addr)) {
16672276bdaSValentin Clement     // Length parameters processing will need care in global initializer
16772276bdaSValentin Clement     // context.
16872276bdaSValentin Clement     if (hasDerivedTypeWithLengthParameters(*sym))
16972276bdaSValentin Clement       TODO(loc, "initial-data-target with derived type length parameters");
17072276bdaSValentin Clement 
17172276bdaSValentin Clement     auto var = Fortran::lower::pft::Variable(*sym, /*global=*/true);
17272276bdaSValentin Clement     Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
17372276bdaSValentin Clement                                         storeMap);
17472276bdaSValentin Clement   }
17572276bdaSValentin Clement   return Fortran::lower::createInitializerAddress(loc, converter, addr,
17672276bdaSValentin Clement                                                   globalOpSymMap, stmtCtx);
17772276bdaSValentin Clement }
17872276bdaSValentin Clement 
1798c22cb84SValentin Clement /// create initial-data-target fir.box in a global initializer region.
genInitialDataTarget(Fortran::lower::AbstractConverter & converter,mlir::Location loc,mlir::Type boxType,const Fortran::lower::SomeExpr & initialTarget)1808c22cb84SValentin Clement mlir::Value Fortran::lower::genInitialDataTarget(
1818c22cb84SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
1828c22cb84SValentin Clement     mlir::Type boxType, const Fortran::lower::SomeExpr &initialTarget) {
1838c22cb84SValentin Clement   Fortran::lower::SymMap globalOpSymMap;
1848c22cb84SValentin Clement   Fortran::lower::AggregateStoreMap storeMap;
1858c22cb84SValentin Clement   Fortran::lower::StatementContext stmtCtx;
1868c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1878c22cb84SValentin Clement   if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
1888c22cb84SValentin Clement           initialTarget))
1898c22cb84SValentin Clement     return fir::factory::createUnallocatedBox(builder, loc, boxType,
1908c22cb84SValentin Clement                                               /*nonDeferredParams=*/llvm::None);
1918c22cb84SValentin Clement   // Pointer initial data target, and NULL(mold).
1928c22cb84SValentin Clement   if (const Fortran::semantics::Symbol *sym =
1938c22cb84SValentin Clement           Fortran::evaluate::GetFirstSymbol(initialTarget)) {
1948c22cb84SValentin Clement     // Length parameters processing will need care in global initializer
1958c22cb84SValentin Clement     // context.
1968c22cb84SValentin Clement     if (hasDerivedTypeWithLengthParameters(*sym))
1978c22cb84SValentin Clement       TODO(loc, "initial-data-target with derived type length parameters");
1988c22cb84SValentin Clement 
1998c22cb84SValentin Clement     auto var = Fortran::lower::pft::Variable(*sym, /*global=*/true);
2008c22cb84SValentin Clement     Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
2018c22cb84SValentin Clement                                         storeMap);
2028c22cb84SValentin Clement   }
2038c22cb84SValentin Clement   mlir::Value box;
2048c22cb84SValentin Clement   if (initialTarget.Rank() > 0) {
2058c22cb84SValentin Clement     box = fir::getBase(Fortran::lower::createSomeArrayBox(
2068c22cb84SValentin Clement         converter, initialTarget, globalOpSymMap, stmtCtx));
2078c22cb84SValentin Clement   } else {
2088c22cb84SValentin Clement     fir::ExtendedValue addr = Fortran::lower::createInitializerAddress(
2098c22cb84SValentin Clement         loc, converter, initialTarget, globalOpSymMap, stmtCtx);
2108c22cb84SValentin Clement     box = builder.createBox(loc, addr);
2118c22cb84SValentin Clement   }
2128c22cb84SValentin Clement   // box is a fir.box<T>, not a fir.box<fir.ptr<T>> as it should to be used
2138c22cb84SValentin Clement   // for pointers. A fir.convert should not be used here, because it would
2148c22cb84SValentin Clement   // not actually set the pointer attribute in the descriptor.
2158c22cb84SValentin Clement   // In a normal context, fir.rebox would be used to set the pointer attribute
2168c22cb84SValentin Clement   // while copying the projection from another fir.box. But fir.rebox cannot be
2178c22cb84SValentin Clement   // used in initializer because its current codegen expects that the input
2188c22cb84SValentin Clement   // fir.box is in memory, which is not the case in initializers.
2198c22cb84SValentin Clement   // So, just replace the fir.embox that created addr with one with
2208c22cb84SValentin Clement   // fir.box<fir.ptr<T>> result type.
2218c22cb84SValentin Clement   // Note that the descriptor cannot have been created with fir.rebox because
2228c22cb84SValentin Clement   // the initial-data-target cannot be a fir.box itself (it cannot be
2238c22cb84SValentin Clement   // assumed-shape, deferred-shape, or polymorphic as per C765). However the
2248c22cb84SValentin Clement   // case where the initial data target is a derived type with length parameters
2258c22cb84SValentin Clement   // will most likely be a bit trickier, hence the TODO above.
2268c22cb84SValentin Clement 
2278c22cb84SValentin Clement   mlir::Operation *op = box.getDefiningOp();
2288c22cb84SValentin Clement   if (!op || !mlir::isa<fir::EmboxOp>(*op))
2298c22cb84SValentin Clement     fir::emitFatalError(
2308c22cb84SValentin Clement         loc, "fir.box must be created with embox in global initializers");
2318c22cb84SValentin Clement   mlir::Type targetEleTy = unwrapElementType(box.getType());
2328c22cb84SValentin Clement   if (!fir::isa_char(targetEleTy))
2338c22cb84SValentin Clement     return builder.create<fir::EmboxOp>(loc, boxType, op->getOperands(),
2348c22cb84SValentin Clement                                         op->getAttrs());
2358c22cb84SValentin Clement 
2368c22cb84SValentin Clement   // Handle the character case length particularities: embox takes a length
2378c22cb84SValentin Clement   // value argument when the result type has unknown length, but not when the
2388c22cb84SValentin Clement   // result type has constant length. The type of the initial target must be
2398c22cb84SValentin Clement   // constant length, but the one of the pointer may not be. In this case, a
2408c22cb84SValentin Clement   // length operand must be added.
2418c22cb84SValentin Clement   auto targetLen = targetEleTy.cast<fir::CharacterType>().getLen();
2428c22cb84SValentin Clement   auto ptrLen = unwrapElementType(boxType).cast<fir::CharacterType>().getLen();
2438c22cb84SValentin Clement   if (ptrLen == targetLen)
2448c22cb84SValentin Clement     // Nothing to do
2458c22cb84SValentin Clement     return builder.create<fir::EmboxOp>(loc, boxType, op->getOperands(),
2468c22cb84SValentin Clement                                         op->getAttrs());
2478c22cb84SValentin Clement   auto embox = mlir::cast<fir::EmboxOp>(*op);
2488c22cb84SValentin Clement   auto ptrType = boxType.cast<fir::BoxType>().getEleTy();
2498c22cb84SValentin Clement   mlir::Value memref = builder.createConvert(loc, ptrType, embox.getMemref());
2508c22cb84SValentin Clement   if (targetLen == fir::CharacterType::unknownLen())
2518c22cb84SValentin Clement     // Drop the length argument.
2528c22cb84SValentin Clement     return builder.create<fir::EmboxOp>(loc, boxType, memref, embox.getShape(),
2538c22cb84SValentin Clement                                         embox.getSlice());
2548c22cb84SValentin Clement   // targetLen is constant and ptrLen is unknown. Add a length argument.
2558c22cb84SValentin Clement   mlir::Value targetLenValue =
2568c22cb84SValentin Clement       builder.createIntegerConstant(loc, builder.getIndexType(), targetLen);
2578c22cb84SValentin Clement   return builder.create<fir::EmboxOp>(loc, boxType, memref, embox.getShape(),
2588c22cb84SValentin Clement                                       embox.getSlice(),
2598c22cb84SValentin Clement                                       mlir::ValueRange{targetLenValue});
2608c22cb84SValentin Clement }
2618c22cb84SValentin Clement 
genDefaultInitializerValue(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::semantics::Symbol & sym,mlir::Type symTy,Fortran::lower::StatementContext & stmtCtx)2628c22cb84SValentin Clement static mlir::Value genDefaultInitializerValue(
2638c22cb84SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
2648c22cb84SValentin Clement     const Fortran::semantics::Symbol &sym, mlir::Type symTy,
2658c22cb84SValentin Clement     Fortran::lower::StatementContext &stmtCtx) {
2668c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
2678c22cb84SValentin Clement   mlir::Type scalarType = symTy;
2688c22cb84SValentin Clement   fir::SequenceType sequenceType;
2698c22cb84SValentin Clement   if (auto ty = symTy.dyn_cast<fir::SequenceType>()) {
2708c22cb84SValentin Clement     sequenceType = ty;
2718c22cb84SValentin Clement     scalarType = ty.getEleTy();
2728c22cb84SValentin Clement   }
2738c22cb84SValentin Clement   // Build a scalar default value of the symbol type, looping through the
2748c22cb84SValentin Clement   // components to build each component initial value.
2758c22cb84SValentin Clement   auto recTy = scalarType.cast<fir::RecordType>();
2768c22cb84SValentin Clement   auto fieldTy = fir::FieldType::get(scalarType.getContext());
2778c22cb84SValentin Clement   mlir::Value initialValue = builder.create<fir::UndefOp>(loc, scalarType);
2788c22cb84SValentin Clement   const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
2798c22cb84SValentin Clement   assert(declTy && "var with default initialization must have a type");
2808c22cb84SValentin Clement   Fortran::semantics::OrderedComponentIterator components(
2818c22cb84SValentin Clement       declTy->derivedTypeSpec());
2828c22cb84SValentin Clement   for (const auto &component : components) {
2838c22cb84SValentin Clement     // Skip parent components, the sub-components of parent types are part of
2848c22cb84SValentin Clement     // components and will be looped through right after.
2858c22cb84SValentin Clement     if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
2868c22cb84SValentin Clement       continue;
2878c22cb84SValentin Clement     mlir::Value componentValue;
2888c22cb84SValentin Clement     llvm::StringRef name = toStringRef(component.name());
2898c22cb84SValentin Clement     mlir::Type componentTy = recTy.getType(name);
2908c22cb84SValentin Clement     assert(componentTy && "component not found in type");
2918c22cb84SValentin Clement     if (const auto *object{
2928c22cb84SValentin Clement             component.detailsIf<Fortran::semantics::ObjectEntityDetails>()}) {
2938c22cb84SValentin Clement       if (const auto &init = object->init()) {
2948c22cb84SValentin Clement         // Component has explicit initialization.
2958c22cb84SValentin Clement         if (Fortran::semantics::IsPointer(component))
2968c22cb84SValentin Clement           // Initial data target.
2978c22cb84SValentin Clement           componentValue =
2988c22cb84SValentin Clement               genInitialDataTarget(converter, loc, componentTy, *init);
2998c22cb84SValentin Clement         else
3008c22cb84SValentin Clement           // Initial value.
3018c22cb84SValentin Clement           componentValue = fir::getBase(
3028c22cb84SValentin Clement               genInitializerExprValue(converter, loc, *init, stmtCtx));
3038c22cb84SValentin Clement       } else if (Fortran::semantics::IsAllocatableOrPointer(component)) {
3048c22cb84SValentin Clement         // Pointer or allocatable without initialization.
3058c22cb84SValentin Clement         // Create deallocated/disassociated value.
3068c22cb84SValentin Clement         // From a standard point of view, pointer without initialization do not
3078c22cb84SValentin Clement         // need to be disassociated, but for sanity and simplicity, do it in
3088c22cb84SValentin Clement         // global constructor since this has no runtime cost.
3098c22cb84SValentin Clement         componentValue = fir::factory::createUnallocatedBox(
3108c22cb84SValentin Clement             builder, loc, componentTy, llvm::None);
3118c22cb84SValentin Clement       } else if (hasDefaultInitialization(component)) {
3128c22cb84SValentin Clement         // Component type has default initialization.
3138c22cb84SValentin Clement         componentValue = genDefaultInitializerValue(converter, loc, component,
3148c22cb84SValentin Clement                                                     componentTy, stmtCtx);
3158c22cb84SValentin Clement       } else {
3168c22cb84SValentin Clement         // Component has no initial value.
3178c22cb84SValentin Clement         componentValue = builder.create<fir::UndefOp>(loc, componentTy);
3188c22cb84SValentin Clement       }
3198c22cb84SValentin Clement     } else if (const auto *proc{
3208c22cb84SValentin Clement                    component
3218c22cb84SValentin Clement                        .detailsIf<Fortran::semantics::ProcEntityDetails>()}) {
3228c22cb84SValentin Clement       if (proc->init().has_value())
3238c22cb84SValentin Clement         TODO(loc, "procedure pointer component default initialization");
3248c22cb84SValentin Clement       else
3258c22cb84SValentin Clement         componentValue = builder.create<fir::UndefOp>(loc, componentTy);
3268c22cb84SValentin Clement     }
3278c22cb84SValentin Clement     assert(componentValue && "must have been computed");
3288c22cb84SValentin Clement     componentValue = builder.createConvert(loc, componentTy, componentValue);
3298c22cb84SValentin Clement     // FIXME: type parameters must come from the derived-type-spec
3308c22cb84SValentin Clement     auto field = builder.create<fir::FieldIndexOp>(
3318c22cb84SValentin Clement         loc, fieldTy, name, scalarType,
3328c22cb84SValentin Clement         /*typeParams=*/mlir::ValueRange{} /*TODO*/);
3338c22cb84SValentin Clement     initialValue = builder.create<fir::InsertValueOp>(
3348c22cb84SValentin Clement         loc, recTy, initialValue, componentValue,
3358c22cb84SValentin Clement         builder.getArrayAttr(field.getAttributes()));
3368c22cb84SValentin Clement   }
3378c22cb84SValentin Clement 
3388c22cb84SValentin Clement   if (sequenceType) {
3398c22cb84SValentin Clement     // For arrays, duplicate the scalar value to all elements with an
3408c22cb84SValentin Clement     // fir.insert_range covering the whole array.
3418c22cb84SValentin Clement     auto arrayInitialValue = builder.create<fir::UndefOp>(loc, sequenceType);
3428c22cb84SValentin Clement     llvm::SmallVector<int64_t> rangeBounds;
3438c22cb84SValentin Clement     for (int64_t extent : sequenceType.getShape()) {
3448c22cb84SValentin Clement       if (extent == fir::SequenceType::getUnknownExtent())
3458c22cb84SValentin Clement         TODO(loc,
3468c22cb84SValentin Clement              "default initial value of array component with length parameters");
3478c22cb84SValentin Clement       rangeBounds.push_back(0);
3488c22cb84SValentin Clement       rangeBounds.push_back(extent - 1);
3498c22cb84SValentin Clement     }
3508c22cb84SValentin Clement     return builder.create<fir::InsertOnRangeOp>(
3518c22cb84SValentin Clement         loc, sequenceType, arrayInitialValue, initialValue,
3528c22cb84SValentin Clement         builder.getIndexVectorAttr(rangeBounds));
3538c22cb84SValentin Clement   }
3548c22cb84SValentin Clement   return initialValue;
3558c22cb84SValentin Clement }
3568c22cb84SValentin Clement 
3578c22cb84SValentin Clement /// Does this global already have an initializer ?
globalIsInitialized(fir::GlobalOp global)3588c22cb84SValentin Clement static bool globalIsInitialized(fir::GlobalOp global) {
3598c22cb84SValentin Clement   return !global.getRegion().empty() || global.getInitVal();
3608c22cb84SValentin Clement }
3618c22cb84SValentin Clement 
3628c22cb84SValentin Clement /// Call \p genInit to generate code inside \p global initializer region.
3638c22cb84SValentin Clement static void
createGlobalInitialization(fir::FirOpBuilder & builder,fir::GlobalOp global,std::function<void (fir::FirOpBuilder &)> genInit)3648c22cb84SValentin Clement createGlobalInitialization(fir::FirOpBuilder &builder, fir::GlobalOp global,
3658c22cb84SValentin Clement                            std::function<void(fir::FirOpBuilder &)> genInit) {
3668c22cb84SValentin Clement   mlir::Region &region = global.getRegion();
3678c22cb84SValentin Clement   region.push_back(new mlir::Block);
3688c22cb84SValentin Clement   mlir::Block &block = region.back();
3698c22cb84SValentin Clement   auto insertPt = builder.saveInsertionPoint();
3708c22cb84SValentin Clement   builder.setInsertionPointToStart(&block);
3718c22cb84SValentin Clement   genInit(builder);
3728c22cb84SValentin Clement   builder.restoreInsertionPoint(insertPt);
3738c22cb84SValentin Clement }
3748c22cb84SValentin Clement 
3758c22cb84SValentin Clement /// Create the global op and its init if it has one
defineGlobal(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var,llvm::StringRef globalName,mlir::StringAttr linkage)3768c22cb84SValentin Clement static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
3778c22cb84SValentin Clement                                   const Fortran::lower::pft::Variable &var,
3788c22cb84SValentin Clement                                   llvm::StringRef globalName,
3798c22cb84SValentin Clement                                   mlir::StringAttr linkage) {
3808c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
3818c22cb84SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
382*53804e42SValentin Clement   mlir::Location loc = genLocation(converter, sym);
3838c22cb84SValentin Clement   bool isConst = isConstant(sym);
3848c22cb84SValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(globalName);
3858c22cb84SValentin Clement   mlir::Type symTy = converter.genType(var);
3868c22cb84SValentin Clement 
3878c22cb84SValentin Clement   if (global && globalIsInitialized(global))
3888c22cb84SValentin Clement     return global;
3891e1f60c6SV Donaldson 
3901e1f60c6SV Donaldson   if (Fortran::semantics::IsProcedurePointer(sym))
3911e1f60c6SV Donaldson     TODO(loc, "procedure pointer globals");
3921e1f60c6SV Donaldson 
3938c22cb84SValentin Clement   // If this is an array, check to see if we can use a dense attribute
3948c22cb84SValentin Clement   // with a tensor mlir type.  This optimization currently only supports
3958c22cb84SValentin Clement   // rank-1 Fortran arrays of integer, real, or logical. The tensor
3968c22cb84SValentin Clement   // type does not support nested structures which are needed for
3978c22cb84SValentin Clement   // complex numbers.
3988c22cb84SValentin Clement   // To get multidimensional arrays to work, we will have to use column major
3998c22cb84SValentin Clement   // array ordering with the tensor type (so it matches column major ordering
4008c22cb84SValentin Clement   // with the Fortran fir.array).  By default, tensor types assume row major
4018c22cb84SValentin Clement   // ordering. How to create this tensor type is to be determined.
4028c22cb84SValentin Clement   if (symTy.isa<fir::SequenceType>() && sym.Rank() == 1 &&
4038c22cb84SValentin Clement       !Fortran::semantics::IsAllocatableOrPointer(sym)) {
4048c22cb84SValentin Clement     mlir::Type eleTy = symTy.cast<fir::SequenceType>().getEleTy();
4058c22cb84SValentin Clement     if (eleTy.isa<mlir::IntegerType, mlir::FloatType, fir::LogicalType>()) {
4068c22cb84SValentin Clement       const auto *details =
4078c22cb84SValentin Clement           sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
4088c22cb84SValentin Clement       if (details->init()) {
4098c22cb84SValentin Clement         global = Fortran::lower::createDenseGlobal(
4108c22cb84SValentin Clement             loc, symTy, globalName, linkage, isConst, details->init().value(),
4118c22cb84SValentin Clement             converter);
4128c22cb84SValentin Clement         if (global) {
4138c22cb84SValentin Clement           global.setVisibility(mlir::SymbolTable::Visibility::Public);
4148c22cb84SValentin Clement           return global;
4158c22cb84SValentin Clement         }
4168c22cb84SValentin Clement       }
4178c22cb84SValentin Clement     }
4188c22cb84SValentin Clement   }
4198c22cb84SValentin Clement   if (!global)
4208c22cb84SValentin Clement     global = builder.createGlobal(loc, symTy, globalName, linkage,
4218c22cb84SValentin Clement                                   mlir::Attribute{}, isConst);
4228c22cb84SValentin Clement   if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
4238c22cb84SValentin Clement     const auto *details =
4248c22cb84SValentin Clement         sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
4258c22cb84SValentin Clement     if (details && details->init()) {
4268c22cb84SValentin Clement       auto expr = *details->init();
4278c22cb84SValentin Clement       createGlobalInitialization(builder, global, [&](fir::FirOpBuilder &b) {
4288c22cb84SValentin Clement         mlir::Value box =
4298c22cb84SValentin Clement             Fortran::lower::genInitialDataTarget(converter, loc, symTy, expr);
4308c22cb84SValentin Clement         b.create<fir::HasValueOp>(loc, box);
4318c22cb84SValentin Clement       });
4328c22cb84SValentin Clement     } else {
4338c22cb84SValentin Clement       // Create unallocated/disassociated descriptor if no explicit init
4348c22cb84SValentin Clement       createGlobalInitialization(builder, global, [&](fir::FirOpBuilder &b) {
4358c22cb84SValentin Clement         mlir::Value box =
4368c22cb84SValentin Clement             fir::factory::createUnallocatedBox(b, loc, symTy, llvm::None);
4378c22cb84SValentin Clement         b.create<fir::HasValueOp>(loc, box);
4388c22cb84SValentin Clement       });
4398c22cb84SValentin Clement     }
4408c22cb84SValentin Clement 
4418c22cb84SValentin Clement   } else if (const auto *details =
4428c22cb84SValentin Clement                  sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
4438c22cb84SValentin Clement     if (details->init()) {
4448c22cb84SValentin Clement       createGlobalInitialization(
4458c22cb84SValentin Clement           builder, global, [&](fir::FirOpBuilder &builder) {
4468c22cb84SValentin Clement             Fortran::lower::StatementContext stmtCtx(
4478c22cb84SValentin Clement                 /*cleanupProhibited=*/true);
4488c22cb84SValentin Clement             fir::ExtendedValue initVal = genInitializerExprValue(
4498c22cb84SValentin Clement                 converter, loc, details->init().value(), stmtCtx);
4508c22cb84SValentin Clement             mlir::Value castTo =
4518c22cb84SValentin Clement                 builder.createConvert(loc, symTy, fir::getBase(initVal));
4528c22cb84SValentin Clement             builder.create<fir::HasValueOp>(loc, castTo);
4538c22cb84SValentin Clement           });
4548c22cb84SValentin Clement     } else if (hasDefaultInitialization(sym)) {
4558c22cb84SValentin Clement       createGlobalInitialization(
4568c22cb84SValentin Clement           builder, global, [&](fir::FirOpBuilder &builder) {
4578c22cb84SValentin Clement             Fortran::lower::StatementContext stmtCtx(
4588c22cb84SValentin Clement                 /*cleanupProhibited=*/true);
4598c22cb84SValentin Clement             mlir::Value initVal =
4608c22cb84SValentin Clement                 genDefaultInitializerValue(converter, loc, sym, symTy, stmtCtx);
4618c22cb84SValentin Clement             mlir::Value castTo = builder.createConvert(loc, symTy, initVal);
4628c22cb84SValentin Clement             builder.create<fir::HasValueOp>(loc, castTo);
4638c22cb84SValentin Clement           });
4648c22cb84SValentin Clement     }
4658c22cb84SValentin Clement   } else if (sym.has<Fortran::semantics::CommonBlockDetails>()) {
4668c22cb84SValentin Clement     mlir::emitError(loc, "COMMON symbol processed elsewhere");
4678c22cb84SValentin Clement   } else {
4688c22cb84SValentin Clement     TODO(loc, "global"); // Procedure pointer or something else
4698c22cb84SValentin Clement   }
4708c22cb84SValentin Clement   // Creates undefined initializer for globals without initializers
47110b23ae8SValentin Clement   if (!globalIsInitialized(global)) {
47210b23ae8SValentin Clement     // TODO: Is it really required to add the undef init if the Public
47310b23ae8SValentin Clement     // visibility is set ? We need to make sure the global is not optimized out
47410b23ae8SValentin Clement     // by LLVM if unused in the current compilation unit, but at least for
47510b23ae8SValentin Clement     // BIND(C) variables, an initial value may be given in another compilation
47610b23ae8SValentin Clement     // unit (on the C side), and setting an undef init here creates linkage
47710b23ae8SValentin Clement     // conflicts.
47810b23ae8SValentin Clement     if (sym.attrs().test(Fortran::semantics::Attr::BIND_C))
47910b23ae8SValentin Clement       TODO(loc, "BIND(C) module variable linkage");
4808c22cb84SValentin Clement     createGlobalInitialization(
4818c22cb84SValentin Clement         builder, global, [&](fir::FirOpBuilder &builder) {
4828c22cb84SValentin Clement           builder.create<fir::HasValueOp>(
4838c22cb84SValentin Clement               loc, builder.create<fir::UndefOp>(loc, symTy));
4848c22cb84SValentin Clement         });
48510b23ae8SValentin Clement   }
4868c22cb84SValentin Clement   // Set public visibility to prevent global definition to be optimized out
4878c22cb84SValentin Clement   // even if they have no initializer and are unused in this compilation unit.
4888c22cb84SValentin Clement   global.setVisibility(mlir::SymbolTable::Visibility::Public);
4898c22cb84SValentin Clement   return global;
4908c22cb84SValentin Clement }
4918c22cb84SValentin Clement 
4928c22cb84SValentin Clement /// Return linkage attribute for \p var.
4938c22cb84SValentin Clement static mlir::StringAttr
getLinkageAttribute(fir::FirOpBuilder & builder,const Fortran::lower::pft::Variable & var)4948c22cb84SValentin Clement getLinkageAttribute(fir::FirOpBuilder &builder,
4958c22cb84SValentin Clement                     const Fortran::lower::pft::Variable &var) {
496a1425019SValentin Clement   // Runtime type info for a same derived type is identical in each compilation
497a1425019SValentin Clement   // unit. It desired to avoid having to link against module that only define a
498a1425019SValentin Clement   // type. Therefore the runtime type info is generated everywhere it is needed
499a1425019SValentin Clement   // with `linkonce_odr` LLVM linkage.
500a1425019SValentin Clement   if (var.hasSymbol() && isRuntimeTypeInfoData(var.getSymbol()))
501a1425019SValentin Clement     return builder.createLinkOnceODRLinkage();
5028c22cb84SValentin Clement   if (var.isModuleVariable())
5038c22cb84SValentin Clement     return {}; // external linkage
5048c22cb84SValentin Clement   // Otherwise, the variable is owned by a procedure and must not be visible in
5058c22cb84SValentin Clement   // other compilation units.
5068c22cb84SValentin Clement   return builder.createInternalLinkage();
5078c22cb84SValentin Clement }
5088c22cb84SValentin Clement 
5098c22cb84SValentin Clement /// Instantiate a global variable. If it hasn't already been processed, add
5108c22cb84SValentin Clement /// the global to the ModuleOp as a new uniqued symbol and initialize it with
5118c22cb84SValentin Clement /// the correct value. It will be referenced on demand using `fir.addr_of`.
instantiateGlobal(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var,Fortran::lower::SymMap & symMap)5128c22cb84SValentin Clement static void instantiateGlobal(Fortran::lower::AbstractConverter &converter,
5138c22cb84SValentin Clement                               const Fortran::lower::pft::Variable &var,
5148c22cb84SValentin Clement                               Fortran::lower::SymMap &symMap) {
5158c22cb84SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
5168c22cb84SValentin Clement   assert(!var.isAlias() && "must be handled in instantiateAlias");
5178c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
5188c22cb84SValentin Clement   std::string globalName = Fortran::lower::mangle::mangleName(sym);
519*53804e42SValentin Clement   mlir::Location loc = genLocation(converter, sym);
5208c22cb84SValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(globalName);
5218c22cb84SValentin Clement   mlir::StringAttr linkage = getLinkageAttribute(builder, var);
5228c22cb84SValentin Clement   if (var.isModuleVariable()) {
5238c22cb84SValentin Clement     // A module global was or will be defined when lowering the module. Emit
5248c22cb84SValentin Clement     // only a declaration if the global does not exist at that point.
5258c22cb84SValentin Clement     global = declareGlobal(converter, var, globalName, linkage);
5268c22cb84SValentin Clement   } else {
5278c22cb84SValentin Clement     global = defineGlobal(converter, var, globalName, linkage);
5288c22cb84SValentin Clement   }
5298c22cb84SValentin Clement   auto addrOf = builder.create<fir::AddrOfOp>(loc, global.resultType(),
5308c22cb84SValentin Clement                                               global.getSymbol());
5318c22cb84SValentin Clement   Fortran::lower::StatementContext stmtCtx;
5328c22cb84SValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx, addrOf);
5338c22cb84SValentin Clement }
5348c22cb84SValentin Clement 
5352c2e5a5dSValentin Clement //===----------------------------------------------------------------===//
5362c2e5a5dSValentin Clement // Local variables instantiation (not for alias)
5372c2e5a5dSValentin Clement //===----------------------------------------------------------------===//
5382c2e5a5dSValentin Clement 
5392c2e5a5dSValentin Clement /// Create a stack slot for a local variable. Precondition: the insertion
5402c2e5a5dSValentin Clement /// point of the builder must be in the entry block, which is currently being
5412c2e5a5dSValentin Clement /// constructed.
createNewLocal(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::lower::pft::Variable & var,mlir::Value preAlloc,llvm::ArrayRef<mlir::Value> shape={},llvm::ArrayRef<mlir::Value> lenParams={})5422c2e5a5dSValentin Clement static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
5432c2e5a5dSValentin Clement                                   mlir::Location loc,
5442c2e5a5dSValentin Clement                                   const Fortran::lower::pft::Variable &var,
5452c2e5a5dSValentin Clement                                   mlir::Value preAlloc,
5462c2e5a5dSValentin Clement                                   llvm::ArrayRef<mlir::Value> shape = {},
5472c2e5a5dSValentin Clement                                   llvm::ArrayRef<mlir::Value> lenParams = {}) {
5482c2e5a5dSValentin Clement   if (preAlloc)
5492c2e5a5dSValentin Clement     return preAlloc;
5502c2e5a5dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
5512c2e5a5dSValentin Clement   std::string nm = Fortran::lower::mangle::mangleName(var.getSymbol());
5522c2e5a5dSValentin Clement   mlir::Type ty = converter.genType(var);
5532c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &ultimateSymbol =
5542c2e5a5dSValentin Clement       var.getSymbol().GetUltimate();
5552c2e5a5dSValentin Clement   llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
5562c2e5a5dSValentin Clement   bool isTarg = var.isTarget();
5572c2e5a5dSValentin Clement   // Let the builder do all the heavy lifting.
5582c2e5a5dSValentin Clement   return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg);
5592c2e5a5dSValentin Clement }
5602c2e5a5dSValentin Clement 
561a1425019SValentin Clement /// Must \p var be default initialized at runtime when entering its scope.
562a1425019SValentin Clement static bool
mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable & var)563a1425019SValentin Clement mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable &var) {
564a1425019SValentin Clement   if (!var.hasSymbol())
565a1425019SValentin Clement     return false;
566a1425019SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
567a1425019SValentin Clement   if (var.isGlobal())
568a1425019SValentin Clement     // Global variables are statically initialized.
569a1425019SValentin Clement     return false;
570a1425019SValentin Clement   if (Fortran::semantics::IsDummy(sym) && !Fortran::semantics::IsIntentOut(sym))
571a1425019SValentin Clement     return false;
572a1425019SValentin Clement   // Local variables (including function results), and intent(out) dummies must
573a1425019SValentin Clement   // be default initialized at runtime if their type has default initialization.
574a1425019SValentin Clement   return hasDefaultInitialization(sym);
575a1425019SValentin Clement }
576a1425019SValentin Clement 
577a1425019SValentin Clement /// Call default initialization runtime routine to initialize \p var.
578a1425019SValentin Clement static void
defaultInitializeAtRuntime(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var,Fortran::lower::SymMap & symMap)579a1425019SValentin Clement defaultInitializeAtRuntime(Fortran::lower::AbstractConverter &converter,
580a1425019SValentin Clement                            const Fortran::lower::pft::Variable &var,
581a1425019SValentin Clement                            Fortran::lower::SymMap &symMap) {
582a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
583a1425019SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
584a1425019SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
585a1425019SValentin Clement   fir::ExtendedValue exv = symMap.lookupSymbol(sym).toExtendedValue();
586a1425019SValentin Clement   if (Fortran::semantics::IsOptional(sym)) {
587a1425019SValentin Clement     // 15.5.2.12 point 3, absent optional dummies are not initialized.
588a1425019SValentin Clement     // Creating descriptor/passing null descriptor to the runtime would
589a1425019SValentin Clement     // create runtime crashes.
590a1425019SValentin Clement     auto isPresent = builder.create<fir::IsPresentOp>(loc, builder.getI1Type(),
591a1425019SValentin Clement                                                       fir::getBase(exv));
592a1425019SValentin Clement     builder.genIfThen(loc, isPresent)
593a1425019SValentin Clement         .genThen([&]() {
594a1425019SValentin Clement           auto box = builder.createBox(loc, exv);
595a1425019SValentin Clement           fir::runtime::genDerivedTypeInitialize(builder, loc, box);
596a1425019SValentin Clement         })
597a1425019SValentin Clement         .end();
598a1425019SValentin Clement   } else {
599a1425019SValentin Clement     mlir::Value box = builder.createBox(loc, exv);
600a1425019SValentin Clement     fir::runtime::genDerivedTypeInitialize(builder, loc, box);
601a1425019SValentin Clement   }
602a1425019SValentin Clement }
603a1425019SValentin Clement 
6042c2e5a5dSValentin Clement /// Instantiate a local variable. Precondition: Each variable will be visited
6052c2e5a5dSValentin Clement /// such that if its properties depend on other variables, the variables upon
6062c2e5a5dSValentin Clement /// which its properties depend will already have been visited.
instantiateLocal(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var,Fortran::lower::SymMap & symMap)6072c2e5a5dSValentin Clement static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
6082c2e5a5dSValentin Clement                              const Fortran::lower::pft::Variable &var,
6092c2e5a5dSValentin Clement                              Fortran::lower::SymMap &symMap) {
6102c2e5a5dSValentin Clement   assert(!var.isAlias());
6112a59ead1SValentin Clement   Fortran::lower::StatementContext stmtCtx;
6122a59ead1SValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx);
613a1425019SValentin Clement   if (mustBeDefaultInitializedAtRuntime(var))
614a1425019SValentin Clement     defaultInitializeAtRuntime(converter, var, symMap);
615a1425019SValentin Clement }
616a1425019SValentin Clement 
617a1425019SValentin Clement //===----------------------------------------------------------------===//
618a1425019SValentin Clement // Aliased (EQUIVALENCE) variables instantiation
619a1425019SValentin Clement //===----------------------------------------------------------------===//
620a1425019SValentin Clement 
621a1425019SValentin Clement /// Insert \p aggregateStore instance into an AggregateStoreMap.
insertAggregateStore(Fortran::lower::AggregateStoreMap & storeMap,const Fortran::lower::pft::Variable & var,mlir::Value aggregateStore)622a1425019SValentin Clement static void insertAggregateStore(Fortran::lower::AggregateStoreMap &storeMap,
623a1425019SValentin Clement                                  const Fortran::lower::pft::Variable &var,
624a1425019SValentin Clement                                  mlir::Value aggregateStore) {
625a1425019SValentin Clement   std::size_t off = var.getAggregateStore().getOffset();
626a1425019SValentin Clement   Fortran::lower::AggregateStoreKey key = {var.getOwningScope(), off};
627a1425019SValentin Clement   storeMap[key] = aggregateStore;
628a1425019SValentin Clement }
629a1425019SValentin Clement 
630a1425019SValentin Clement /// Retrieve the aggregate store instance of \p alias from an
631a1425019SValentin Clement /// AggregateStoreMap.
632a1425019SValentin Clement static mlir::Value
getAggregateStore(Fortran::lower::AggregateStoreMap & storeMap,const Fortran::lower::pft::Variable & alias)633a1425019SValentin Clement getAggregateStore(Fortran::lower::AggregateStoreMap &storeMap,
634a1425019SValentin Clement                   const Fortran::lower::pft::Variable &alias) {
635a1425019SValentin Clement   Fortran::lower::AggregateStoreKey key = {alias.getOwningScope(),
636a1425019SValentin Clement                                            alias.getAlias()};
637a1425019SValentin Clement   auto iter = storeMap.find(key);
638a1425019SValentin Clement   assert(iter != storeMap.end());
639a1425019SValentin Clement   return iter->second;
640a1425019SValentin Clement }
641a1425019SValentin Clement 
642a1425019SValentin Clement /// Build the name for the storage of a global equivalence.
mangleGlobalAggregateStore(const Fortran::lower::pft::Variable::AggregateStore & st)643a1425019SValentin Clement static std::string mangleGlobalAggregateStore(
644a1425019SValentin Clement     const Fortran::lower::pft::Variable::AggregateStore &st) {
645a1425019SValentin Clement   return Fortran::lower::mangle::mangleName(st.getNamingSymbol());
646a1425019SValentin Clement }
647a1425019SValentin Clement 
648a1425019SValentin Clement /// Build the type for the storage of an equivalence.
649a1425019SValentin Clement static mlir::Type
getAggregateType(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable::AggregateStore & st)650a1425019SValentin Clement getAggregateType(Fortran::lower::AbstractConverter &converter,
651a1425019SValentin Clement                  const Fortran::lower::pft::Variable::AggregateStore &st) {
652a1425019SValentin Clement   if (const Fortran::semantics::Symbol *initSym = st.getInitialValueSymbol())
653a1425019SValentin Clement     return converter.genType(*initSym);
654a1425019SValentin Clement   mlir::IntegerType byteTy = converter.getFirOpBuilder().getIntegerType(8);
655a1425019SValentin Clement   return fir::SequenceType::get(std::get<1>(st.interval), byteTy);
656a1425019SValentin Clement }
657a1425019SValentin Clement 
658a1425019SValentin Clement /// Define a GlobalOp for the storage of a global equivalence described
659a1425019SValentin Clement /// by \p aggregate. The global is named \p aggName and is created with
660a1425019SValentin Clement /// the provided \p linkage.
661a1425019SValentin Clement /// If any of the equivalence members are initialized, an initializer is
662a1425019SValentin Clement /// created for the equivalence.
663a1425019SValentin Clement /// This is to be used when lowering the scope that owns the equivalence
664a1425019SValentin Clement /// (as opposed to simply using it through host or use association).
665a1425019SValentin Clement /// This is not to be used for equivalence of common block members (they
666a1425019SValentin Clement /// already have the common block GlobalOp for them, see defineCommonBlock).
defineGlobalAggregateStore(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable::AggregateStore & aggregate,llvm::StringRef aggName,mlir::StringAttr linkage)667a1425019SValentin Clement static fir::GlobalOp defineGlobalAggregateStore(
668a1425019SValentin Clement     Fortran::lower::AbstractConverter &converter,
669a1425019SValentin Clement     const Fortran::lower::pft::Variable::AggregateStore &aggregate,
670a1425019SValentin Clement     llvm::StringRef aggName, mlir::StringAttr linkage) {
671a1425019SValentin Clement   assert(aggregate.isGlobal() && "not a global interval");
672a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
673a1425019SValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(aggName);
674a1425019SValentin Clement   if (global && globalIsInitialized(global))
675a1425019SValentin Clement     return global;
676a1425019SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
677a1425019SValentin Clement   mlir::Type aggTy = getAggregateType(converter, aggregate);
678a1425019SValentin Clement   if (!global)
679a1425019SValentin Clement     global = builder.createGlobal(loc, aggTy, aggName, linkage);
680a1425019SValentin Clement 
681a1425019SValentin Clement   if (const Fortran::semantics::Symbol *initSym =
682a1425019SValentin Clement           aggregate.getInitialValueSymbol())
683a1425019SValentin Clement     if (const auto *objectDetails =
684a1425019SValentin Clement             initSym->detailsIf<Fortran::semantics::ObjectEntityDetails>())
685a1425019SValentin Clement       if (objectDetails->init()) {
686a1425019SValentin Clement         createGlobalInitialization(
687a1425019SValentin Clement             builder, global, [&](fir::FirOpBuilder &builder) {
688a1425019SValentin Clement               Fortran::lower::StatementContext stmtCtx;
689a1425019SValentin Clement               mlir::Value initVal = fir::getBase(genInitializerExprValue(
690a1425019SValentin Clement                   converter, loc, objectDetails->init().value(), stmtCtx));
691a1425019SValentin Clement               builder.create<fir::HasValueOp>(loc, initVal);
692a1425019SValentin Clement             });
693a1425019SValentin Clement         return global;
694a1425019SValentin Clement       }
695a1425019SValentin Clement   // Equivalence has no Fortran initial value. Create an undefined FIR initial
696a1425019SValentin Clement   // value to ensure this is consider an object definition in the IR regardless
697a1425019SValentin Clement   // of the linkage.
698a1425019SValentin Clement   createGlobalInitialization(builder, global, [&](fir::FirOpBuilder &builder) {
699a1425019SValentin Clement     Fortran::lower::StatementContext stmtCtx;
700a1425019SValentin Clement     mlir::Value initVal = builder.create<fir::UndefOp>(loc, aggTy);
701a1425019SValentin Clement     builder.create<fir::HasValueOp>(loc, initVal);
702a1425019SValentin Clement   });
703a1425019SValentin Clement   return global;
704a1425019SValentin Clement }
705a1425019SValentin Clement 
706a1425019SValentin Clement /// Declare a GlobalOp for the storage of a global equivalence described
707a1425019SValentin Clement /// by \p aggregate. The global is named \p aggName and is created with
708a1425019SValentin Clement /// the provided \p linkage.
709a1425019SValentin Clement /// No initializer is built for the created GlobalOp.
710a1425019SValentin Clement /// This is to be used when lowering the scope that uses members of an
711a1425019SValentin Clement /// equivalence it through host or use association.
712a1425019SValentin Clement /// This is not to be used for equivalence of common block members (they
713a1425019SValentin Clement /// already have the common block GlobalOp for them, see defineCommonBlock).
declareGlobalAggregateStore(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::lower::pft::Variable::AggregateStore & aggregate,llvm::StringRef aggName,mlir::StringAttr linkage)714a1425019SValentin Clement static fir::GlobalOp declareGlobalAggregateStore(
715a1425019SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
716a1425019SValentin Clement     const Fortran::lower::pft::Variable::AggregateStore &aggregate,
717a1425019SValentin Clement     llvm::StringRef aggName, mlir::StringAttr linkage) {
718a1425019SValentin Clement   assert(aggregate.isGlobal() && "not a global interval");
719a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
720a1425019SValentin Clement   if (fir::GlobalOp global = builder.getNamedGlobal(aggName))
721a1425019SValentin Clement     return global;
722a1425019SValentin Clement   mlir::Type aggTy = getAggregateType(converter, aggregate);
723a1425019SValentin Clement   return builder.createGlobal(loc, aggTy, aggName, linkage);
724a1425019SValentin Clement }
725a1425019SValentin Clement 
726a1425019SValentin Clement /// This is an aggregate store for a set of EQUIVALENCED variables. Create the
727a1425019SValentin Clement /// storage on the stack or global memory and add it to the map.
728a1425019SValentin Clement static void
instantiateAggregateStore(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var,Fortran::lower::AggregateStoreMap & storeMap)729a1425019SValentin Clement instantiateAggregateStore(Fortran::lower::AbstractConverter &converter,
730a1425019SValentin Clement                           const Fortran::lower::pft::Variable &var,
731a1425019SValentin Clement                           Fortran::lower::AggregateStoreMap &storeMap) {
732a1425019SValentin Clement   assert(var.isAggregateStore() && "not an interval");
733a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
734a1425019SValentin Clement   mlir::IntegerType i8Ty = builder.getIntegerType(8);
735a1425019SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
736a1425019SValentin Clement   std::string aggName = mangleGlobalAggregateStore(var.getAggregateStore());
737a1425019SValentin Clement   if (var.isGlobal()) {
738a1425019SValentin Clement     fir::GlobalOp global;
739a1425019SValentin Clement     auto &aggregate = var.getAggregateStore();
740a1425019SValentin Clement     mlir::StringAttr linkage = getLinkageAttribute(builder, var);
741a1425019SValentin Clement     if (var.isModuleVariable()) {
742a1425019SValentin Clement       // A module global was or will be defined when lowering the module. Emit
743a1425019SValentin Clement       // only a declaration if the global does not exist at that point.
744a1425019SValentin Clement       global = declareGlobalAggregateStore(converter, loc, aggregate, aggName,
745a1425019SValentin Clement                                            linkage);
746a1425019SValentin Clement     } else {
747a1425019SValentin Clement       global =
748a1425019SValentin Clement           defineGlobalAggregateStore(converter, aggregate, aggName, linkage);
749a1425019SValentin Clement     }
750a1425019SValentin Clement     auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(),
751a1425019SValentin Clement                                               global.getSymbol());
752a1425019SValentin Clement     auto size = std::get<1>(var.getInterval());
753a1425019SValentin Clement     fir::SequenceType::Shape shape(1, size);
754a1425019SValentin Clement     auto seqTy = fir::SequenceType::get(shape, i8Ty);
755a1425019SValentin Clement     mlir::Type refTy = builder.getRefType(seqTy);
756a1425019SValentin Clement     mlir::Value aggregateStore = builder.createConvert(loc, refTy, addr);
757a1425019SValentin Clement     insertAggregateStore(storeMap, var, aggregateStore);
758a1425019SValentin Clement     return;
759a1425019SValentin Clement   }
760a1425019SValentin Clement   // This is a local aggregate, allocate an anonymous block of memory.
761a1425019SValentin Clement   auto size = std::get<1>(var.getInterval());
762a1425019SValentin Clement   fir::SequenceType::Shape shape(1, size);
763a1425019SValentin Clement   auto seqTy = fir::SequenceType::get(shape, i8Ty);
764a1425019SValentin Clement   mlir::Value local =
765a1425019SValentin Clement       builder.allocateLocal(loc, seqTy, aggName, "", llvm::None, llvm::None,
766a1425019SValentin Clement                             /*target=*/false);
767a1425019SValentin Clement   insertAggregateStore(storeMap, var, local);
7682a59ead1SValentin Clement }
7692a59ead1SValentin Clement 
7705d25267dSValentin Clement /// Cast an alias address (variable part of an equivalence) to fir.ptr so that
7715d25267dSValentin Clement /// the optimizer is conservative and avoids doing copy elision in assignment
7725d25267dSValentin Clement /// involving equivalenced variables.
7735d25267dSValentin Clement /// TODO: Represent the equivalence aliasing constraint in another way to avoid
7745d25267dSValentin Clement /// pessimizing array assignments involving equivalenced variables.
castAliasToPointer(fir::FirOpBuilder & builder,mlir::Location loc,mlir::Type aliasType,mlir::Value aliasAddr)7755d25267dSValentin Clement static mlir::Value castAliasToPointer(fir::FirOpBuilder &builder,
7765d25267dSValentin Clement                                       mlir::Location loc, mlir::Type aliasType,
7775d25267dSValentin Clement                                       mlir::Value aliasAddr) {
7785d25267dSValentin Clement   return builder.createConvert(loc, fir::PointerType::get(aliasType),
7795d25267dSValentin Clement                                aliasAddr);
7805d25267dSValentin Clement }
7815d25267dSValentin Clement 
782a1425019SValentin Clement /// Instantiate a member of an equivalence. Compute its address in its
783a1425019SValentin Clement /// aggregate storage and lower its attributes.
instantiateAlias(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var,Fortran::lower::SymMap & symMap,Fortran::lower::AggregateStoreMap & storeMap)784a1425019SValentin Clement static void instantiateAlias(Fortran::lower::AbstractConverter &converter,
785a1425019SValentin Clement                              const Fortran::lower::pft::Variable &var,
786a1425019SValentin Clement                              Fortran::lower::SymMap &symMap,
787a1425019SValentin Clement                              Fortran::lower::AggregateStoreMap &storeMap) {
788a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
789a1425019SValentin Clement   assert(var.isAlias());
790a1425019SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
791*53804e42SValentin Clement   const mlir::Location loc = genLocation(converter, sym);
792a1425019SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
793a1425019SValentin Clement   std::size_t aliasOffset = var.getAlias();
794a1425019SValentin Clement   mlir::Value store = getAggregateStore(storeMap, var);
795a1425019SValentin Clement   mlir::IntegerType i8Ty = builder.getIntegerType(8);
796a1425019SValentin Clement   mlir::Type i8Ptr = builder.getRefType(i8Ty);
797a1425019SValentin Clement   mlir::Value offset = builder.createIntegerConstant(
798a1425019SValentin Clement       loc, idxTy, sym.GetUltimate().offset() - aliasOffset);
799a1425019SValentin Clement   auto ptr = builder.create<fir::CoordinateOp>(loc, i8Ptr, store,
800a1425019SValentin Clement                                                mlir::ValueRange{offset});
801a1425019SValentin Clement   mlir::Value preAlloc =
802a1425019SValentin Clement       castAliasToPointer(builder, loc, converter.genType(sym), ptr);
803a1425019SValentin Clement   Fortran::lower::StatementContext stmtCtx;
804a1425019SValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx, preAlloc);
805a1425019SValentin Clement   // Default initialization is possible for equivalence members: see
806a1425019SValentin Clement   // F2018 19.5.3.4. Note that if several equivalenced entities have
807a1425019SValentin Clement   // default initialization, they must have the same type, and the standard
808a1425019SValentin Clement   // allows the storage to be default initialized several times (this has
809a1425019SValentin Clement   // no consequences other than wasting some execution time). For now,
810a1425019SValentin Clement   // do not try optimizing this to single default initializations of
811a1425019SValentin Clement   // the equivalenced storages. Keep lowering simple.
812a1425019SValentin Clement   if (mustBeDefaultInitializedAtRuntime(var))
813a1425019SValentin Clement     defaultInitializeAtRuntime(converter, var, symMap);
814a1425019SValentin Clement }
815a1425019SValentin Clement 
8165d25267dSValentin Clement //===--------------------------------------------------------------===//
8175d25267dSValentin Clement // COMMON blocks instantiation
8185d25267dSValentin Clement //===--------------------------------------------------------------===//
8195d25267dSValentin Clement 
8205d25267dSValentin Clement /// Does any member of the common block has an initializer ?
8215d25267dSValentin Clement static bool
commonBlockHasInit(const Fortran::semantics::MutableSymbolVector & cmnBlkMems)8225d25267dSValentin Clement commonBlockHasInit(const Fortran::semantics::MutableSymbolVector &cmnBlkMems) {
8235d25267dSValentin Clement   for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
8245d25267dSValentin Clement     if (const auto *memDet =
8255d25267dSValentin Clement             mem->detailsIf<Fortran::semantics::ObjectEntityDetails>())
8265d25267dSValentin Clement       if (memDet->init())
8275d25267dSValentin Clement         return true;
8285d25267dSValentin Clement   }
8295d25267dSValentin Clement   return false;
8305d25267dSValentin Clement }
8315d25267dSValentin Clement 
8325d25267dSValentin Clement /// Build a tuple type for a common block based on the common block
8335d25267dSValentin Clement /// members and the common block size.
8345d25267dSValentin Clement /// This type is only needed to build common block initializers where
8355d25267dSValentin Clement /// the initial value is the collection of the member initial values.
getTypeOfCommonWithInit(Fortran::lower::AbstractConverter & converter,const Fortran::semantics::MutableSymbolVector & cmnBlkMems,std::size_t commonSize)8365d25267dSValentin Clement static mlir::TupleType getTypeOfCommonWithInit(
8375d25267dSValentin Clement     Fortran::lower::AbstractConverter &converter,
8385d25267dSValentin Clement     const Fortran::semantics::MutableSymbolVector &cmnBlkMems,
8395d25267dSValentin Clement     std::size_t commonSize) {
8405d25267dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
8415d25267dSValentin Clement   llvm::SmallVector<mlir::Type> members;
8425d25267dSValentin Clement   std::size_t counter = 0;
8435d25267dSValentin Clement   for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
8445d25267dSValentin Clement     if (const auto *memDet =
8455d25267dSValentin Clement             mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
8465d25267dSValentin Clement       if (mem->offset() > counter) {
8475d25267dSValentin Clement         fir::SequenceType::Shape len = {
8485d25267dSValentin Clement             static_cast<fir::SequenceType::Extent>(mem->offset() - counter)};
8495d25267dSValentin Clement         mlir::IntegerType byteTy = builder.getIntegerType(8);
8505d25267dSValentin Clement         auto memTy = fir::SequenceType::get(len, byteTy);
8515d25267dSValentin Clement         members.push_back(memTy);
8525d25267dSValentin Clement         counter = mem->offset();
8535d25267dSValentin Clement       }
8545d25267dSValentin Clement       if (memDet->init()) {
8555d25267dSValentin Clement         mlir::Type memTy = converter.genType(*mem);
8565d25267dSValentin Clement         members.push_back(memTy);
8575d25267dSValentin Clement         counter = mem->offset() + mem->size();
8585d25267dSValentin Clement       }
8595d25267dSValentin Clement     }
8605d25267dSValentin Clement   }
8615d25267dSValentin Clement   if (counter < commonSize) {
8625d25267dSValentin Clement     fir::SequenceType::Shape len = {
8635d25267dSValentin Clement         static_cast<fir::SequenceType::Extent>(commonSize - counter)};
8645d25267dSValentin Clement     mlir::IntegerType byteTy = builder.getIntegerType(8);
8655d25267dSValentin Clement     auto memTy = fir::SequenceType::get(len, byteTy);
8665d25267dSValentin Clement     members.push_back(memTy);
8675d25267dSValentin Clement   }
8685d25267dSValentin Clement   return mlir::TupleType::get(builder.getContext(), members);
8695d25267dSValentin Clement }
8705d25267dSValentin Clement 
8715d25267dSValentin Clement /// Common block members may have aliases. They are not in the common block
8725d25267dSValentin Clement /// member list from the symbol. We need to know about these aliases if they
8735d25267dSValentin Clement /// have initializer to generate the common initializer.
8745d25267dSValentin Clement /// This function takes care of adding aliases with initializer to the member
8755d25267dSValentin Clement /// list.
8765d25267dSValentin Clement static Fortran::semantics::MutableSymbolVector
getCommonMembersWithInitAliases(const Fortran::semantics::Symbol & common)8775d25267dSValentin Clement getCommonMembersWithInitAliases(const Fortran::semantics::Symbol &common) {
8785d25267dSValentin Clement   const auto &commonDetails =
8795d25267dSValentin Clement       common.get<Fortran::semantics::CommonBlockDetails>();
8805d25267dSValentin Clement   auto members = commonDetails.objects();
8815d25267dSValentin Clement 
8825d25267dSValentin Clement   // The number and size of equivalence and common is expected to be small, so
8835d25267dSValentin Clement   // no effort is given to optimize this loop of complexity equivalenced
8845d25267dSValentin Clement   // common members * common members
8855d25267dSValentin Clement   for (const Fortran::semantics::EquivalenceSet &set :
8865d25267dSValentin Clement        common.owner().equivalenceSets())
8875d25267dSValentin Clement     for (const Fortran::semantics::EquivalenceObject &obj : set) {
8885d25267dSValentin Clement       if (!obj.symbol.test(Fortran::semantics::Symbol::Flag::CompilerCreated)) {
8895d25267dSValentin Clement         if (const auto &details =
8905d25267dSValentin Clement                 obj.symbol
8915d25267dSValentin Clement                     .detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
8925d25267dSValentin Clement           const Fortran::semantics::Symbol *com =
8935d25267dSValentin Clement               FindCommonBlockContaining(obj.symbol);
8945d25267dSValentin Clement           if (!details->init() || com != &common)
8955d25267dSValentin Clement             continue;
8965d25267dSValentin Clement           // This is an alias with an init that belongs to the list
8975d25267dSValentin Clement           if (std::find(members.begin(), members.end(), obj.symbol) ==
8985d25267dSValentin Clement               members.end())
8995d25267dSValentin Clement             members.emplace_back(obj.symbol);
9005d25267dSValentin Clement         }
9015d25267dSValentin Clement       }
9025d25267dSValentin Clement     }
9035d25267dSValentin Clement   return members;
9045d25267dSValentin Clement }
9055d25267dSValentin Clement 
9062c8cb9acSJean Perier /// Return the fir::GlobalOp that was created of COMMON block \p common.
9072c8cb9acSJean Perier /// It is an error if the fir::GlobalOp was not created before this is
9082c8cb9acSJean Perier /// called (it cannot be created on the flight because it is not known here
9092c8cb9acSJean Perier /// what mlir type the GlobalOp should have to satisfy all the
9102c8cb9acSJean Perier /// appearances in the program).
9115d25267dSValentin Clement static fir::GlobalOp
getCommonBlockGlobal(Fortran::lower::AbstractConverter & converter,const Fortran::semantics::Symbol & common)9122c8cb9acSJean Perier getCommonBlockGlobal(Fortran::lower::AbstractConverter &converter,
9135d25267dSValentin Clement                      const Fortran::semantics::Symbol &common) {
9145d25267dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
9155d25267dSValentin Clement   std::string commonName = Fortran::lower::mangle::mangleName(common);
9165d25267dSValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(commonName);
9172c8cb9acSJean Perier   // Common blocks are lowered before any subprograms to deal with common
9182c8cb9acSJean Perier   // whose size may not be the same in every subprograms.
9192c8cb9acSJean Perier   if (!global)
9202c8cb9acSJean Perier     fir::emitFatalError(converter.genLocation(common.name()),
9212c8cb9acSJean Perier                         "COMMON block was not lowered before its usage");
9225d25267dSValentin Clement   return global;
9232c8cb9acSJean Perier }
9242c8cb9acSJean Perier 
9252c8cb9acSJean Perier /// Create the fir::GlobalOp for COMMON block \p common. If \p common has an
9262c8cb9acSJean Perier /// initial value, it is not created yet. Instead, the common block list
9272c8cb9acSJean Perier /// members is returned to later create the initial value in
9282c8cb9acSJean Perier /// finalizeCommonBlockDefinition.
9292c8cb9acSJean Perier static std::optional<std::tuple<
9302c8cb9acSJean Perier     fir::GlobalOp, Fortran::semantics::MutableSymbolVector, mlir::Location>>
declareCommonBlock(Fortran::lower::AbstractConverter & converter,const Fortran::semantics::Symbol & common,std::size_t commonSize)9312c8cb9acSJean Perier declareCommonBlock(Fortran::lower::AbstractConverter &converter,
9322c8cb9acSJean Perier                    const Fortran::semantics::Symbol &common,
9332c8cb9acSJean Perier                    std::size_t commonSize) {
9342c8cb9acSJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
9352c8cb9acSJean Perier   std::string commonName = Fortran::lower::mangle::mangleName(common);
9362c8cb9acSJean Perier   fir::GlobalOp global = builder.getNamedGlobal(commonName);
9372c8cb9acSJean Perier   if (global)
9382c8cb9acSJean Perier     return std::nullopt;
9395d25267dSValentin Clement   Fortran::semantics::MutableSymbolVector cmnBlkMems =
9405d25267dSValentin Clement       getCommonMembersWithInitAliases(common);
9415d25267dSValentin Clement   mlir::Location loc = converter.genLocation(common.name());
9425d25267dSValentin Clement   mlir::StringAttr linkage = builder.createCommonLinkage();
9432c8cb9acSJean Perier   if (!commonBlockHasInit(cmnBlkMems)) {
9442c8cb9acSJean Perier     // A COMMON block sans initializers is initialized to zero.
9455d25267dSValentin Clement     // mlir::Vector types must have a strictly positive size, so at least
9465d25267dSValentin Clement     // temporarily, force a zero size COMMON block to have one byte.
9472c8cb9acSJean Perier     const auto sz =
9482c8cb9acSJean Perier         static_cast<fir::SequenceType::Extent>(commonSize > 0 ? commonSize : 1);
9495d25267dSValentin Clement     fir::SequenceType::Shape shape = {sz};
9505d25267dSValentin Clement     mlir::IntegerType i8Ty = builder.getIntegerType(8);
9515d25267dSValentin Clement     auto commonTy = fir::SequenceType::get(shape, i8Ty);
9525d25267dSValentin Clement     auto vecTy = mlir::VectorType::get(sz, i8Ty);
9535d25267dSValentin Clement     mlir::Attribute zero = builder.getIntegerAttr(i8Ty, 0);
9545d25267dSValentin Clement     auto init = mlir::DenseElementsAttr::get(vecTy, llvm::makeArrayRef(zero));
9552c8cb9acSJean Perier     builder.createGlobal(loc, commonTy, commonName, linkage, init);
9562c8cb9acSJean Perier     // No need to add any initial value later.
9572c8cb9acSJean Perier     return std::nullopt;
9585d25267dSValentin Clement   }
9592c8cb9acSJean Perier   // COMMON block with initializer (note that initialized blank common are
9602c8cb9acSJean Perier   // accepted as an extension by semantics). Sort members by offset before
9612c8cb9acSJean Perier   // generating the type and initializer.
9625d25267dSValentin Clement   std::sort(cmnBlkMems.begin(), cmnBlkMems.end(),
9635d25267dSValentin Clement             [](auto &s1, auto &s2) { return s1->offset() < s2->offset(); });
9645d25267dSValentin Clement   mlir::TupleType commonTy =
9652c8cb9acSJean Perier       getTypeOfCommonWithInit(converter, cmnBlkMems, commonSize);
9662c8cb9acSJean Perier   // Create the global object, the initial value will be added later.
9672c8cb9acSJean Perier   global = builder.createGlobal(loc, commonTy, commonName);
9682c8cb9acSJean Perier   return std::make_tuple(global, std::move(cmnBlkMems), loc);
9692c8cb9acSJean Perier }
9702c8cb9acSJean Perier 
9712c8cb9acSJean Perier /// Add initial value to a COMMON block fir::GlobalOp \p global given the list
9722c8cb9acSJean Perier /// \p cmnBlkMems of the common block member symbols that contains symbols with
9732c8cb9acSJean Perier /// an initial value.
finalizeCommonBlockDefinition(mlir::Location loc,Fortran::lower::AbstractConverter & converter,fir::GlobalOp global,const Fortran::semantics::MutableSymbolVector & cmnBlkMems)9742c8cb9acSJean Perier static void finalizeCommonBlockDefinition(
9752c8cb9acSJean Perier     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
9762c8cb9acSJean Perier     fir::GlobalOp global,
9772c8cb9acSJean Perier     const Fortran::semantics::MutableSymbolVector &cmnBlkMems) {
9782c8cb9acSJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
9792c8cb9acSJean Perier   mlir::TupleType commonTy = global.getType().cast<mlir::TupleType>();
9805d25267dSValentin Clement   auto initFunc = [&](fir::FirOpBuilder &builder) {
9812c8cb9acSJean Perier     mlir::IndexType idxTy = builder.getIndexType();
9825d25267dSValentin Clement     mlir::Value cb = builder.create<fir::UndefOp>(loc, commonTy);
9835d25267dSValentin Clement     unsigned tupIdx = 0;
9845d25267dSValentin Clement     std::size_t offset = 0;
9855d25267dSValentin Clement     LLVM_DEBUG(llvm::dbgs() << "block {\n");
9865d25267dSValentin Clement     for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
9875d25267dSValentin Clement       if (const auto *memDet =
9885d25267dSValentin Clement               mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
9895d25267dSValentin Clement         if (mem->offset() > offset) {
9905d25267dSValentin Clement           ++tupIdx;
9915d25267dSValentin Clement           offset = mem->offset();
9925d25267dSValentin Clement         }
9935d25267dSValentin Clement         if (memDet->init()) {
9945d25267dSValentin Clement           LLVM_DEBUG(llvm::dbgs()
9955d25267dSValentin Clement                      << "offset: " << mem->offset() << " is " << *mem << '\n');
9965d25267dSValentin Clement           Fortran::lower::StatementContext stmtCtx;
9975d25267dSValentin Clement           auto initExpr = memDet->init().value();
9985d25267dSValentin Clement           fir::ExtendedValue initVal =
9995d25267dSValentin Clement               Fortran::semantics::IsPointer(*mem)
10005d25267dSValentin Clement                   ? Fortran::lower::genInitialDataTarget(
10015d25267dSValentin Clement                         converter, loc, converter.genType(*mem), initExpr)
10025d25267dSValentin Clement                   : genInitializerExprValue(converter, loc, initExpr, stmtCtx);
10035d25267dSValentin Clement           mlir::IntegerAttr offVal = builder.getIntegerAttr(idxTy, tupIdx);
10045d25267dSValentin Clement           mlir::Value castVal = builder.createConvert(
10055d25267dSValentin Clement               loc, commonTy.getType(tupIdx), fir::getBase(initVal));
10065d25267dSValentin Clement           cb = builder.create<fir::InsertValueOp>(loc, commonTy, cb, castVal,
10075d25267dSValentin Clement                                                   builder.getArrayAttr(offVal));
10085d25267dSValentin Clement           ++tupIdx;
10095d25267dSValentin Clement           offset = mem->offset() + mem->size();
10105d25267dSValentin Clement         }
10115d25267dSValentin Clement       }
10125d25267dSValentin Clement     }
10135d25267dSValentin Clement     LLVM_DEBUG(llvm::dbgs() << "}\n");
10145d25267dSValentin Clement     builder.create<fir::HasValueOp>(loc, cb);
10155d25267dSValentin Clement   };
10162c8cb9acSJean Perier   createGlobalInitialization(builder, global, initFunc);
10175d25267dSValentin Clement }
10182c8cb9acSJean Perier 
defineCommonBlocks(Fortran::lower::AbstractConverter & converter,const Fortran::semantics::CommonBlockList & commonBlocks)10192c8cb9acSJean Perier void Fortran::lower::defineCommonBlocks(
10202c8cb9acSJean Perier     Fortran::lower::AbstractConverter &converter,
10212c8cb9acSJean Perier     const Fortran::semantics::CommonBlockList &commonBlocks) {
10222c8cb9acSJean Perier   // Common blocks may depend on another common block address (if they contain
10232c8cb9acSJean Perier   // pointers with initial targets). To cover this case, create all common block
10242c8cb9acSJean Perier   // fir::Global before creating the initial values (if any).
10252c8cb9acSJean Perier   std::vector<std::tuple<fir::GlobalOp, Fortran::semantics::MutableSymbolVector,
10262c8cb9acSJean Perier                          mlir::Location>>
10272c8cb9acSJean Perier       delayedInitializations;
10285a793640SPeter Klausler   for (const auto &[common, size] : commonBlocks)
10292c8cb9acSJean Perier     if (auto delayedInit = declareCommonBlock(converter, common, size))
10302c8cb9acSJean Perier       delayedInitializations.emplace_back(std::move(*delayedInit));
10312c8cb9acSJean Perier   for (auto &[global, cmnBlkMems, loc] : delayedInitializations)
10322c8cb9acSJean Perier     finalizeCommonBlockDefinition(loc, converter, global, cmnBlkMems);
10332c8cb9acSJean Perier }
10342c8cb9acSJean Perier 
10355d25267dSValentin Clement /// The COMMON block is a global structure. `var` will be at some offset
10365d25267dSValentin Clement /// within the COMMON block. Adds the address of `var` (COMMON + offset) to
10375d25267dSValentin Clement /// the symbol map.
instantiateCommon(Fortran::lower::AbstractConverter & converter,const Fortran::semantics::Symbol & common,const Fortran::lower::pft::Variable & var,Fortran::lower::SymMap & symMap)10385d25267dSValentin Clement static void instantiateCommon(Fortran::lower::AbstractConverter &converter,
10395d25267dSValentin Clement                               const Fortran::semantics::Symbol &common,
10405d25267dSValentin Clement                               const Fortran::lower::pft::Variable &var,
10415d25267dSValentin Clement                               Fortran::lower::SymMap &symMap) {
10425d25267dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
10435d25267dSValentin Clement   const Fortran::semantics::Symbol &varSym = var.getSymbol();
10445d25267dSValentin Clement   mlir::Location loc = converter.genLocation(varSym.name());
10455d25267dSValentin Clement 
10465d25267dSValentin Clement   mlir::Value commonAddr;
10475d25267dSValentin Clement   if (Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(common))
10485d25267dSValentin Clement     commonAddr = symBox.getAddr();
10495d25267dSValentin Clement   if (!commonAddr) {
10505d25267dSValentin Clement     // introduce a local AddrOf and add it to the map
10512c8cb9acSJean Perier     fir::GlobalOp global = getCommonBlockGlobal(converter, common);
10525d25267dSValentin Clement     commonAddr = builder.create<fir::AddrOfOp>(loc, global.resultType(),
10535d25267dSValentin Clement                                                global.getSymbol());
10545d25267dSValentin Clement 
10555d25267dSValentin Clement     symMap.addSymbol(common, commonAddr);
10565d25267dSValentin Clement   }
10575d25267dSValentin Clement   std::size_t byteOffset = varSym.GetUltimate().offset();
10585d25267dSValentin Clement   mlir::IntegerType i8Ty = builder.getIntegerType(8);
10595d25267dSValentin Clement   mlir::Type i8Ptr = builder.getRefType(i8Ty);
10605d25267dSValentin Clement   mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(i8Ty));
10615d25267dSValentin Clement   mlir::Value base = builder.createConvert(loc, seqTy, commonAddr);
10625d25267dSValentin Clement   mlir::Value offs =
10635d25267dSValentin Clement       builder.createIntegerConstant(loc, builder.getIndexType(), byteOffset);
10645d25267dSValentin Clement   auto varAddr = builder.create<fir::CoordinateOp>(loc, i8Ptr, base,
10655d25267dSValentin Clement                                                    mlir::ValueRange{offs});
10665d25267dSValentin Clement   mlir::Type symType = converter.genType(var.getSymbol());
10675d25267dSValentin Clement   mlir::Value local;
10685d25267dSValentin Clement   if (Fortran::semantics::FindEquivalenceSet(var.getSymbol()) != nullptr)
10695d25267dSValentin Clement     local = castAliasToPointer(builder, loc, symType, varAddr);
10705d25267dSValentin Clement   else
10715d25267dSValentin Clement     local = builder.createConvert(loc, builder.getRefType(symType), varAddr);
10725d25267dSValentin Clement   Fortran::lower::StatementContext stmtCtx;
10735d25267dSValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx, local);
10745d25267dSValentin Clement }
10755d25267dSValentin Clement 
10765d25267dSValentin Clement //===--------------------------------------------------------------===//
10775d25267dSValentin Clement // Lower Variables specification expressions and attributes
10785d25267dSValentin Clement //===--------------------------------------------------------------===//
10795d25267dSValentin Clement 
10802a59ead1SValentin Clement /// Helper to decide if a dummy argument must be tracked in an BoxValue.
lowerToBoxValue(const Fortran::semantics::Symbol & sym,mlir::Value dummyArg)10812a59ead1SValentin Clement static bool lowerToBoxValue(const Fortran::semantics::Symbol &sym,
10822a59ead1SValentin Clement                             mlir::Value dummyArg) {
10832a59ead1SValentin Clement   // Only dummy arguments coming as fir.box can be tracked in an BoxValue.
10842a59ead1SValentin Clement   if (!dummyArg || !dummyArg.getType().isa<fir::BoxType>())
10852a59ead1SValentin Clement     return false;
10862a59ead1SValentin Clement   // Non contiguous arrays must be tracked in an BoxValue.
10872a59ead1SValentin Clement   if (sym.Rank() > 0 && !sym.attrs().test(Fortran::semantics::Attr::CONTIGUOUS))
10882a59ead1SValentin Clement     return true;
10892a59ead1SValentin Clement   // Assumed rank and optional fir.box cannot yet be read while lowering the
10902a59ead1SValentin Clement   // specifications.
10912a59ead1SValentin Clement   if (Fortran::evaluate::IsAssumedRank(sym) ||
10922a59ead1SValentin Clement       Fortran::semantics::IsOptional(sym))
10932a59ead1SValentin Clement     return true;
10942a59ead1SValentin Clement   // Polymorphic entity should be tracked through a fir.box that has the
10952a59ead1SValentin Clement   // dynamic type info.
10962a59ead1SValentin Clement   if (const Fortran::semantics::DeclTypeSpec *type = sym.GetType())
10972a59ead1SValentin Clement     if (type->IsPolymorphic())
10982a59ead1SValentin Clement       return true;
10992a59ead1SValentin Clement   return false;
11002a59ead1SValentin Clement }
11012a59ead1SValentin Clement 
11022a59ead1SValentin Clement /// Compute extent from lower and upper bound.
computeExtent(fir::FirOpBuilder & builder,mlir::Location loc,mlir::Value lb,mlir::Value ub)11032a59ead1SValentin Clement static mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc,
11042a59ead1SValentin Clement                                  mlir::Value lb, mlir::Value ub) {
11052a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
11062a59ead1SValentin Clement   // Let the folder deal with the common `ub - <const> + 1` case.
11072a59ead1SValentin Clement   auto diff = builder.create<mlir::arith::SubIOp>(loc, idxTy, ub, lb);
11082a59ead1SValentin Clement   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
11095bc9ee1bSJean Perier   auto rawExtent = builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one);
1110d91735b5SjeanPerier   return fir::factory::genMaxWithZero(builder, loc, rawExtent);
11112a59ead1SValentin Clement }
11122a59ead1SValentin Clement 
11132a59ead1SValentin Clement /// Lower explicit lower bounds into \p result. Does nothing if this is not an
11142a59ead1SValentin Clement /// array, or if the lower bounds are deferred, or all implicit or one.
lowerExplicitLowerBounds(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::lower::BoxAnalyzer & box,llvm::SmallVectorImpl<mlir::Value> & result,Fortran::lower::SymMap & symMap,Fortran::lower::StatementContext & stmtCtx)11152a59ead1SValentin Clement static void lowerExplicitLowerBounds(
11162a59ead1SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
11172a59ead1SValentin Clement     const Fortran::lower::BoxAnalyzer &box,
11182a59ead1SValentin Clement     llvm::SmallVectorImpl<mlir::Value> &result, Fortran::lower::SymMap &symMap,
11192a59ead1SValentin Clement     Fortran::lower::StatementContext &stmtCtx) {
11202a59ead1SValentin Clement   if (!box.isArray() || box.lboundIsAllOnes())
11212a59ead1SValentin Clement     return;
11222a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
11232a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
11242a59ead1SValentin Clement   if (box.isStaticArray()) {
11252a59ead1SValentin Clement     for (int64_t lb : box.staticLBound())
11262a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, lb));
11272a59ead1SValentin Clement     return;
11282a59ead1SValentin Clement   }
11292a59ead1SValentin Clement   for (const Fortran::semantics::ShapeSpec *spec : box.dynamicBound()) {
11302a59ead1SValentin Clement     if (auto low = spec->lbound().GetExplicit()) {
11312a59ead1SValentin Clement       auto expr = Fortran::lower::SomeExpr{*low};
11322a59ead1SValentin Clement       mlir::Value lb = builder.createConvert(
11332a59ead1SValentin Clement           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
11342a59ead1SValentin Clement       result.emplace_back(lb);
11352a59ead1SValentin Clement     }
11362a59ead1SValentin Clement   }
11372a59ead1SValentin Clement   assert(result.empty() || result.size() == box.dynamicBound().size());
11382a59ead1SValentin Clement }
11392a59ead1SValentin Clement 
11402a59ead1SValentin Clement /// Lower explicit extents into \p result if this is an explicit-shape or
11412a59ead1SValentin Clement /// assumed-size array. Does nothing if this is not an explicit-shape or
11422a59ead1SValentin Clement /// assumed-size array.
11435bc9ee1bSJean Perier static void
lowerExplicitExtents(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::lower::BoxAnalyzer & box,llvm::SmallVectorImpl<mlir::Value> & lowerBounds,llvm::SmallVectorImpl<mlir::Value> & result,Fortran::lower::SymMap & symMap,Fortran::lower::StatementContext & stmtCtx)11445bc9ee1bSJean Perier lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
11455bc9ee1bSJean Perier                      mlir::Location loc, const Fortran::lower::BoxAnalyzer &box,
11465bc9ee1bSJean Perier                      llvm::SmallVectorImpl<mlir::Value> &lowerBounds,
11472a59ead1SValentin Clement                      llvm::SmallVectorImpl<mlir::Value> &result,
11482a59ead1SValentin Clement                      Fortran::lower::SymMap &symMap,
11492a59ead1SValentin Clement                      Fortran::lower::StatementContext &stmtCtx) {
11502a59ead1SValentin Clement   if (!box.isArray())
11512a59ead1SValentin Clement     return;
11522a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
11532a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
11542a59ead1SValentin Clement   if (box.isStaticArray()) {
11552a59ead1SValentin Clement     for (int64_t extent : box.staticShape())
11562a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, extent));
11572a59ead1SValentin Clement     return;
11582a59ead1SValentin Clement   }
11592a59ead1SValentin Clement   for (const auto &spec : llvm::enumerate(box.dynamicBound())) {
11602a59ead1SValentin Clement     if (auto up = spec.value()->ubound().GetExplicit()) {
11612a59ead1SValentin Clement       auto expr = Fortran::lower::SomeExpr{*up};
11622a59ead1SValentin Clement       mlir::Value ub = builder.createConvert(
11632a59ead1SValentin Clement           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
11642a59ead1SValentin Clement       if (lowerBounds.empty())
1165d91735b5SjeanPerier         result.emplace_back(fir::factory::genMaxWithZero(builder, loc, ub));
11662a59ead1SValentin Clement       else
11672a59ead1SValentin Clement         result.emplace_back(
11682a59ead1SValentin Clement             computeExtent(builder, loc, lowerBounds[spec.index()], ub));
11692a59ead1SValentin Clement     } else if (spec.value()->ubound().isStar()) {
11702a59ead1SValentin Clement       // Assumed extent is undefined. Must be provided by user's code.
11712a59ead1SValentin Clement       result.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
11722a59ead1SValentin Clement     }
11732a59ead1SValentin Clement   }
11742a59ead1SValentin Clement   assert(result.empty() || result.size() == box.dynamicBound().size());
11752a59ead1SValentin Clement }
11762a59ead1SValentin Clement 
117796d9df41SValentin Clement /// Lower explicit character length if any. Return empty mlir::Value if no
117896d9df41SValentin Clement /// explicit length.
117996d9df41SValentin Clement static mlir::Value
lowerExplicitCharLen(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::lower::BoxAnalyzer & box,Fortran::lower::SymMap & symMap,Fortran::lower::StatementContext & stmtCtx)118096d9df41SValentin Clement lowerExplicitCharLen(Fortran::lower::AbstractConverter &converter,
118196d9df41SValentin Clement                      mlir::Location loc, const Fortran::lower::BoxAnalyzer &box,
118296d9df41SValentin Clement                      Fortran::lower::SymMap &symMap,
118396d9df41SValentin Clement                      Fortran::lower::StatementContext &stmtCtx) {
118496d9df41SValentin Clement   if (!box.isChar())
118596d9df41SValentin Clement     return mlir::Value{};
118696d9df41SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
118796d9df41SValentin Clement   mlir::Type lenTy = builder.getCharacterLengthType();
118896d9df41SValentin Clement   if (llvm::Optional<int64_t> len = box.getCharLenConst())
118996d9df41SValentin Clement     return builder.createIntegerConstant(loc, lenTy, *len);
119096d9df41SValentin Clement   if (llvm::Optional<Fortran::lower::SomeExpr> lenExpr = box.getCharLenExpr())
1191fe252f8eSValentin Clement     // If the length expression is negative, the length is zero. See F2018
1192fe252f8eSValentin Clement     // 7.4.4.2 point 5.
1193d91735b5SjeanPerier     return fir::factory::genMaxWithZero(
1194fe252f8eSValentin Clement         builder, loc,
1195fe252f8eSValentin Clement         genScalarValue(converter, loc, *lenExpr, symMap, stmtCtx));
119696d9df41SValentin Clement   return mlir::Value{};
119796d9df41SValentin Clement }
119896d9df41SValentin Clement 
11992a59ead1SValentin Clement /// Treat negative values as undefined. Assumed size arrays will return -1 from
12002a59ead1SValentin Clement /// the front end for example. Using negative values can produce hard to find
12012a59ead1SValentin Clement /// bugs much further along in the compilation.
genExtentValue(fir::FirOpBuilder & builder,mlir::Location loc,mlir::Type idxTy,long frontEndExtent)12022a59ead1SValentin Clement static mlir::Value genExtentValue(fir::FirOpBuilder &builder,
12032a59ead1SValentin Clement                                   mlir::Location loc, mlir::Type idxTy,
12042a59ead1SValentin Clement                                   long frontEndExtent) {
12052a59ead1SValentin Clement   if (frontEndExtent >= 0)
12062a59ead1SValentin Clement     return builder.createIntegerConstant(loc, idxTy, frontEndExtent);
12072a59ead1SValentin Clement   return builder.create<fir::UndefOp>(loc, idxTy);
12082a59ead1SValentin Clement }
12092a59ead1SValentin Clement 
1210411f839aSValentin Clement /// If a symbol is an array, it may have been declared with unknown extent
1211411f839aSValentin Clement /// parameters (e.g., `*`), but if it has an initial value then the actual size
1212411f839aSValentin Clement /// may be available from the initial array value's type.
1213411f839aSValentin Clement inline static llvm::SmallVector<std::int64_t>
recoverShapeVector(llvm::ArrayRef<std::int64_t> shapeVec,mlir::Value initVal)1214411f839aSValentin Clement recoverShapeVector(llvm::ArrayRef<std::int64_t> shapeVec, mlir::Value initVal) {
1215411f839aSValentin Clement   llvm::SmallVector<std::int64_t> result;
1216411f839aSValentin Clement   if (initVal) {
1217411f839aSValentin Clement     if (auto seqTy = fir::unwrapUntilSeqType(initVal.getType())) {
1218411f839aSValentin Clement       for (auto [fst, snd] : llvm::zip(shapeVec, seqTy.getShape()))
1219411f839aSValentin Clement         result.push_back(fst == fir::SequenceType::getUnknownExtent() ? snd
1220411f839aSValentin Clement                                                                       : fst);
1221411f839aSValentin Clement       return result;
1222411f839aSValentin Clement     }
1223411f839aSValentin Clement   }
1224411f839aSValentin Clement   result.assign(shapeVec.begin(), shapeVec.end());
1225411f839aSValentin Clement   return result;
1226411f839aSValentin Clement }
1227411f839aSValentin Clement 
12282a59ead1SValentin Clement /// Lower specification expressions and attributes of variable \p var and
12291e1f60c6SV Donaldson /// add it to the symbol map.  For a global or an alias, the address must be
12301e1f60c6SV Donaldson /// pre-computed and provided in \p preAlloc.  A dummy argument for the current
12311e1f60c6SV Donaldson /// entry point has already been mapped to an mlir block argument in
12321e1f60c6SV Donaldson /// mapDummiesAndResults.  Its mapping may be updated here.
mapSymbolAttributes(AbstractConverter & converter,const Fortran::lower::pft::Variable & var,Fortran::lower::SymMap & symMap,Fortran::lower::StatementContext & stmtCtx,mlir::Value preAlloc)12332a59ead1SValentin Clement void Fortran::lower::mapSymbolAttributes(
12342a59ead1SValentin Clement     AbstractConverter &converter, const Fortran::lower::pft::Variable &var,
12352a59ead1SValentin Clement     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
12362a59ead1SValentin Clement     mlir::Value preAlloc) {
12372a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
12382c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
1239*53804e42SValentin Clement   const mlir::Location loc = genLocation(converter, sym);
12402a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
12411e1f60c6SV Donaldson   const bool isDeclaredDummy = Fortran::semantics::IsDummy(sym);
12421e1f60c6SV Donaldson   // An active dummy from the current entry point.
12431e1f60c6SV Donaldson   const bool isDummy = isDeclaredDummy && symMap.lookupSymbol(sym).getAddr();
12441e1f60c6SV Donaldson   // An unused dummy from another entry point.
12451e1f60c6SV Donaldson   const bool isUnusedEntryDummy = isDeclaredDummy && !isDummy;
1246da7c77b8SValentin Clement   const bool isResult = Fortran::semantics::IsFunctionResult(sym);
12472a59ead1SValentin Clement   const bool replace = isDummy || isResult;
12482a59ead1SValentin Clement   fir::factory::CharacterExprHelper charHelp{builder, loc};
12491e1f60c6SV Donaldson 
12501e1f60c6SV Donaldson   if (Fortran::semantics::IsProcedure(sym)) {
12511e1f60c6SV Donaldson     if (isUnusedEntryDummy) {
12521e1f60c6SV Donaldson       // Additional discussion below.
12531e1f60c6SV Donaldson       mlir::Type dummyProcType =
12541e1f60c6SV Donaldson           Fortran::lower::getDummyProcedureType(sym, converter);
12551e1f60c6SV Donaldson       mlir::Value undefOp = builder.create<fir::UndefOp>(loc, dummyProcType);
12561e1f60c6SV Donaldson       symMap.addSymbol(sym, undefOp);
12571e1f60c6SV Donaldson     }
12581e1f60c6SV Donaldson     if (Fortran::semantics::IsPointer(sym))
12591e1f60c6SV Donaldson       TODO(loc, "procedure pointers");
12601e1f60c6SV Donaldson     return;
12611e1f60c6SV Donaldson   }
12621e1f60c6SV Donaldson 
12632a59ead1SValentin Clement   Fortran::lower::BoxAnalyzer ba;
12642a59ead1SValentin Clement   ba.analyze(sym);
1265da7c77b8SValentin Clement 
12661e1f60c6SV Donaldson   // First deal with pointers and allocatables, because their handling here
12672a59ead1SValentin Clement   // is the same regardless of their rank.
12682a59ead1SValentin Clement   if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
12692a59ead1SValentin Clement     // Get address of fir.box describing the entity.
12702a59ead1SValentin Clement     // global
12712a59ead1SValentin Clement     mlir::Value boxAlloc = preAlloc;
12722a59ead1SValentin Clement     // dummy or passed result
12732a59ead1SValentin Clement     if (!boxAlloc)
12742a59ead1SValentin Clement       if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
12752a59ead1SValentin Clement         boxAlloc = symbox.getAddr();
12762a59ead1SValentin Clement     // local
12772a59ead1SValentin Clement     if (!boxAlloc)
12782a59ead1SValentin Clement       boxAlloc = createNewLocal(converter, loc, var, preAlloc);
12792a59ead1SValentin Clement     // Lower non deferred parameters.
12802a59ead1SValentin Clement     llvm::SmallVector<mlir::Value> nonDeferredLenParams;
12812a59ead1SValentin Clement     if (ba.isChar()) {
128296d9df41SValentin Clement       if (mlir::Value len =
128396d9df41SValentin Clement               lowerExplicitCharLen(converter, loc, ba, symMap, stmtCtx))
128496d9df41SValentin Clement         nonDeferredLenParams.push_back(len);
128596d9df41SValentin Clement       else if (Fortran::semantics::IsAssumedLengthCharacter(sym))
128696d9df41SValentin Clement         TODO(loc, "assumed length character allocatable");
12872a59ead1SValentin Clement     } else if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) {
12882a59ead1SValentin Clement       if (const Fortran::semantics::DerivedTypeSpec *derived =
12892a59ead1SValentin Clement               declTy->AsDerived())
12902a59ead1SValentin Clement         if (Fortran::semantics::CountLenParameters(*derived) != 0)
12912a59ead1SValentin Clement           TODO(loc,
12922a59ead1SValentin Clement                "derived type allocatable or pointer with length parameters");
12932a59ead1SValentin Clement     }
12942a59ead1SValentin Clement     fir::MutableBoxValue box = Fortran::lower::createMutableBox(
12952a59ead1SValentin Clement         converter, loc, var, boxAlloc, nonDeferredLenParams);
12962a59ead1SValentin Clement     symMap.addAllocatableOrPointer(var.getSymbol(), box, replace);
12972a59ead1SValentin Clement     return;
12982a59ead1SValentin Clement   }
12992a59ead1SValentin Clement 
13002a59ead1SValentin Clement   if (isDummy) {
13012a59ead1SValentin Clement     mlir::Value dummyArg = symMap.lookupSymbol(sym).getAddr();
13022a59ead1SValentin Clement     if (lowerToBoxValue(sym, dummyArg)) {
13032a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> lbounds;
13045bc9ee1bSJean Perier       llvm::SmallVector<mlir::Value> explicitExtents;
13052a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> explicitParams;
13062a59ead1SValentin Clement       // Lower lower bounds, explicit type parameters and explicit
13072a59ead1SValentin Clement       // extents if any.
13082a59ead1SValentin Clement       if (ba.isChar())
130980f8c6ddSValentin Clement         if (mlir::Value len =
131080f8c6ddSValentin Clement                 lowerExplicitCharLen(converter, loc, ba, symMap, stmtCtx))
131180f8c6ddSValentin Clement           explicitParams.push_back(len);
13122a59ead1SValentin Clement       // TODO: derived type length parameters.
13132a59ead1SValentin Clement       lowerExplicitLowerBounds(converter, loc, ba, lbounds, symMap, stmtCtx);
13145bc9ee1bSJean Perier       lowerExplicitExtents(converter, loc, ba, lbounds, explicitExtents, symMap,
13152a59ead1SValentin Clement                            stmtCtx);
13165bc9ee1bSJean Perier       symMap.addBoxSymbol(sym, dummyArg, lbounds, explicitParams,
13175bc9ee1bSJean Perier                           explicitExtents, replace);
13182a59ead1SValentin Clement       return;
13192a59ead1SValentin Clement     }
13202a59ead1SValentin Clement   }
13212a59ead1SValentin Clement 
13221e1f60c6SV Donaldson   // A dummy from another entry point that is not declared in the current
13231e1f60c6SV Donaldson   // entry point requires a skeleton definition.  Most such "unused" dummies
13241e1f60c6SV Donaldson   // will not survive into final generated code, but some will.  It is illegal
13251e1f60c6SV Donaldson   // to reference one at run time if it does.  Such a dummy is mapped to a
13261e1f60c6SV Donaldson   // value in one of three ways:
13271e1f60c6SV Donaldson   //
13281e1f60c6SV Donaldson   //  - Generate a fir::UndefOp value.  This is lightweight, easy to clean up,
13291e1f60c6SV Donaldson   //    and often valid, but it may fail for a dummy with dynamic bounds,
13301e1f60c6SV Donaldson   //    or a dummy used to define another dummy.  Information to distinguish
13311e1f60c6SV Donaldson   //    valid cases is not generally available here, with the exception of
13321e1f60c6SV Donaldson   //    dummy procedures.  See the first function exit above.
13331e1f60c6SV Donaldson   //
13341e1f60c6SV Donaldson   //  - Allocate an uninitialized stack slot.  This is an intermediate-weight
13351e1f60c6SV Donaldson   //    solution that is harder to clean up.  It is often valid, but may fail
13361e1f60c6SV Donaldson   //    for an object with dynamic bounds.  This option is "automatically"
13371e1f60c6SV Donaldson   //    used by default for cases that do not use one of the other options.
13381e1f60c6SV Donaldson   //
13391e1f60c6SV Donaldson   //  - Allocate a heap box/descriptor, initialized to zero.  This always
13401e1f60c6SV Donaldson   //    works, but is more heavyweight and harder to clean up.  It is used
13411e1f60c6SV Donaldson   //    for dynamic objects via calls to genUnusedEntryPointBox.
13421e1f60c6SV Donaldson 
13431e1f60c6SV Donaldson   auto genUnusedEntryPointBox = [&]() {
13441e1f60c6SV Donaldson     if (isUnusedEntryDummy) {
13451e1f60c6SV Donaldson       assert(!Fortran::semantics::IsAllocatableOrPointer(sym) &&
13461e1f60c6SV Donaldson              "handled above");
13471e1f60c6SV Donaldson       // The box is read right away because lowering code does not expect
13481e1f60c6SV Donaldson       // a non pointer/allocatable symbol to be mapped to a MutableBox.
13491e1f60c6SV Donaldson       symMap.addSymbol(sym, fir::factory::genMutableBoxRead(
13501e1f60c6SV Donaldson                                 builder, loc,
13511e1f60c6SV Donaldson                                 fir::factory::createTempMutableBox(
13521e1f60c6SV Donaldson                                     builder, loc, converter.genType(var))));
13531e1f60c6SV Donaldson       return true;
13541e1f60c6SV Donaldson     }
13551e1f60c6SV Donaldson     return false;
13561e1f60c6SV Donaldson   };
13571e1f60c6SV Donaldson 
1358d88dfd2bSValentin Clement   // Helper to generate scalars for the symbol properties.
1359d88dfd2bSValentin Clement   auto genValue = [&](const Fortran::lower::SomeExpr &expr) {
1360d88dfd2bSValentin Clement     return genScalarValue(converter, loc, expr, symMap, stmtCtx);
1361d88dfd2bSValentin Clement   };
1362d88dfd2bSValentin Clement 
1363d88dfd2bSValentin Clement   // For symbols reaching this point, all properties are constant and can be
1364d88dfd2bSValentin Clement   // read/computed already into ssa values.
1365d88dfd2bSValentin Clement 
1366d88dfd2bSValentin Clement   // The origin must be \vec{1}.
1367d88dfd2bSValentin Clement   auto populateShape = [&](auto &shapes, const auto &bounds, mlir::Value box) {
1368d88dfd2bSValentin Clement     for (auto iter : llvm::enumerate(bounds)) {
1369d88dfd2bSValentin Clement       auto *spec = iter.value();
1370d88dfd2bSValentin Clement       assert(spec->lbound().GetExplicit() &&
1371d88dfd2bSValentin Clement              "lbound must be explicit with constant value 1");
1372d88dfd2bSValentin Clement       if (auto high = spec->ubound().GetExplicit()) {
1373d88dfd2bSValentin Clement         Fortran::lower::SomeExpr highEx{*high};
1374d88dfd2bSValentin Clement         mlir::Value ub = genValue(highEx);
13755bc9ee1bSJean Perier         ub = builder.createConvert(loc, idxTy, ub);
1376d91735b5SjeanPerier         shapes.emplace_back(fir::factory::genMaxWithZero(builder, loc, ub));
1377d88dfd2bSValentin Clement       } else if (spec->ubound().isColon()) {
1378d88dfd2bSValentin Clement         assert(box && "assumed bounds require a descriptor");
1379d88dfd2bSValentin Clement         mlir::Value dim =
1380d88dfd2bSValentin Clement             builder.createIntegerConstant(loc, idxTy, iter.index());
1381d88dfd2bSValentin Clement         auto dimInfo =
1382d88dfd2bSValentin Clement             builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
1383d88dfd2bSValentin Clement         shapes.emplace_back(dimInfo.getResult(1));
1384d88dfd2bSValentin Clement       } else if (spec->ubound().isStar()) {
1385d88dfd2bSValentin Clement         shapes.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
1386d88dfd2bSValentin Clement       } else {
1387d88dfd2bSValentin Clement         llvm::report_fatal_error("unknown bound category");
1388d88dfd2bSValentin Clement       }
1389d88dfd2bSValentin Clement     }
1390d88dfd2bSValentin Clement   };
1391d88dfd2bSValentin Clement 
1392d88dfd2bSValentin Clement   // The origin is not \vec{1}.
1393d88dfd2bSValentin Clement   auto populateLBoundsExtents = [&](auto &lbounds, auto &extents,
1394d88dfd2bSValentin Clement                                     const auto &bounds, mlir::Value box) {
1395d88dfd2bSValentin Clement     for (auto iter : llvm::enumerate(bounds)) {
1396d88dfd2bSValentin Clement       auto *spec = iter.value();
1397d88dfd2bSValentin Clement       fir::BoxDimsOp dimInfo;
1398d88dfd2bSValentin Clement       mlir::Value ub, lb;
1399d88dfd2bSValentin Clement       if (spec->lbound().isColon() || spec->ubound().isColon()) {
1400d88dfd2bSValentin Clement         // This is an assumed shape because allocatables and pointers extents
1401d88dfd2bSValentin Clement         // are not constant in the scope and are not read here.
1402d88dfd2bSValentin Clement         assert(box && "deferred bounds require a descriptor");
1403d88dfd2bSValentin Clement         mlir::Value dim =
1404d88dfd2bSValentin Clement             builder.createIntegerConstant(loc, idxTy, iter.index());
1405d88dfd2bSValentin Clement         dimInfo =
1406d88dfd2bSValentin Clement             builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
1407d88dfd2bSValentin Clement         extents.emplace_back(dimInfo.getResult(1));
1408d88dfd2bSValentin Clement         if (auto low = spec->lbound().GetExplicit()) {
1409d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*low};
1410d88dfd2bSValentin Clement           mlir::Value lb = builder.createConvert(loc, idxTy, genValue(expr));
1411d88dfd2bSValentin Clement           lbounds.emplace_back(lb);
1412d88dfd2bSValentin Clement         } else {
1413d88dfd2bSValentin Clement           // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
1414d88dfd2bSValentin Clement           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, 1));
1415d88dfd2bSValentin Clement         }
1416d88dfd2bSValentin Clement       } else {
1417d88dfd2bSValentin Clement         if (auto low = spec->lbound().GetExplicit()) {
1418d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*low};
1419d88dfd2bSValentin Clement           lb = builder.createConvert(loc, idxTy, genValue(expr));
1420d88dfd2bSValentin Clement         } else {
142139377d52SValentin Clement           TODO(loc, "support for assumed rank entities");
1422d88dfd2bSValentin Clement         }
14235bc9ee1bSJean Perier         lbounds.emplace_back(lb);
1424d88dfd2bSValentin Clement 
1425d88dfd2bSValentin Clement         if (auto high = spec->ubound().GetExplicit()) {
1426d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*high};
1427d88dfd2bSValentin Clement           ub = builder.createConvert(loc, idxTy, genValue(expr));
1428d88dfd2bSValentin Clement           extents.emplace_back(computeExtent(builder, loc, lb, ub));
1429d88dfd2bSValentin Clement         } else {
1430d88dfd2bSValentin Clement           // An assumed size array. The extent is not computed.
1431d88dfd2bSValentin Clement           assert(spec->ubound().isStar() && "expected assumed size");
1432d88dfd2bSValentin Clement           extents.emplace_back(builder.create<fir::UndefOp>(loc, idxTy));
1433d88dfd2bSValentin Clement         }
1434d88dfd2bSValentin Clement       }
1435d88dfd2bSValentin Clement     }
1436d88dfd2bSValentin Clement   };
1437d88dfd2bSValentin Clement 
1438859d4a18SValentin Clement   // Lower length expression for non deferred and non dummy assumed length
1439859d4a18SValentin Clement   // characters.
1440859d4a18SValentin Clement   auto genExplicitCharLen =
1441859d4a18SValentin Clement       [&](llvm::Optional<Fortran::lower::SomeExpr> charLen) -> mlir::Value {
1442859d4a18SValentin Clement     if (!charLen)
1443859d4a18SValentin Clement       fir::emitFatalError(loc, "expected explicit character length");
1444859d4a18SValentin Clement     mlir::Value rawLen = genValue(*charLen);
1445859d4a18SValentin Clement     // If the length expression is negative, the length is zero. See
1446859d4a18SValentin Clement     // F2018 7.4.4.2 point 5.
1447d91735b5SjeanPerier     return fir::factory::genMaxWithZero(builder, loc, rawLen);
1448859d4a18SValentin Clement   };
14492a59ead1SValentin Clement 
14502a59ead1SValentin Clement   ba.match(
14512a59ead1SValentin Clement       //===--------------------------------------------------------------===//
14522a59ead1SValentin Clement       // Trivial case.
14532a59ead1SValentin Clement       //===--------------------------------------------------------------===//
14542a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarSym &) {
1455da7c77b8SValentin Clement         if (isDummy) {
1456da7c77b8SValentin Clement           // This is an argument.
1457da7c77b8SValentin Clement           if (!symMap.lookupSymbol(sym))
1458da7c77b8SValentin Clement             mlir::emitError(loc, "symbol \"")
1459da7c77b8SValentin Clement                 << toStringRef(sym.name()) << "\" must already be in map";
1460da7c77b8SValentin Clement           return;
1461da7c77b8SValentin Clement         } else if (isResult) {
1462da7c77b8SValentin Clement           // Some Fortran results may be passed by argument (e.g. derived
1463da7c77b8SValentin Clement           // types)
1464da7c77b8SValentin Clement           if (symMap.lookupSymbol(sym))
1465da7c77b8SValentin Clement             return;
1466da7c77b8SValentin Clement         }
1467da7c77b8SValentin Clement         // Otherwise, it's a local variable or function result.
14682a59ead1SValentin Clement         mlir::Value local = createNewLocal(converter, loc, var, preAlloc);
14692c2e5a5dSValentin Clement         symMap.addSymbol(sym, local);
14702a59ead1SValentin Clement       },
14712a59ead1SValentin Clement 
14722a59ead1SValentin Clement       //===--------------------------------------------------------------===//
14732a59ead1SValentin Clement       // The non-trivial cases are when we have an argument or local that has
14742a59ead1SValentin Clement       // a repetition value. Arguments might be passed as simple pointers and
14752a59ead1SValentin Clement       // need to be cast to a multi-dimensional array with constant bounds
14762a59ead1SValentin Clement       // (possibly with a missing column), bounds computed in the callee
14772a59ead1SValentin Clement       // (here), or with bounds from the caller (boxed somewhere else). Locals
14782a59ead1SValentin Clement       // have the same properties except they are never boxed arguments from
14792a59ead1SValentin Clement       // the caller and never having a missing column size.
14802a59ead1SValentin Clement       //===--------------------------------------------------------------===//
14812a59ead1SValentin Clement 
14822a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarStaticChar &x) {
148337e84d9bSValentin Clement         // type is a CHARACTER, determine the LEN value
148437e84d9bSValentin Clement         auto charLen = x.charLen();
148537e84d9bSValentin Clement         if (replace) {
148637e84d9bSValentin Clement           Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym);
148737e84d9bSValentin Clement           std::pair<mlir::Value, mlir::Value> unboxchar =
148837e84d9bSValentin Clement               charHelp.createUnboxChar(symBox.getAddr());
148937e84d9bSValentin Clement           mlir::Value boxAddr = unboxchar.first;
149037e84d9bSValentin Clement           // Set/override LEN with a constant
149137e84d9bSValentin Clement           mlir::Value len = builder.createIntegerConstant(loc, idxTy, charLen);
149237e84d9bSValentin Clement           symMap.addCharSymbol(sym, boxAddr, len, true);
149337e84d9bSValentin Clement           return;
149437e84d9bSValentin Clement         }
149537e84d9bSValentin Clement         mlir::Value len = builder.createIntegerConstant(loc, idxTy, charLen);
149637e84d9bSValentin Clement         if (preAlloc) {
149737e84d9bSValentin Clement           symMap.addCharSymbol(sym, preAlloc, len);
149837e84d9bSValentin Clement           return;
149937e84d9bSValentin Clement         }
150037e84d9bSValentin Clement         mlir::Value local = createNewLocal(converter, loc, var, preAlloc);
150137e84d9bSValentin Clement         symMap.addCharSymbol(sym, local, len);
15022a59ead1SValentin Clement       },
15032a59ead1SValentin Clement 
15042a59ead1SValentin Clement       //===--------------------------------------------------------------===//
15052a59ead1SValentin Clement 
15062a59ead1SValentin Clement       [&](const Fortran::lower::details::ScalarDynamicChar &x) {
15071e1f60c6SV Donaldson         if (genUnusedEntryPointBox())
15081e1f60c6SV Donaldson           return;
1509764f95a8SValentin Clement         // type is a CHARACTER, determine the LEN value
1510764f95a8SValentin Clement         auto charLen = x.charLen();
1511764f95a8SValentin Clement         if (replace) {
1512764f95a8SValentin Clement           Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym);
1513764f95a8SValentin Clement           mlir::Value boxAddr = symBox.getAddr();
1514764f95a8SValentin Clement           mlir::Value len;
1515764f95a8SValentin Clement           mlir::Type addrTy = boxAddr.getType();
15161e1f60c6SV Donaldson           if (addrTy.isa<fir::BoxCharType>() || addrTy.isa<fir::BoxType>())
1517764f95a8SValentin Clement             std::tie(boxAddr, len) = charHelp.createUnboxChar(symBox.getAddr());
1518764f95a8SValentin Clement           // Override LEN with an expression
1519764f95a8SValentin Clement           if (charLen)
1520764f95a8SValentin Clement             len = genExplicitCharLen(charLen);
1521764f95a8SValentin Clement           symMap.addCharSymbol(sym, boxAddr, len, true);
1522764f95a8SValentin Clement           return;
1523764f95a8SValentin Clement         }
1524764f95a8SValentin Clement         // local CHARACTER variable
1525764f95a8SValentin Clement         mlir::Value len = genExplicitCharLen(charLen);
1526764f95a8SValentin Clement         if (preAlloc) {
1527764f95a8SValentin Clement           symMap.addCharSymbol(sym, preAlloc, len);
1528764f95a8SValentin Clement           return;
1529764f95a8SValentin Clement         }
1530764f95a8SValentin Clement         llvm::SmallVector<mlir::Value> lengths = {len};
1531764f95a8SValentin Clement         mlir::Value local =
1532764f95a8SValentin Clement             createNewLocal(converter, loc, var, preAlloc, llvm::None, lengths);
1533764f95a8SValentin Clement         symMap.addCharSymbol(sym, local, len);
15342a59ead1SValentin Clement       },
15352a59ead1SValentin Clement 
15362a59ead1SValentin Clement       //===--------------------------------------------------------------===//
15372a59ead1SValentin Clement 
15382a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArray &x) {
15392a59ead1SValentin Clement         // object shape is constant, not a character
15402a59ead1SValentin Clement         mlir::Type castTy = builder.getRefType(converter.genType(var));
15412a59ead1SValentin Clement         mlir::Value addr = symMap.lookupSymbol(sym).getAddr();
15422a59ead1SValentin Clement         if (addr)
15432a59ead1SValentin Clement           addr = builder.createConvert(loc, castTy, addr);
15442a59ead1SValentin Clement         if (x.lboundAllOnes()) {
15452a59ead1SValentin Clement           // if lower bounds are all ones, build simple shaped object
15462a59ead1SValentin Clement           llvm::SmallVector<mlir::Value> shape;
1547411f839aSValentin Clement           for (int64_t i : recoverShapeVector(x.shapes, preAlloc))
15482a59ead1SValentin Clement             shape.push_back(genExtentValue(builder, loc, idxTy, i));
15492a59ead1SValentin Clement           mlir::Value local =
15502a59ead1SValentin Clement               isDummy ? addr : createNewLocal(converter, loc, var, preAlloc);
15512a59ead1SValentin Clement           symMap.addSymbolWithShape(sym, local, shape, isDummy);
15522a59ead1SValentin Clement           return;
15532a59ead1SValentin Clement         }
15542a59ead1SValentin Clement         // If object is an array process the lower bound and extent values by
15552a59ead1SValentin Clement         // constructing constants and populating the lbounds and extents.
15562a59ead1SValentin Clement         llvm::SmallVector<mlir::Value> extents;
15572a59ead1SValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
1558411f839aSValentin Clement         for (auto [fst, snd] :
1559411f839aSValentin Clement              llvm::zip(x.lbounds, recoverShapeVector(x.shapes, preAlloc))) {
15602a59ead1SValentin Clement           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, fst));
15612a59ead1SValentin Clement           extents.emplace_back(genExtentValue(builder, loc, idxTy, snd));
15622a59ead1SValentin Clement         }
15632a59ead1SValentin Clement         mlir::Value local =
15642a59ead1SValentin Clement             isDummy ? addr
15652a59ead1SValentin Clement                     : createNewLocal(converter, loc, var, preAlloc, extents);
1566411f839aSValentin Clement         // Must be a dummy argument, have an explicit shape, or be a PARAMETER.
1567411f839aSValentin Clement         assert(isDummy || Fortran::lower::isExplicitShape(sym) ||
1568411f839aSValentin Clement                Fortran::semantics::IsNamedConstant(sym));
15692a59ead1SValentin Clement         symMap.addSymbolWithBounds(sym, local, extents, lbounds, isDummy);
15702a59ead1SValentin Clement       },
15712a59ead1SValentin Clement 
15722a59ead1SValentin Clement       //===--------------------------------------------------------------===//
15732a59ead1SValentin Clement 
15742a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArray &x) {
15751e1f60c6SV Donaldson         if (genUnusedEntryPointBox())
15761e1f60c6SV Donaldson           return;
1577d88dfd2bSValentin Clement         // cast to the known constant parts from the declaration
1578d88dfd2bSValentin Clement         mlir::Type varType = converter.genType(var);
1579d88dfd2bSValentin Clement         mlir::Value addr = symMap.lookupSymbol(sym).getAddr();
1580d88dfd2bSValentin Clement         mlir::Value argBox;
1581d88dfd2bSValentin Clement         mlir::Type castTy = builder.getRefType(varType);
1582d88dfd2bSValentin Clement         if (addr) {
1583d88dfd2bSValentin Clement           if (auto boxTy = addr.getType().dyn_cast<fir::BoxType>()) {
1584d88dfd2bSValentin Clement             argBox = addr;
1585d88dfd2bSValentin Clement             mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
1586d88dfd2bSValentin Clement             addr = builder.create<fir::BoxAddrOp>(loc, refTy, argBox);
1587d88dfd2bSValentin Clement           }
1588d88dfd2bSValentin Clement           addr = builder.createConvert(loc, castTy, addr);
1589d88dfd2bSValentin Clement         }
1590d88dfd2bSValentin Clement         if (x.lboundAllOnes()) {
1591d88dfd2bSValentin Clement           // if lower bounds are all ones, build simple shaped object
1592d88dfd2bSValentin Clement           llvm::SmallVector<mlir::Value> shapes;
1593d88dfd2bSValentin Clement           populateShape(shapes, x.bounds, argBox);
1594d88dfd2bSValentin Clement           if (isDummy) {
1595d88dfd2bSValentin Clement             symMap.addSymbolWithShape(sym, addr, shapes, true);
1596d88dfd2bSValentin Clement             return;
1597d88dfd2bSValentin Clement           }
1598d88dfd2bSValentin Clement           // local array with computed bounds
1599d88dfd2bSValentin Clement           assert(Fortran::lower::isExplicitShape(sym) ||
1600d88dfd2bSValentin Clement                  Fortran::semantics::IsAllocatableOrPointer(sym));
1601d88dfd2bSValentin Clement           mlir::Value local =
1602d88dfd2bSValentin Clement               createNewLocal(converter, loc, var, preAlloc, shapes);
1603d88dfd2bSValentin Clement           symMap.addSymbolWithShape(sym, local, shapes);
1604d88dfd2bSValentin Clement           return;
1605d88dfd2bSValentin Clement         }
1606d88dfd2bSValentin Clement         // if object is an array process the lower bound and extent values
1607d88dfd2bSValentin Clement         llvm::SmallVector<mlir::Value> extents;
1608d88dfd2bSValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
1609d88dfd2bSValentin Clement         populateLBoundsExtents(lbounds, extents, x.bounds, argBox);
1610d88dfd2bSValentin Clement         if (isDummy) {
1611d88dfd2bSValentin Clement           symMap.addSymbolWithBounds(sym, addr, extents, lbounds, true);
1612d88dfd2bSValentin Clement           return;
1613d88dfd2bSValentin Clement         }
1614d88dfd2bSValentin Clement         // local array with computed bounds
1615d88dfd2bSValentin Clement         assert(Fortran::lower::isExplicitShape(sym));
1616d88dfd2bSValentin Clement         mlir::Value local =
1617d88dfd2bSValentin Clement             createNewLocal(converter, loc, var, preAlloc, extents);
1618d88dfd2bSValentin Clement         symMap.addSymbolWithBounds(sym, local, extents, lbounds);
16192a59ead1SValentin Clement       },
16202a59ead1SValentin Clement 
16212a59ead1SValentin Clement       //===--------------------------------------------------------------===//
16222a59ead1SValentin Clement 
16232a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArrayStaticChar &x) {
1624859d4a18SValentin Clement         // if element type is a CHARACTER, determine the LEN value
1625859d4a18SValentin Clement         auto charLen = x.charLen();
1626859d4a18SValentin Clement         mlir::Value addr;
1627859d4a18SValentin Clement         mlir::Value len;
1628859d4a18SValentin Clement         if (isDummy) {
1629859d4a18SValentin Clement           Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym);
1630859d4a18SValentin Clement           std::pair<mlir::Value, mlir::Value> unboxchar =
1631859d4a18SValentin Clement               charHelp.createUnboxChar(symBox.getAddr());
1632859d4a18SValentin Clement           addr = unboxchar.first;
1633859d4a18SValentin Clement           // Set/override LEN with a constant
1634859d4a18SValentin Clement           len = builder.createIntegerConstant(loc, idxTy, charLen);
1635859d4a18SValentin Clement         } else {
1636859d4a18SValentin Clement           // local CHARACTER variable
1637859d4a18SValentin Clement           len = builder.createIntegerConstant(loc, idxTy, charLen);
1638859d4a18SValentin Clement         }
1639859d4a18SValentin Clement 
1640859d4a18SValentin Clement         // object shape is constant
1641859d4a18SValentin Clement         mlir::Type castTy = builder.getRefType(converter.genType(var));
1642859d4a18SValentin Clement         if (addr)
1643859d4a18SValentin Clement           addr = builder.createConvert(loc, castTy, addr);
1644859d4a18SValentin Clement 
1645859d4a18SValentin Clement         if (x.lboundAllOnes()) {
1646859d4a18SValentin Clement           // if lower bounds are all ones, build simple shaped object
1647859d4a18SValentin Clement           llvm::SmallVector<mlir::Value> shape;
1648411f839aSValentin Clement           for (int64_t i : recoverShapeVector(x.shapes, preAlloc))
1649859d4a18SValentin Clement             shape.push_back(genExtentValue(builder, loc, idxTy, i));
1650859d4a18SValentin Clement           mlir::Value local =
1651859d4a18SValentin Clement               isDummy ? addr : createNewLocal(converter, loc, var, preAlloc);
1652859d4a18SValentin Clement           symMap.addCharSymbolWithShape(sym, local, len, shape, isDummy);
1653859d4a18SValentin Clement           return;
1654859d4a18SValentin Clement         }
1655859d4a18SValentin Clement 
1656859d4a18SValentin Clement         // if object is an array process the lower bound and extent values
1657859d4a18SValentin Clement         llvm::SmallVector<mlir::Value> extents;
1658859d4a18SValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
1659859d4a18SValentin Clement         // construct constants and populate `bounds`
1660411f839aSValentin Clement         for (auto [fst, snd] :
1661411f839aSValentin Clement              llvm::zip(x.lbounds, recoverShapeVector(x.shapes, preAlloc))) {
1662859d4a18SValentin Clement           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, fst));
1663859d4a18SValentin Clement           extents.emplace_back(genExtentValue(builder, loc, idxTy, snd));
1664859d4a18SValentin Clement         }
1665859d4a18SValentin Clement 
1666859d4a18SValentin Clement         if (isDummy) {
1667859d4a18SValentin Clement           symMap.addCharSymbolWithBounds(sym, addr, len, extents, lbounds,
1668859d4a18SValentin Clement                                          true);
1669859d4a18SValentin Clement           return;
1670859d4a18SValentin Clement         }
1671859d4a18SValentin Clement         // local CHARACTER array with computed bounds
1672859d4a18SValentin Clement         assert(Fortran::lower::isExplicitShape(sym));
1673859d4a18SValentin Clement         mlir::Value local =
1674859d4a18SValentin Clement             createNewLocal(converter, loc, var, preAlloc, extents);
1675859d4a18SValentin Clement         symMap.addCharSymbolWithBounds(sym, local, len, extents, lbounds);
16762a59ead1SValentin Clement       },
16772a59ead1SValentin Clement 
16782a59ead1SValentin Clement       //===--------------------------------------------------------------===//
16792a59ead1SValentin Clement 
16802a59ead1SValentin Clement       [&](const Fortran::lower::details::StaticArrayDynamicChar &x) {
16811e1f60c6SV Donaldson         if (genUnusedEntryPointBox())
16821e1f60c6SV Donaldson           return;
1683859d4a18SValentin Clement         mlir::Value addr;
1684859d4a18SValentin Clement         mlir::Value len;
1685859d4a18SValentin Clement         [[maybe_unused]] bool mustBeDummy = false;
1686859d4a18SValentin Clement         auto charLen = x.charLen();
1687859d4a18SValentin Clement         // if element type is a CHARACTER, determine the LEN value
1688859d4a18SValentin Clement         if (isDummy) {
1689859d4a18SValentin Clement           Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym);
1690859d4a18SValentin Clement           std::pair<mlir::Value, mlir::Value> unboxchar =
1691859d4a18SValentin Clement               charHelp.createUnboxChar(symBox.getAddr());
1692859d4a18SValentin Clement           addr = unboxchar.first;
1693859d4a18SValentin Clement           if (charLen) {
1694859d4a18SValentin Clement             // Set/override LEN with an expression
1695859d4a18SValentin Clement             len = genExplicitCharLen(charLen);
1696859d4a18SValentin Clement           } else {
1697859d4a18SValentin Clement             // LEN is from the boxchar
1698859d4a18SValentin Clement             len = unboxchar.second;
1699859d4a18SValentin Clement             mustBeDummy = true;
1700859d4a18SValentin Clement           }
1701859d4a18SValentin Clement         } else {
1702859d4a18SValentin Clement           // local CHARACTER variable
1703859d4a18SValentin Clement           len = genExplicitCharLen(charLen);
1704859d4a18SValentin Clement         }
1705859d4a18SValentin Clement         llvm::SmallVector<mlir::Value> lengths = {len};
1706859d4a18SValentin Clement 
1707859d4a18SValentin Clement         // cast to the known constant parts from the declaration
1708859d4a18SValentin Clement         mlir::Type castTy = builder.getRefType(converter.genType(var));
1709859d4a18SValentin Clement         if (addr)
1710859d4a18SValentin Clement           addr = builder.createConvert(loc, castTy, addr);
1711859d4a18SValentin Clement 
1712859d4a18SValentin Clement         if (x.lboundAllOnes()) {
1713859d4a18SValentin Clement           // if lower bounds are all ones, build simple shaped object
1714859d4a18SValentin Clement           llvm::SmallVector<mlir::Value> shape;
1715411f839aSValentin Clement           for (int64_t i : recoverShapeVector(x.shapes, preAlloc))
1716859d4a18SValentin Clement             shape.push_back(genExtentValue(builder, loc, idxTy, i));
1717859d4a18SValentin Clement           if (isDummy) {
1718859d4a18SValentin Clement             symMap.addCharSymbolWithShape(sym, addr, len, shape, true);
1719859d4a18SValentin Clement             return;
1720859d4a18SValentin Clement           }
1721859d4a18SValentin Clement           // local CHARACTER array with constant size
1722859d4a18SValentin Clement           mlir::Value local = createNewLocal(converter, loc, var, preAlloc,
1723859d4a18SValentin Clement                                              llvm::None, lengths);
1724859d4a18SValentin Clement           symMap.addCharSymbolWithShape(sym, local, len, shape);
1725859d4a18SValentin Clement           return;
1726859d4a18SValentin Clement         }
1727859d4a18SValentin Clement 
1728859d4a18SValentin Clement         // if object is an array process the lower bound and extent values
1729859d4a18SValentin Clement         llvm::SmallVector<mlir::Value> extents;
1730859d4a18SValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
1731859d4a18SValentin Clement 
1732859d4a18SValentin Clement         // construct constants and populate `bounds`
1733411f839aSValentin Clement         for (auto [fst, snd] :
1734411f839aSValentin Clement              llvm::zip(x.lbounds, recoverShapeVector(x.shapes, preAlloc))) {
1735859d4a18SValentin Clement           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, fst));
1736859d4a18SValentin Clement           extents.emplace_back(genExtentValue(builder, loc, idxTy, snd));
1737859d4a18SValentin Clement         }
1738859d4a18SValentin Clement         if (isDummy) {
1739859d4a18SValentin Clement           symMap.addCharSymbolWithBounds(sym, addr, len, extents, lbounds,
1740859d4a18SValentin Clement                                          true);
1741859d4a18SValentin Clement           return;
1742859d4a18SValentin Clement         }
1743859d4a18SValentin Clement         // local CHARACTER array with computed bounds
1744859d4a18SValentin Clement         assert((!mustBeDummy) && (Fortran::lower::isExplicitShape(sym)));
1745859d4a18SValentin Clement         mlir::Value local =
1746859d4a18SValentin Clement             createNewLocal(converter, loc, var, preAlloc, llvm::None, lengths);
1747859d4a18SValentin Clement         symMap.addCharSymbolWithBounds(sym, local, len, extents, lbounds);
17482a59ead1SValentin Clement       },
17492a59ead1SValentin Clement 
17502a59ead1SValentin Clement       //===--------------------------------------------------------------===//
17512a59ead1SValentin Clement 
17522a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArrayStaticChar &x) {
17531e1f60c6SV Donaldson         if (genUnusedEntryPointBox())
17541e1f60c6SV Donaldson           return;
1755a1425019SValentin Clement         mlir::Value addr;
1756a1425019SValentin Clement         mlir::Value len;
1757a1425019SValentin Clement         mlir::Value argBox;
1758a1425019SValentin Clement         auto charLen = x.charLen();
1759a1425019SValentin Clement         // if element type is a CHARACTER, determine the LEN value
1760a1425019SValentin Clement         if (isDummy) {
1761a1425019SValentin Clement           mlir::Value actualArg = symMap.lookupSymbol(sym).getAddr();
1762a1425019SValentin Clement           if (auto boxTy = actualArg.getType().dyn_cast<fir::BoxType>()) {
1763a1425019SValentin Clement             argBox = actualArg;
1764a1425019SValentin Clement             mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
1765a1425019SValentin Clement             addr = builder.create<fir::BoxAddrOp>(loc, refTy, argBox);
1766a1425019SValentin Clement           } else {
1767a1425019SValentin Clement             addr = charHelp.createUnboxChar(actualArg).first;
1768a1425019SValentin Clement           }
1769a1425019SValentin Clement           // Set/override LEN with a constant
1770a1425019SValentin Clement           len = builder.createIntegerConstant(loc, idxTy, charLen);
1771a1425019SValentin Clement         } else {
1772a1425019SValentin Clement           // local CHARACTER variable
1773a1425019SValentin Clement           len = builder.createIntegerConstant(loc, idxTy, charLen);
1774a1425019SValentin Clement         }
1775a1425019SValentin Clement 
1776a1425019SValentin Clement         // cast to the known constant parts from the declaration
1777a1425019SValentin Clement         mlir::Type castTy = builder.getRefType(converter.genType(var));
1778a1425019SValentin Clement         if (addr)
1779a1425019SValentin Clement           addr = builder.createConvert(loc, castTy, addr);
1780a1425019SValentin Clement         if (x.lboundAllOnes()) {
1781a1425019SValentin Clement           // if lower bounds are all ones, build simple shaped object
1782a1425019SValentin Clement           llvm::SmallVector<mlir::Value> shape;
1783a1425019SValentin Clement           populateShape(shape, x.bounds, argBox);
1784a1425019SValentin Clement           if (isDummy) {
1785a1425019SValentin Clement             symMap.addCharSymbolWithShape(sym, addr, len, shape, true);
1786a1425019SValentin Clement             return;
1787a1425019SValentin Clement           }
1788a1425019SValentin Clement           // local CHARACTER array
1789a1425019SValentin Clement           mlir::Value local =
1790a1425019SValentin Clement               createNewLocal(converter, loc, var, preAlloc, shape);
1791a1425019SValentin Clement           symMap.addCharSymbolWithShape(sym, local, len, shape);
1792a1425019SValentin Clement           return;
1793a1425019SValentin Clement         }
1794a1425019SValentin Clement         // if object is an array process the lower bound and extent values
1795a1425019SValentin Clement         llvm::SmallVector<mlir::Value> extents;
1796a1425019SValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
1797a1425019SValentin Clement         populateLBoundsExtents(lbounds, extents, x.bounds, argBox);
1798a1425019SValentin Clement         if (isDummy) {
1799a1425019SValentin Clement           symMap.addCharSymbolWithBounds(sym, addr, len, extents, lbounds,
1800a1425019SValentin Clement                                          true);
1801a1425019SValentin Clement           return;
1802a1425019SValentin Clement         }
1803a1425019SValentin Clement         // local CHARACTER array with computed bounds
1804a1425019SValentin Clement         assert(Fortran::lower::isExplicitShape(sym));
1805a1425019SValentin Clement         mlir::Value local =
1806a1425019SValentin Clement             createNewLocal(converter, loc, var, preAlloc, extents);
1807a1425019SValentin Clement         symMap.addCharSymbolWithBounds(sym, local, len, extents, lbounds);
18082a59ead1SValentin Clement       },
18092a59ead1SValentin Clement 
18102a59ead1SValentin Clement       //===--------------------------------------------------------------===//
18112a59ead1SValentin Clement 
18122a59ead1SValentin Clement       [&](const Fortran::lower::details::DynamicArrayDynamicChar &x) {
18131e1f60c6SV Donaldson         if (genUnusedEntryPointBox())
18141e1f60c6SV Donaldson           return;
1815a1425019SValentin Clement         mlir::Value addr;
1816a1425019SValentin Clement         mlir::Value len;
1817a1425019SValentin Clement         mlir::Value argBox;
1818a1425019SValentin Clement         auto charLen = x.charLen();
1819a1425019SValentin Clement         // if element type is a CHARACTER, determine the LEN value
1820a1425019SValentin Clement         if (isDummy) {
1821a1425019SValentin Clement           mlir::Value actualArg = symMap.lookupSymbol(sym).getAddr();
1822a1425019SValentin Clement           if (auto boxTy = actualArg.getType().dyn_cast<fir::BoxType>()) {
1823a1425019SValentin Clement             argBox = actualArg;
1824a1425019SValentin Clement             mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
1825a1425019SValentin Clement             addr = builder.create<fir::BoxAddrOp>(loc, refTy, argBox);
1826a1425019SValentin Clement             if (charLen)
1827a1425019SValentin Clement               // Set/override LEN with an expression.
1828a1425019SValentin Clement               len = genExplicitCharLen(charLen);
1829a1425019SValentin Clement             else
1830a1425019SValentin Clement               // Get the length from the actual arguments.
1831a1425019SValentin Clement               len = charHelp.readLengthFromBox(argBox);
1832a1425019SValentin Clement           } else {
1833a1425019SValentin Clement             std::pair<mlir::Value, mlir::Value> unboxchar =
1834a1425019SValentin Clement                 charHelp.createUnboxChar(actualArg);
1835a1425019SValentin Clement             addr = unboxchar.first;
1836a1425019SValentin Clement             if (charLen) {
1837a1425019SValentin Clement               // Set/override LEN with an expression
1838a1425019SValentin Clement               len = genExplicitCharLen(charLen);
1839a1425019SValentin Clement             } else {
1840a1425019SValentin Clement               // Get the length from the actual arguments.
1841a1425019SValentin Clement               len = unboxchar.second;
1842a1425019SValentin Clement             }
1843a1425019SValentin Clement           }
1844a1425019SValentin Clement         } else {
1845a1425019SValentin Clement           // local CHARACTER variable
1846a1425019SValentin Clement           len = genExplicitCharLen(charLen);
1847a1425019SValentin Clement         }
1848a1425019SValentin Clement         llvm::SmallVector<mlir::Value> lengths = {len};
1849a1425019SValentin Clement 
1850a1425019SValentin Clement         // cast to the known constant parts from the declaration
1851a1425019SValentin Clement         mlir::Type castTy = builder.getRefType(converter.genType(var));
1852a1425019SValentin Clement         if (addr)
1853a1425019SValentin Clement           addr = builder.createConvert(loc, castTy, addr);
1854a1425019SValentin Clement         if (x.lboundAllOnes()) {
1855a1425019SValentin Clement           // if lower bounds are all ones, build simple shaped object
1856a1425019SValentin Clement           llvm::SmallVector<mlir::Value> shape;
1857a1425019SValentin Clement           populateShape(shape, x.bounds, argBox);
1858a1425019SValentin Clement           if (isDummy) {
1859a1425019SValentin Clement             symMap.addCharSymbolWithShape(sym, addr, len, shape, true);
1860a1425019SValentin Clement             return;
1861a1425019SValentin Clement           }
1862a1425019SValentin Clement           // local CHARACTER array
1863a1425019SValentin Clement           mlir::Value local =
1864a1425019SValentin Clement               createNewLocal(converter, loc, var, preAlloc, shape, lengths);
1865a1425019SValentin Clement           symMap.addCharSymbolWithShape(sym, local, len, shape);
1866a1425019SValentin Clement           return;
1867a1425019SValentin Clement         }
1868a1425019SValentin Clement         // Process the lower bound and extent values.
1869a1425019SValentin Clement         llvm::SmallVector<mlir::Value> extents;
1870a1425019SValentin Clement         llvm::SmallVector<mlir::Value> lbounds;
1871a1425019SValentin Clement         populateLBoundsExtents(lbounds, extents, x.bounds, argBox);
1872a1425019SValentin Clement         if (isDummy) {
1873a1425019SValentin Clement           symMap.addCharSymbolWithBounds(sym, addr, len, extents, lbounds,
1874a1425019SValentin Clement                                          true);
1875a1425019SValentin Clement           return;
1876a1425019SValentin Clement         }
1877a1425019SValentin Clement         // local CHARACTER array with computed bounds
1878a1425019SValentin Clement         assert(Fortran::lower::isExplicitShape(sym));
1879a1425019SValentin Clement         mlir::Value local =
1880a1425019SValentin Clement             createNewLocal(converter, loc, var, preAlloc, extents, lengths);
1881a1425019SValentin Clement         symMap.addCharSymbolWithBounds(sym, local, len, extents, lbounds);
18822a59ead1SValentin Clement       },
18832a59ead1SValentin Clement 
18842a59ead1SValentin Clement       //===--------------------------------------------------------------===//
18852a59ead1SValentin Clement 
18862a59ead1SValentin Clement       [&](const Fortran::lower::BoxAnalyzer::None &) {
18872a59ead1SValentin Clement         mlir::emitError(loc, "symbol analysis failed on ")
18882a59ead1SValentin Clement             << toStringRef(sym.name());
18892a59ead1SValentin Clement       });
18902c2e5a5dSValentin Clement }
18912c2e5a5dSValentin Clement 
defineModuleVariable(AbstractConverter & converter,const Fortran::lower::pft::Variable & var)189217d71347SValentin Clement void Fortran::lower::defineModuleVariable(
189317d71347SValentin Clement     AbstractConverter &converter, const Fortran::lower::pft::Variable &var) {
189417d71347SValentin Clement   // Use empty linkage for module variables, which makes them available
189517d71347SValentin Clement   // for use in another unit.
1896a1425019SValentin Clement   mlir::StringAttr linkage =
1897a1425019SValentin Clement       getLinkageAttribute(converter.getFirOpBuilder(), var);
189817d71347SValentin Clement   if (!var.isGlobal())
189917d71347SValentin Clement     fir::emitFatalError(converter.getCurrentLocation(),
190017d71347SValentin Clement                         "attempting to lower module variable as local");
190117d71347SValentin Clement   // Define aggregate storages for equivalenced objects.
190217d71347SValentin Clement   if (var.isAggregateStore()) {
1903a1425019SValentin Clement     const Fortran::lower::pft::Variable::AggregateStore &aggregate =
1904a1425019SValentin Clement         var.getAggregateStore();
1905a1425019SValentin Clement     std::string aggName = mangleGlobalAggregateStore(aggregate);
1906a1425019SValentin Clement     defineGlobalAggregateStore(converter, aggregate, aggName, linkage);
1907a1425019SValentin Clement     return;
190817d71347SValentin Clement   }
190917d71347SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
19105d25267dSValentin Clement   if (const Fortran::semantics::Symbol *common =
19115d25267dSValentin Clement           Fortran::semantics::FindCommonBlockContaining(var.getSymbol())) {
19122c8cb9acSJean Perier     // Nothing to do, common block are generated before everything. Ensure
19132c8cb9acSJean Perier     // this was done by calling getCommonBlockGlobal.
19142c8cb9acSJean Perier     getCommonBlockGlobal(converter, *common);
191517d71347SValentin Clement   } else if (var.isAlias()) {
191617d71347SValentin Clement     // Do nothing. Mapping will be done on user side.
191717d71347SValentin Clement   } else {
191817d71347SValentin Clement     std::string globalName = Fortran::lower::mangle::mangleName(sym);
1919a1425019SValentin Clement     defineGlobal(converter, var, globalName, linkage);
192017d71347SValentin Clement   }
192117d71347SValentin Clement }
192217d71347SValentin Clement 
instantiateVariable(AbstractConverter & converter,const pft::Variable & var,Fortran::lower::SymMap & symMap,AggregateStoreMap & storeMap)19232c2e5a5dSValentin Clement void Fortran::lower::instantiateVariable(AbstractConverter &converter,
19242c2e5a5dSValentin Clement                                          const pft::Variable &var,
1925a1425019SValentin Clement                                          Fortran::lower::SymMap &symMap,
19268c22cb84SValentin Clement                                          AggregateStoreMap &storeMap) {
19272c2e5a5dSValentin Clement   if (var.isAggregateStore()) {
1928a1425019SValentin Clement     instantiateAggregateStore(converter, var, storeMap);
19295d25267dSValentin Clement   } else if (const Fortran::semantics::Symbol *common =
19305d25267dSValentin Clement                  Fortran::semantics::FindCommonBlockContaining(
19312c2e5a5dSValentin Clement                      var.getSymbol().GetUltimate())) {
19325d25267dSValentin Clement     instantiateCommon(converter, *common, var, symMap);
19332c2e5a5dSValentin Clement   } else if (var.isAlias()) {
1934a1425019SValentin Clement     instantiateAlias(converter, var, symMap, storeMap);
19352c2e5a5dSValentin Clement   } else if (var.isGlobal()) {
19368c22cb84SValentin Clement     instantiateGlobal(converter, var, symMap);
19372c2e5a5dSValentin Clement   } else {
19382c2e5a5dSValentin Clement     instantiateLocal(converter, var, symMap);
19392c2e5a5dSValentin Clement   }
19402c2e5a5dSValentin Clement }
1941d0b70a07SValentin Clement 
mapCallInterfaceSymbols(AbstractConverter & converter,const Fortran::lower::CallerInterface & caller,SymMap & symMap)1942d0b70a07SValentin Clement void Fortran::lower::mapCallInterfaceSymbols(
1943d0b70a07SValentin Clement     AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
1944d0b70a07SValentin Clement     SymMap &symMap) {
19458c22cb84SValentin Clement   Fortran::lower::AggregateStoreMap storeMap;
1946d0b70a07SValentin Clement   const Fortran::semantics::Symbol &result = caller.getResultSymbol();
1947d0b70a07SValentin Clement   for (Fortran::lower::pft::Variable var :
1948d0b70a07SValentin Clement        Fortran::lower::pft::buildFuncResultDependencyList(result)) {
1949d0b70a07SValentin Clement     if (var.isAggregateStore()) {
19508c22cb84SValentin Clement       instantiateVariable(converter, var, symMap, storeMap);
1951d0b70a07SValentin Clement     } else {
1952d0b70a07SValentin Clement       const Fortran::semantics::Symbol &sym = var.getSymbol();
1953d0b70a07SValentin Clement       const auto *hostDetails =
1954d0b70a07SValentin Clement           sym.detailsIf<Fortran::semantics::HostAssocDetails>();
1955d0b70a07SValentin Clement       if (hostDetails && !var.isModuleVariable()) {
1956d0b70a07SValentin Clement         // The callee is an internal procedure `A` whose result properties
1957d0b70a07SValentin Clement         // depend on host variables. The caller may be the host, or another
1958d0b70a07SValentin Clement         // internal procedure `B` contained in the same host.  In the first
1959d0b70a07SValentin Clement         // case, the host symbol is obviously mapped, in the second case, it
1960d0b70a07SValentin Clement         // must also be mapped because
1961d0b70a07SValentin Clement         // HostAssociations::internalProcedureBindings that was called when
1962d0b70a07SValentin Clement         // lowering `B` will have mapped all host symbols of captured variables
1963d0b70a07SValentin Clement         // to the tuple argument containing the composite of all host associated
1964d0b70a07SValentin Clement         // variables, whether or not the host symbol is actually referred to in
1965d0b70a07SValentin Clement         // `B`. Hence it is possible to simply lookup the variable associated to
1966d0b70a07SValentin Clement         // the host symbol without having to go back to the tuple argument.
1967d0b70a07SValentin Clement         Fortran::lower::SymbolBox hostValue =
1968d0b70a07SValentin Clement             symMap.lookupSymbol(hostDetails->symbol());
1969d0b70a07SValentin Clement         assert(hostValue && "callee host symbol must be mapped on caller side");
1970d0b70a07SValentin Clement         symMap.addSymbol(sym, hostValue.toExtendedValue());
1971d0b70a07SValentin Clement         // The SymbolBox associated to the host symbols is complete, skip
1972d0b70a07SValentin Clement         // instantiateVariable that would try to allocate a new storage.
1973d0b70a07SValentin Clement         continue;
1974d0b70a07SValentin Clement       }
1975d0b70a07SValentin Clement       if (Fortran::semantics::IsDummy(sym) && sym.owner() == result.owner()) {
1976d0b70a07SValentin Clement         // Get the argument for the dummy argument symbols of the current call.
1977d0b70a07SValentin Clement         symMap.addSymbol(sym, caller.getArgumentValue(sym));
1978d0b70a07SValentin Clement         // All the properties of the dummy variable may not come from the actual
1979d0b70a07SValentin Clement         // argument, let instantiateVariable handle this.
1980d0b70a07SValentin Clement       }
1981d0b70a07SValentin Clement       // If this is neither a host associated or dummy symbol, it must be a
1982d0b70a07SValentin Clement       // module or common block variable to satisfy specification expression
1983d0b70a07SValentin Clement       // requirements in 10.1.11, instantiateVariable will get its address and
1984d0b70a07SValentin Clement       // properties.
19858c22cb84SValentin Clement       instantiateVariable(converter, var, symMap, storeMap);
1986d0b70a07SValentin Clement     }
1987d0b70a07SValentin Clement   }
1988d0b70a07SValentin Clement }
1989a1425019SValentin Clement 
createRuntimeTypeInfoGlobal(Fortran::lower::AbstractConverter & converter,mlir::Location loc,const Fortran::semantics::Symbol & typeInfoSym)1990a1425019SValentin Clement void Fortran::lower::createRuntimeTypeInfoGlobal(
1991a1425019SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
1992a1425019SValentin Clement     const Fortran::semantics::Symbol &typeInfoSym) {
1993a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1994a1425019SValentin Clement   std::string globalName = Fortran::lower::mangle::mangleName(typeInfoSym);
1995a1425019SValentin Clement   auto var = Fortran::lower::pft::Variable(typeInfoSym, /*global=*/true);
1996a1425019SValentin Clement   mlir::StringAttr linkage = getLinkageAttribute(builder, var);
1997a1425019SValentin Clement   defineGlobal(converter, var, globalName, linkage);
1998a1425019SValentin Clement }
1999