xref: /llvm-project/flang/lib/Lower/ConvertVariable.cpp (revision ce32625966a922fe96aababe0ed975ada004901f)
1 //===-- ConvertVariable.cpp -- bridge to lower to MLIR --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "flang/Lower/ConvertVariable.h"
14 #include "flang/Lower/AbstractConverter.h"
15 #include "flang/Lower/Allocatable.h"
16 #include "flang/Lower/BoxAnalyzer.h"
17 #include "flang/Lower/CallInterface.h"
18 #include "flang/Lower/ConvertConstant.h"
19 #include "flang/Lower/ConvertExpr.h"
20 #include "flang/Lower/ConvertExprToHLFIR.h"
21 #include "flang/Lower/ConvertProcedureDesignator.h"
22 #include "flang/Lower/Mangler.h"
23 #include "flang/Lower/PFTBuilder.h"
24 #include "flang/Lower/StatementContext.h"
25 #include "flang/Lower/Support/Utils.h"
26 #include "flang/Lower/SymbolMap.h"
27 #include "flang/Optimizer/Builder/Character.h"
28 #include "flang/Optimizer/Builder/FIRBuilder.h"
29 #include "flang/Optimizer/Builder/HLFIRTools.h"
30 #include "flang/Optimizer/Builder/IntrinsicCall.h"
31 #include "flang/Optimizer/Builder/Runtime/Derived.h"
32 #include "flang/Optimizer/Builder/Todo.h"
33 #include "flang/Optimizer/Dialect/CUF/CUFOps.h"
34 #include "flang/Optimizer/Dialect/FIRAttr.h"
35 #include "flang/Optimizer/Dialect/FIRDialect.h"
36 #include "flang/Optimizer/Dialect/FIROps.h"
37 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
38 #include "flang/Optimizer/HLFIR/HLFIROps.h"
39 #include "flang/Optimizer/Support/FatalError.h"
40 #include "flang/Optimizer/Support/InternalNames.h"
41 #include "flang/Optimizer/Support/Utils.h"
42 #include "flang/Runtime/allocator-registry-consts.h"
43 #include "flang/Semantics/runtime-type-info.h"
44 #include "flang/Semantics/tools.h"
45 #include "llvm/Support/CommandLine.h"
46 #include "llvm/Support/Debug.h"
47 #include <optional>
48 
49 static llvm::cl::opt<bool>
50     allowAssumedRank("allow-assumed-rank",
51                      llvm::cl::desc("Enable assumed rank lowering"),
52                      llvm::cl::init(true));
53 
54 #define DEBUG_TYPE "flang-lower-variable"
55 
56 /// Helper to lower a scalar expression using a specific symbol mapping.
57 static mlir::Value genScalarValue(Fortran::lower::AbstractConverter &converter,
58                                   mlir::Location loc,
59                                   const Fortran::lower::SomeExpr &expr,
60                                   Fortran::lower::SymMap &symMap,
61                                   Fortran::lower::StatementContext &context) {
62   // This does not use the AbstractConverter member function to override the
63   // symbol mapping to be used expression lowering.
64   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
65     hlfir::EntityWithAttributes loweredExpr =
66         Fortran::lower::convertExprToHLFIR(loc, converter, expr, symMap,
67                                            context);
68     return hlfir::loadTrivialScalar(loc, converter.getFirOpBuilder(),
69                                     loweredExpr);
70   }
71   return fir::getBase(Fortran::lower::createSomeExtendedExpression(
72       loc, converter, expr, symMap, context));
73 }
74 
75 /// Does this variable have a default initialization?
76 bool Fortran::lower::hasDefaultInitialization(
77     const Fortran::semantics::Symbol &sym) {
78   if (sym.has<Fortran::semantics::ObjectEntityDetails>() && sym.size())
79     if (!Fortran::semantics::IsAllocatableOrPointer(sym))
80       if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
81         if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
82                 declTypeSpec->AsDerived()) {
83           // Pointer assignments in the runtime may hit undefined behaviors if
84           // the RHS contains garbage. Pointer objects are always established by
85           // lowering to NULL() (in Fortran::lower::createMutableBox). However,
86           // pointer components need special care here so that local and global
87           // derived type containing pointers are always initialized.
88           // Intent(out), however, do not need to be initialized since the
89           // related descriptor storage comes from a local or global that has
90           // been initialized (it may not be NULL() anymore, but the rank, type,
91           // and non deferred length parameters are still correct in a
92           // conformant program, and that is what matters).
93           const bool ignorePointer = Fortran::semantics::IsIntentOut(sym);
94           return derivedTypeSpec->HasDefaultInitialization(
95               /*ignoreAllocatable=*/false, ignorePointer);
96         }
97   return false;
98 }
99 
100 // Does this variable have a finalization?
101 static bool hasFinalization(const Fortran::semantics::Symbol &sym) {
102   if (sym.has<Fortran::semantics::ObjectEntityDetails>())
103     if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
104       if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
105               declTypeSpec->AsDerived())
106         return Fortran::semantics::IsFinalizable(*derivedTypeSpec);
107   return false;
108 }
109 
110 // Does this variable have an allocatable direct component?
111 static bool
112 hasAllocatableDirectComponent(const Fortran::semantics::Symbol &sym) {
113   if (sym.has<Fortran::semantics::ObjectEntityDetails>())
114     if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
115       if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
116               declTypeSpec->AsDerived())
117         return Fortran::semantics::HasAllocatableDirectComponent(
118             *derivedTypeSpec);
119   return false;
120 }
121 //===----------------------------------------------------------------===//
122 // Global variables instantiation (not for alias and common)
123 //===----------------------------------------------------------------===//
124 
125 /// Helper to generate expression value inside global initializer.
126 static fir::ExtendedValue
127 genInitializerExprValue(Fortran::lower::AbstractConverter &converter,
128                         mlir::Location loc,
129                         const Fortran::lower::SomeExpr &expr,
130                         Fortran::lower::StatementContext &stmtCtx) {
131   // Data initializer are constant value and should not depend on other symbols
132   // given the front-end fold parameter references. In any case, the "current"
133   // map of the converter should not be used since it holds mapping to
134   // mlir::Value from another mlir region. If these value are used by accident
135   // in the initializer, this will lead to segfaults in mlir code.
136   Fortran::lower::SymMap emptyMap;
137   return Fortran::lower::createSomeInitializerExpression(loc, converter, expr,
138                                                          emptyMap, stmtCtx);
139 }
140 
141 /// Can this symbol constant be placed in read-only memory?
142 static bool isConstant(const Fortran::semantics::Symbol &sym) {
143   return sym.attrs().test(Fortran::semantics::Attr::PARAMETER) ||
144          sym.test(Fortran::semantics::Symbol::Flag::ReadOnly);
145 }
146 
147 static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
148                                   const Fortran::lower::pft::Variable &var,
149                                   llvm::StringRef globalName,
150                                   mlir::StringAttr linkage,
151                                   cuf::DataAttributeAttr dataAttr = {});
152 
153 static mlir::Location genLocation(Fortran::lower::AbstractConverter &converter,
154                                   const Fortran::semantics::Symbol &sym) {
155   // Compiler generated name cannot be used as source location, their name
156   // is not pointing to the source files.
157   if (!sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated))
158     return converter.genLocation(sym.name());
159   return converter.getCurrentLocation();
160 }
161 
162 /// Create the global op declaration without any initializer
163 static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
164                                    const Fortran::lower::pft::Variable &var,
165                                    llvm::StringRef globalName,
166                                    mlir::StringAttr linkage) {
167   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
168   if (fir::GlobalOp global = builder.getNamedGlobal(globalName))
169     return global;
170   const Fortran::semantics::Symbol &sym = var.getSymbol();
171   cuf::DataAttributeAttr dataAttr =
172       Fortran::lower::translateSymbolCUFDataAttribute(
173           converter.getFirOpBuilder().getContext(), sym);
174   // Always define linkonce data since it may be optimized out from the module
175   // that actually owns the variable if it does not refers to it.
176   if (linkage == builder.createLinkOnceODRLinkage() ||
177       linkage == builder.createLinkOnceLinkage())
178     return defineGlobal(converter, var, globalName, linkage, dataAttr);
179   mlir::Location loc = genLocation(converter, sym);
180   // Resolve potential host and module association before checking that this
181   // symbol is an object of a function pointer.
182   const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
183   if (!ultimate.has<Fortran::semantics::ObjectEntityDetails>() &&
184       !Fortran::semantics::IsProcedurePointer(ultimate))
185     mlir::emitError(loc, "processing global declaration: symbol '")
186         << toStringRef(sym.name()) << "' has unexpected details\n";
187   return builder.createGlobal(loc, converter.genType(var), globalName, linkage,
188                               mlir::Attribute{}, isConstant(ultimate),
189                               var.isTarget(), dataAttr);
190 }
191 
192 /// Temporary helper to catch todos in initial data target lowering.
193 static bool
194 hasDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol &sym) {
195   if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
196     if (const Fortran::semantics::DerivedTypeSpec *derived =
197             declTy->AsDerived())
198       return Fortran::semantics::CountLenParameters(*derived) > 0;
199   return false;
200 }
201 
202 fir::ExtendedValue Fortran::lower::genExtAddrInInitializer(
203     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
204     const Fortran::lower::SomeExpr &addr) {
205   Fortran::lower::SymMap globalOpSymMap;
206   Fortran::lower::AggregateStoreMap storeMap;
207   Fortran::lower::StatementContext stmtCtx;
208   if (const Fortran::semantics::Symbol *sym =
209           Fortran::evaluate::GetFirstSymbol(addr)) {
210     // Length parameters processing will need care in global initializer
211     // context.
212     if (hasDerivedTypeWithLengthParameters(*sym))
213       TODO(loc, "initial-data-target with derived type length parameters");
214 
215     auto var = Fortran::lower::pft::Variable(*sym, /*global=*/true);
216     Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
217                                         storeMap);
218   }
219 
220   if (converter.getLoweringOptions().getLowerToHighLevelFIR())
221     return Fortran::lower::convertExprToAddress(loc, converter, addr,
222                                                 globalOpSymMap, stmtCtx);
223   return Fortran::lower::createInitializerAddress(loc, converter, addr,
224                                                   globalOpSymMap, stmtCtx);
225 }
226 
227 /// create initial-data-target fir.box in a global initializer region.
228 mlir::Value Fortran::lower::genInitialDataTarget(
229     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
230     mlir::Type boxType, const Fortran::lower::SomeExpr &initialTarget,
231     bool couldBeInEquivalence) {
232   Fortran::lower::SymMap globalOpSymMap;
233   Fortran::lower::AggregateStoreMap storeMap;
234   Fortran::lower::StatementContext stmtCtx;
235   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
236   if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
237           initialTarget))
238     return fir::factory::createUnallocatedBox(
239         builder, loc, boxType,
240         /*nonDeferredParams=*/std::nullopt);
241   // Pointer initial data target, and NULL(mold).
242   for (const auto &sym : Fortran::evaluate::CollectSymbols(initialTarget)) {
243     // Derived type component symbols should not be instantiated as objects
244     // on their own.
245     if (sym->owner().IsDerivedType())
246       continue;
247     // Length parameters processing will need care in global initializer
248     // context.
249     if (hasDerivedTypeWithLengthParameters(sym))
250       TODO(loc, "initial-data-target with derived type length parameters");
251     auto var = Fortran::lower::pft::Variable(sym, /*global=*/true);
252     if (couldBeInEquivalence) {
253       auto dependentVariableList =
254           Fortran::lower::pft::getDependentVariableList(sym);
255       for (Fortran::lower::pft::Variable var : dependentVariableList) {
256         if (!var.isAggregateStore())
257           break;
258         instantiateVariable(converter, var, globalOpSymMap, storeMap);
259       }
260       var = dependentVariableList.back();
261       assert(var.getSymbol().name() == sym->name() &&
262              "missing symbol in dependence list");
263     }
264     Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
265                                         storeMap);
266   }
267 
268   // Handle NULL(mold) as a special case. Return an unallocated box of MOLD
269   // type. The return box is correctly created as a fir.box<fir.ptr<T>> where
270   // T is extracted from the MOLD argument.
271   if (const Fortran::evaluate::ProcedureRef *procRef =
272           Fortran::evaluate::UnwrapProcedureRef(initialTarget)) {
273     const Fortran::evaluate::SpecificIntrinsic *intrinsic =
274         procRef->proc().GetSpecificIntrinsic();
275     if (intrinsic && intrinsic->name == "null") {
276       assert(procRef->arguments().size() == 1 &&
277              "Expecting mold argument for NULL intrinsic");
278       const auto *argExpr = procRef->arguments()[0].value().UnwrapExpr();
279       assert(argExpr);
280       const Fortran::semantics::Symbol *sym =
281           Fortran::evaluate::GetFirstSymbol(*argExpr);
282       assert(sym && "MOLD must be a pointer or allocatable symbol");
283       mlir::Type boxType = converter.genType(*sym);
284       mlir::Value box =
285           fir::factory::createUnallocatedBox(builder, loc, boxType, {});
286       return box;
287     }
288   }
289 
290   mlir::Value targetBox;
291   mlir::Value targetShift;
292   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
293     auto target = Fortran::lower::convertExprToBox(
294         loc, converter, initialTarget, globalOpSymMap, stmtCtx);
295     targetBox = fir::getBase(target);
296     targetShift = builder.createShape(loc, target);
297   } else {
298     if (initialTarget.Rank() > 0) {
299       auto target = Fortran::lower::createSomeArrayBox(converter, initialTarget,
300                                                        globalOpSymMap, stmtCtx);
301       targetBox = fir::getBase(target);
302       targetShift = builder.createShape(loc, target);
303     } else {
304       fir::ExtendedValue addr = Fortran::lower::createInitializerAddress(
305           loc, converter, initialTarget, globalOpSymMap, stmtCtx);
306       targetBox = builder.createBox(loc, addr);
307       // Nothing to do for targetShift, the target is a scalar.
308     }
309   }
310   // The targetBox is a fir.box<T>, not a fir.box<fir.ptr<T>> as it should for
311   // pointers (this matters to get the POINTER attribute correctly inside the
312   // initial value of the descriptor).
313   // Create a fir.rebox to set the attribute correctly, and use targetShift
314   // to preserve the target lower bounds if any.
315   return builder.create<fir::ReboxOp>(loc, boxType, targetBox, targetShift,
316                                       /*slice=*/mlir::Value{});
317 }
318 
319 /// Generate default initial value for a derived type object \p sym with mlir
320 /// type \p symTy.
321 static mlir::Value genDefaultInitializerValue(
322     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
323     const Fortran::semantics::Symbol &sym, mlir::Type symTy,
324     Fortran::lower::StatementContext &stmtCtx);
325 
326 /// Generate the initial value of a derived component \p component and insert
327 /// it into the derived type initial value \p insertInto of type \p recTy.
328 /// Return the new derived type initial value after the insertion.
329 static mlir::Value genComponentDefaultInit(
330     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
331     const Fortran::semantics::Symbol &component, fir::RecordType recTy,
332     mlir::Value insertInto, Fortran::lower::StatementContext &stmtCtx) {
333   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
334   std::string name = converter.getRecordTypeFieldName(component);
335   mlir::Type componentTy = recTy.getType(name);
336   assert(componentTy && "component not found in type");
337   mlir::Value componentValue;
338   if (const auto *object{
339           component.detailsIf<Fortran::semantics::ObjectEntityDetails>()}) {
340     if (const auto &init = object->init()) {
341       // Component has explicit initialization.
342       if (Fortran::semantics::IsPointer(component))
343         // Initial data target.
344         componentValue =
345             genInitialDataTarget(converter, loc, componentTy, *init);
346       else
347         // Initial value.
348         componentValue = fir::getBase(
349             genInitializerExprValue(converter, loc, *init, stmtCtx));
350     } else if (Fortran::semantics::IsAllocatableOrPointer(component)) {
351       // Pointer or allocatable without initialization.
352       // Create deallocated/disassociated value.
353       // From a standard point of view, pointer without initialization do not
354       // need to be disassociated, but for sanity and simplicity, do it in
355       // global constructor since this has no runtime cost.
356       componentValue = fir::factory::createUnallocatedBox(
357           builder, loc, componentTy, std::nullopt);
358     } else if (Fortran::lower::hasDefaultInitialization(component)) {
359       // Component type has default initialization.
360       componentValue = genDefaultInitializerValue(converter, loc, component,
361                                                   componentTy, stmtCtx);
362     } else {
363       // Component has no initial value. Set its bits to zero by extension
364       // to match what is expected because other compilers are doing it.
365       componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
366     }
367   } else if (const auto *proc{
368                  component
369                      .detailsIf<Fortran::semantics::ProcEntityDetails>()}) {
370     if (proc->init().has_value()) {
371       auto sym{*proc->init()};
372       if (sym) // Has a procedure target.
373         componentValue =
374             Fortran::lower::convertProcedureDesignatorInitialTarget(converter,
375                                                                     loc, *sym);
376       else // Has NULL() target.
377         componentValue =
378             fir::factory::createNullBoxProc(builder, loc, componentTy);
379     } else
380       componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
381   }
382   assert(componentValue && "must have been computed");
383   componentValue = builder.createConvert(loc, componentTy, componentValue);
384   auto fieldTy = fir::FieldType::get(recTy.getContext());
385   // FIXME: type parameters must come from the derived-type-spec
386   auto field = builder.create<fir::FieldIndexOp>(
387       loc, fieldTy, name, recTy,
388       /*typeParams=*/mlir::ValueRange{} /*TODO*/);
389   return builder.create<fir::InsertValueOp>(
390       loc, recTy, insertInto, componentValue,
391       builder.getArrayAttr(field.getAttributes()));
392 }
393 
394 static mlir::Value genDefaultInitializerValue(
395     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
396     const Fortran::semantics::Symbol &sym, mlir::Type symTy,
397     Fortran::lower::StatementContext &stmtCtx) {
398   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
399   mlir::Type scalarType = symTy;
400   fir::SequenceType sequenceType;
401   if (auto ty = mlir::dyn_cast<fir::SequenceType>(symTy)) {
402     sequenceType = ty;
403     scalarType = ty.getEleTy();
404   }
405   // Build a scalar default value of the symbol type, looping through the
406   // components to build each component initial value.
407   auto recTy = mlir::cast<fir::RecordType>(scalarType);
408   mlir::Value initialValue = builder.create<fir::UndefOp>(loc, scalarType);
409   const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
410   assert(declTy && "var with default initialization must have a type");
411 
412   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
413     // In HLFIR, the parent type is the first component, while in FIR there is
414     // not parent component in the fir.type and the component of the parent are
415     // "inlined" at the beginning of the fir.type.
416     const Fortran::semantics::Symbol &typeSymbol =
417         declTy->derivedTypeSpec().typeSymbol();
418     const Fortran::semantics::Scope *derivedScope =
419         declTy->derivedTypeSpec().GetScope();
420     assert(derivedScope && "failed to retrieve derived type scope");
421     for (const auto &componentName :
422          typeSymbol.get<Fortran::semantics::DerivedTypeDetails>()
423              .componentNames()) {
424       auto scopeIter = derivedScope->find(componentName);
425       assert(scopeIter != derivedScope->cend() &&
426              "failed to find derived type component symbol");
427       const Fortran::semantics::Symbol &component = scopeIter->second.get();
428       initialValue = genComponentDefaultInit(converter, loc, component, recTy,
429                                              initialValue, stmtCtx);
430     }
431   } else {
432     Fortran::semantics::OrderedComponentIterator components(
433         declTy->derivedTypeSpec());
434     for (const auto &component : components) {
435       // Skip parent components, the sub-components of parent types are part of
436       // components and will be looped through right after.
437       if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
438         continue;
439       initialValue = genComponentDefaultInit(converter, loc, component, recTy,
440                                              initialValue, stmtCtx);
441     }
442   }
443 
444   if (sequenceType) {
445     // For arrays, duplicate the scalar value to all elements with an
446     // fir.insert_range covering the whole array.
447     auto arrayInitialValue = builder.create<fir::UndefOp>(loc, sequenceType);
448     llvm::SmallVector<int64_t> rangeBounds;
449     for (int64_t extent : sequenceType.getShape()) {
450       if (extent == fir::SequenceType::getUnknownExtent())
451         TODO(loc,
452              "default initial value of array component with length parameters");
453       rangeBounds.push_back(0);
454       rangeBounds.push_back(extent - 1);
455     }
456     return builder.create<fir::InsertOnRangeOp>(
457         loc, sequenceType, arrayInitialValue, initialValue,
458         builder.getIndexVectorAttr(rangeBounds));
459   }
460   return initialValue;
461 }
462 
463 /// Does this global already have an initializer ?
464 static bool globalIsInitialized(fir::GlobalOp global) {
465   return !global.getRegion().empty() || global.getInitVal();
466 }
467 
468 /// Call \p genInit to generate code inside \p global initializer region.
469 void Fortran::lower::createGlobalInitialization(
470     fir::FirOpBuilder &builder, fir::GlobalOp global,
471     std::function<void(fir::FirOpBuilder &)> genInit) {
472   mlir::Region &region = global.getRegion();
473   region.push_back(new mlir::Block);
474   mlir::Block &block = region.back();
475   auto insertPt = builder.saveInsertionPoint();
476   builder.setInsertionPointToStart(&block);
477   genInit(builder);
478   builder.restoreInsertionPoint(insertPt);
479 }
480 
481 static unsigned getAllocatorIdx(cuf::DataAttributeAttr dataAttr) {
482   if (dataAttr) {
483     if (dataAttr.getValue() == cuf::DataAttribute::Pinned)
484       return kPinnedAllocatorPos;
485     if (dataAttr.getValue() == cuf::DataAttribute::Device)
486       return kDeviceAllocatorPos;
487     if (dataAttr.getValue() == cuf::DataAttribute::Managed)
488       return kManagedAllocatorPos;
489     if (dataAttr.getValue() == cuf::DataAttribute::Unified)
490       return kUnifiedAllocatorPos;
491   }
492   return kDefaultAllocator;
493 }
494 
495 /// Create the global op and its init if it has one
496 static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
497                                   const Fortran::lower::pft::Variable &var,
498                                   llvm::StringRef globalName,
499                                   mlir::StringAttr linkage,
500                                   cuf::DataAttributeAttr dataAttr) {
501   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
502   const Fortran::semantics::Symbol &sym = var.getSymbol();
503   mlir::Location loc = genLocation(converter, sym);
504   bool isConst = isConstant(sym);
505   fir::GlobalOp global = builder.getNamedGlobal(globalName);
506   mlir::Type symTy = converter.genType(var);
507 
508   if (global && globalIsInitialized(global))
509     return global;
510 
511   if (!converter.getLoweringOptions().getLowerToHighLevelFIR() &&
512       Fortran::semantics::IsProcedurePointer(sym))
513     TODO(loc, "procedure pointer globals");
514 
515   // If this is an array, check to see if we can use a dense attribute
516   // with a tensor mlir type. This optimization currently only supports
517   // Fortran arrays of integer, real, complex, or logical. The tensor
518   // type does not support nested structures.
519   if (mlir::isa<fir::SequenceType>(symTy) &&
520       !Fortran::semantics::IsAllocatableOrPointer(sym)) {
521     mlir::Type eleTy = mlir::cast<fir::SequenceType>(symTy).getElementType();
522     if (mlir::isa<mlir::IntegerType, mlir::FloatType, mlir::ComplexType,
523                   fir::LogicalType>(eleTy)) {
524       const auto *details =
525           sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
526       if (details->init()) {
527         global = Fortran::lower::tryCreatingDenseGlobal(
528             builder, loc, symTy, globalName, linkage, isConst,
529             details->init().value(), dataAttr);
530         if (global) {
531           global.setVisibility(mlir::SymbolTable::Visibility::Public);
532           return global;
533         }
534       }
535     }
536   }
537   if (!global)
538     global =
539         builder.createGlobal(loc, symTy, globalName, linkage, mlir::Attribute{},
540                              isConst, var.isTarget(), dataAttr);
541   if (Fortran::semantics::IsAllocatableOrPointer(sym) &&
542       !Fortran::semantics::IsProcedure(sym)) {
543     const auto *details =
544         sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
545     if (details && details->init()) {
546       auto expr = *details->init();
547       Fortran::lower::createGlobalInitialization(
548           builder, global, [&](fir::FirOpBuilder &b) {
549             mlir::Value box = Fortran::lower::genInitialDataTarget(
550                 converter, loc, symTy, expr);
551             b.create<fir::HasValueOp>(loc, box);
552           });
553     } else {
554       // Create unallocated/disassociated descriptor if no explicit init
555       Fortran::lower::createGlobalInitialization(
556           builder, global, [&](fir::FirOpBuilder &b) {
557             mlir::Value box = fir::factory::createUnallocatedBox(
558                 b, loc, symTy,
559                 /*nonDeferredParams=*/std::nullopt,
560                 /*typeSourceBox=*/{}, getAllocatorIdx(dataAttr));
561             b.create<fir::HasValueOp>(loc, box);
562           });
563     }
564   } else if (const auto *details =
565                  sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
566     if (details->init()) {
567       Fortran::lower::createGlobalInitialization(
568           builder, global, [&](fir::FirOpBuilder &builder) {
569             Fortran::lower::StatementContext stmtCtx(
570                 /*cleanupProhibited=*/true);
571             fir::ExtendedValue initVal = genInitializerExprValue(
572                 converter, loc, details->init().value(), stmtCtx);
573             mlir::Value castTo =
574                 builder.createConvert(loc, symTy, fir::getBase(initVal));
575             builder.create<fir::HasValueOp>(loc, castTo);
576           });
577     } else if (Fortran::lower::hasDefaultInitialization(sym)) {
578       Fortran::lower::createGlobalInitialization(
579           builder, global, [&](fir::FirOpBuilder &builder) {
580             Fortran::lower::StatementContext stmtCtx(
581                 /*cleanupProhibited=*/true);
582             mlir::Value initVal =
583                 genDefaultInitializerValue(converter, loc, sym, symTy, stmtCtx);
584             mlir::Value castTo = builder.createConvert(loc, symTy, initVal);
585             builder.create<fir::HasValueOp>(loc, castTo);
586           });
587     }
588   } else if (Fortran::semantics::IsProcedurePointer(sym)) {
589     const auto *details{sym.detailsIf<Fortran::semantics::ProcEntityDetails>()};
590     if (details && details->init()) {
591       auto sym{*details->init()};
592       if (sym) // Has a procedure target.
593         Fortran::lower::createGlobalInitialization(
594             builder, global, [&](fir::FirOpBuilder &b) {
595               Fortran::lower::StatementContext stmtCtx(
596                   /*cleanupProhibited=*/true);
597               auto box{Fortran::lower::convertProcedureDesignatorInitialTarget(
598                   converter, loc, *sym)};
599               auto castTo{builder.createConvert(loc, symTy, box)};
600               b.create<fir::HasValueOp>(loc, castTo);
601             });
602       else { // Has NULL() target.
603         Fortran::lower::createGlobalInitialization(
604             builder, global, [&](fir::FirOpBuilder &b) {
605               auto box{fir::factory::createNullBoxProc(b, loc, symTy)};
606               b.create<fir::HasValueOp>(loc, box);
607             });
608       }
609     } else {
610       // No initialization.
611       Fortran::lower::createGlobalInitialization(
612           builder, global, [&](fir::FirOpBuilder &b) {
613             auto box{fir::factory::createNullBoxProc(b, loc, symTy)};
614             b.create<fir::HasValueOp>(loc, box);
615           });
616     }
617   } else if (sym.has<Fortran::semantics::CommonBlockDetails>()) {
618     mlir::emitError(loc, "COMMON symbol processed elsewhere");
619   } else {
620     TODO(loc, "global"); // Something else
621   }
622   // Creates zero initializer for globals without initializers, this is a common
623   // and expected behavior (although not required by the standard)
624   if (!globalIsInitialized(global)) {
625     // Fortran does not provide means to specify that a BIND(C) module
626     // uninitialized variables will be defined in C.
627     // Add the common linkage to those to allow some level of support
628     // for this use case. Note that this use case will not work if the Fortran
629     // module code is placed in a shared library since, at least for the ELF
630     // format, common symbols are assigned a section in shared libraries.
631     // The best is still to declare C defined variables in a Fortran module file
632     // with no other definitions, and to never link the resulting module object
633     // file.
634     if (sym.attrs().test(Fortran::semantics::Attr::BIND_C))
635       global.setLinkName(builder.createCommonLinkage());
636     Fortran::lower::createGlobalInitialization(
637         builder, global, [&](fir::FirOpBuilder &builder) {
638           mlir::Value initValue;
639           if (converter.getLoweringOptions().getInitGlobalZero())
640             initValue = builder.create<fir::ZeroOp>(loc, symTy);
641           else
642             initValue = builder.create<fir::UndefOp>(loc, symTy);
643           builder.create<fir::HasValueOp>(loc, initValue);
644         });
645   }
646   // Set public visibility to prevent global definition to be optimized out
647   // even if they have no initializer and are unused in this compilation unit.
648   global.setVisibility(mlir::SymbolTable::Visibility::Public);
649   return global;
650 }
651 
652 /// Return linkage attribute for \p var.
653 static mlir::StringAttr
654 getLinkageAttribute(fir::FirOpBuilder &builder,
655                     const Fortran::lower::pft::Variable &var) {
656   // Runtime type info for a same derived type is identical in each compilation
657   // unit. It desired to avoid having to link against module that only define a
658   // type. Therefore the runtime type info is generated everywhere it is needed
659   // with `linkonce_odr` LLVM linkage.
660   if (var.isRuntimeTypeInfoData())
661     return builder.createLinkOnceODRLinkage();
662   if (var.isModuleOrSubmoduleVariable())
663     return {}; // external linkage
664   // Otherwise, the variable is owned by a procedure and must not be visible in
665   // other compilation units.
666   return builder.createInternalLinkage();
667 }
668 
669 /// Instantiate a global variable. If it hasn't already been processed, add
670 /// the global to the ModuleOp as a new uniqued symbol and initialize it with
671 /// the correct value. It will be referenced on demand using `fir.addr_of`.
672 static void instantiateGlobal(Fortran::lower::AbstractConverter &converter,
673                               const Fortran::lower::pft::Variable &var,
674                               Fortran::lower::SymMap &symMap) {
675   const Fortran::semantics::Symbol &sym = var.getSymbol();
676   assert(!var.isAlias() && "must be handled in instantiateAlias");
677   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
678   std::string globalName = converter.mangleName(sym);
679   mlir::Location loc = genLocation(converter, sym);
680   mlir::StringAttr linkage = getLinkageAttribute(builder, var);
681   fir::GlobalOp global;
682   if (var.isModuleOrSubmoduleVariable()) {
683     // A non-intrinsic module global is defined when lowering the module.
684     // Emit only a declaration if the global does not exist.
685     global = declareGlobal(converter, var, globalName, linkage);
686   } else {
687     cuf::DataAttributeAttr dataAttr =
688         Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
689                                                         sym);
690     global = defineGlobal(converter, var, globalName, linkage, dataAttr);
691   }
692   auto addrOf = builder.create<fir::AddrOfOp>(loc, global.resultType(),
693                                               global.getSymbol());
694   Fortran::lower::StatementContext stmtCtx;
695   mapSymbolAttributes(converter, var, symMap, stmtCtx, addrOf);
696 }
697 
698 //===----------------------------------------------------------------===//
699 // Local variables instantiation (not for alias)
700 //===----------------------------------------------------------------===//
701 
702 /// Create a stack slot for a local variable. Precondition: the insertion
703 /// point of the builder must be in the entry block, which is currently being
704 /// constructed.
705 static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
706                                   mlir::Location loc,
707                                   const Fortran::lower::pft::Variable &var,
708                                   mlir::Value preAlloc,
709                                   llvm::ArrayRef<mlir::Value> shape = {},
710                                   llvm::ArrayRef<mlir::Value> lenParams = {}) {
711   if (preAlloc)
712     return preAlloc;
713   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
714   std::string nm = converter.mangleName(var.getSymbol());
715   mlir::Type ty = converter.genType(var);
716   const Fortran::semantics::Symbol &ultimateSymbol =
717       var.getSymbol().GetUltimate();
718   llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
719   bool isTarg = var.isTarget();
720 
721   // Do not allocate storage for cray pointee. The address inside the cray
722   // pointer will be used instead when using the pointee. Allocating space
723   // would be a waste of space, and incorrect if the pointee is a non dummy
724   // assumed-size (possible with cray pointee).
725   if (ultimateSymbol.test(Fortran::semantics::Symbol::Flag::CrayPointee))
726     return builder.create<fir::ZeroOp>(loc, fir::ReferenceType::get(ty));
727 
728   if (Fortran::semantics::NeedCUDAAlloc(ultimateSymbol)) {
729     cuf::DataAttributeAttr dataAttr =
730         Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
731                                                         ultimateSymbol);
732     llvm::SmallVector<mlir::Value> indices;
733     llvm::SmallVector<mlir::Value> elidedShape =
734         fir::factory::elideExtentsAlreadyInType(ty, shape);
735     llvm::SmallVector<mlir::Value> elidedLenParams =
736         fir::factory::elideLengthsAlreadyInType(ty, lenParams);
737     auto idxTy = builder.getIndexType();
738     for (mlir::Value sh : elidedShape)
739       indices.push_back(builder.createConvert(loc, idxTy, sh));
740     mlir::Value alloc = builder.create<cuf::AllocOp>(
741         loc, ty, nm, symNm, dataAttr, lenParams, indices);
742     return alloc;
743   }
744 
745   // Let the builder do all the heavy lifting.
746   if (!Fortran::semantics::IsProcedurePointer(ultimateSymbol))
747     return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg);
748 
749   // Local procedure pointer.
750   auto res{builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg)};
751   auto box{fir::factory::createNullBoxProc(builder, loc, ty)};
752   builder.create<fir::StoreOp>(loc, box, res);
753   return res;
754 }
755 
756 /// Must \p var be default initialized at runtime when entering its scope.
757 static bool
758 mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable &var) {
759   if (!var.hasSymbol())
760     return false;
761   const Fortran::semantics::Symbol &sym = var.getSymbol();
762   if (var.isGlobal())
763     // Global variables are statically initialized.
764     return false;
765   if (Fortran::semantics::IsDummy(sym) && !Fortran::semantics::IsIntentOut(sym))
766     return false;
767   // Polymorphic intent(out) dummy might need default initialization
768   // at runtime.
769   if (Fortran::semantics::IsPolymorphic(sym) &&
770       Fortran::semantics::IsDummy(sym) &&
771       Fortran::semantics::IsIntentOut(sym) &&
772       !Fortran::semantics::IsAllocatable(sym) &&
773       !Fortran::semantics::IsPointer(sym))
774     return true;
775   // Local variables (including function results), and intent(out) dummies must
776   // be default initialized at runtime if their type has default initialization.
777   return Fortran::lower::hasDefaultInitialization(sym);
778 }
779 
780 /// Call default initialization runtime routine to initialize \p var.
781 void Fortran::lower::defaultInitializeAtRuntime(
782     Fortran::lower::AbstractConverter &converter,
783     const Fortran::semantics::Symbol &sym, Fortran::lower::SymMap &symMap) {
784   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
785   mlir::Location loc = converter.getCurrentLocation();
786   fir::ExtendedValue exv = converter.getSymbolExtendedValue(sym, &symMap);
787   if (Fortran::semantics::IsOptional(sym)) {
788     // 15.5.2.12 point 3, absent optional dummies are not initialized.
789     // Creating descriptor/passing null descriptor to the runtime would
790     // create runtime crashes.
791     auto isPresent = builder.create<fir::IsPresentOp>(loc, builder.getI1Type(),
792                                                       fir::getBase(exv));
793     builder.genIfThen(loc, isPresent)
794         .genThen([&]() {
795           auto box = builder.createBox(loc, exv);
796           fir::runtime::genDerivedTypeInitialize(builder, loc, box);
797         })
798         .end();
799   } else {
800     mlir::Value box = builder.createBox(loc, exv);
801     fir::runtime::genDerivedTypeInitialize(builder, loc, box);
802   }
803 }
804 
805 /// Call clone initialization runtime routine to initialize \p sym's value.
806 void Fortran::lower::initializeCloneAtRuntime(
807     Fortran::lower::AbstractConverter &converter,
808     const Fortran::semantics::Symbol &sym, Fortran::lower::SymMap &symMap) {
809   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
810   mlir::Location loc = converter.getCurrentLocation();
811   fir::ExtendedValue exv = converter.getSymbolExtendedValue(sym, &symMap);
812   mlir::Value newBox = builder.createBox(loc, exv);
813   lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol(sym);
814   fir::ExtendedValue hexv = converter.symBoxToExtendedValue(hsb);
815   mlir::Value box = builder.createBox(loc, hexv);
816   fir::runtime::genDerivedTypeInitializeClone(builder, loc, newBox, box);
817 }
818 
819 enum class VariableCleanUp { Finalize, Deallocate };
820 /// Check whether a local variable needs to be finalized according to clause
821 /// 7.5.6.3 point 3 or if it is an allocatable that must be deallocated. Note
822 /// that deallocation will trigger finalization if the type has any.
823 static std::optional<VariableCleanUp>
824 needDeallocationOrFinalization(const Fortran::lower::pft::Variable &var) {
825   if (!var.hasSymbol())
826     return std::nullopt;
827   const Fortran::semantics::Symbol &sym = var.getSymbol();
828   const Fortran::semantics::Scope &owner = sym.owner();
829   if (owner.kind() == Fortran::semantics::Scope::Kind::MainProgram) {
830     // The standard does not require finalizing main program variables.
831     return std::nullopt;
832   }
833   if (!Fortran::semantics::IsPointer(sym) &&
834       !Fortran::semantics::IsDummy(sym) &&
835       !Fortran::semantics::IsFunctionResult(sym) &&
836       !Fortran::semantics::IsSaved(sym)) {
837     if (Fortran::semantics::IsAllocatable(sym))
838       return VariableCleanUp::Deallocate;
839     if (hasFinalization(sym))
840       return VariableCleanUp::Finalize;
841     // hasFinalization() check above handled all cases that require
842     // finalization, but we also have to deallocate all allocatable
843     // components of local variables (since they are also local variables
844     // according to F18 5.4.3.2.2, p. 2, note 1).
845     // Here, the variable itself is not allocatable. If it has an allocatable
846     // component the Destroy runtime does the job. Use the Finalize clean-up,
847     // though there will be no finalization in runtime.
848     if (hasAllocatableDirectComponent(sym))
849       return VariableCleanUp::Finalize;
850   }
851   return std::nullopt;
852 }
853 
854 /// Check whether a variable needs the be finalized according to clause 7.5.6.3
855 /// point 7.
856 /// Must be nonpointer, nonallocatable, INTENT (OUT) dummy argument.
857 static bool
858 needDummyIntentoutFinalization(const Fortran::lower::pft::Variable &var) {
859   if (!var.hasSymbol())
860     return false;
861   const Fortran::semantics::Symbol &sym = var.getSymbol();
862   if (!Fortran::semantics::IsDummy(sym) ||
863       !Fortran::semantics::IsIntentOut(sym) ||
864       Fortran::semantics::IsAllocatable(sym) ||
865       Fortran::semantics::IsPointer(sym))
866     return false;
867   // Polymorphic and unlimited polymorphic intent(out) dummy argument might need
868   // finalization at runtime.
869   if (Fortran::semantics::IsPolymorphic(sym) ||
870       Fortran::semantics::IsUnlimitedPolymorphic(sym))
871     return true;
872   // Intent(out) dummies must be finalized at runtime if their type has a
873   // finalization.
874   // Allocatable components of INTENT(OUT) dummies must be deallocated (9.7.3.2
875   // p6). Calling finalization runtime for this works even if the components
876   // have no final procedures.
877   return hasFinalization(sym) || hasAllocatableDirectComponent(sym);
878 }
879 
880 /// Call default initialization runtime routine to initialize \p var.
881 static void finalizeAtRuntime(Fortran::lower::AbstractConverter &converter,
882                               const Fortran::lower::pft::Variable &var,
883                               Fortran::lower::SymMap &symMap) {
884   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
885   mlir::Location loc = converter.getCurrentLocation();
886   const Fortran::semantics::Symbol &sym = var.getSymbol();
887   fir::ExtendedValue exv = converter.getSymbolExtendedValue(sym, &symMap);
888   if (Fortran::semantics::IsOptional(sym)) {
889     // Only finalize if present.
890     auto isPresent = builder.create<fir::IsPresentOp>(loc, builder.getI1Type(),
891                                                       fir::getBase(exv));
892     builder.genIfThen(loc, isPresent)
893         .genThen([&]() {
894           auto box = builder.createBox(loc, exv);
895           fir::runtime::genDerivedTypeDestroy(builder, loc, box);
896         })
897         .end();
898   } else {
899     mlir::Value box = builder.createBox(loc, exv);
900     fir::runtime::genDerivedTypeDestroy(builder, loc, box);
901   }
902 }
903 
904 // Fortran 2018 - 9.7.3.2 point 6
905 // When a procedure is invoked, any allocated allocatable object that is an
906 // actual argument corresponding to an INTENT(OUT) allocatable dummy argument
907 // is deallocated; any allocated allocatable object that is a subobject of an
908 // actual argument corresponding to an INTENT(OUT) dummy argument is
909 // deallocated.
910 // Note that allocatable components of non-ALLOCATABLE INTENT(OUT) dummy
911 // arguments are dealt with needDummyIntentoutFinalization (finalization runtime
912 // is called to reach the intended component deallocation effect).
913 static void deallocateIntentOut(Fortran::lower::AbstractConverter &converter,
914                                 const Fortran::lower::pft::Variable &var,
915                                 Fortran::lower::SymMap &symMap) {
916   if (!var.hasSymbol())
917     return;
918 
919   const Fortran::semantics::Symbol &sym = var.getSymbol();
920   if (Fortran::semantics::IsDummy(sym) &&
921       Fortran::semantics::IsIntentOut(sym) &&
922       Fortran::semantics::IsAllocatable(sym)) {
923     fir::ExtendedValue extVal = converter.getSymbolExtendedValue(sym, &symMap);
924     if (auto mutBox = extVal.getBoxOf<fir::MutableBoxValue>()) {
925       // The dummy argument is not passed in the ENTRY so it should not be
926       // deallocated.
927       if (mlir::Operation *op = mutBox->getAddr().getDefiningOp()) {
928         if (auto declOp = mlir::dyn_cast<hlfir::DeclareOp>(op))
929           op = declOp.getMemref().getDefiningOp();
930         if (op && mlir::isa<fir::AllocaOp>(op))
931           return;
932       }
933       mlir::Location loc = converter.getCurrentLocation();
934       fir::FirOpBuilder &builder = converter.getFirOpBuilder();
935 
936       if (Fortran::semantics::IsOptional(sym)) {
937         auto isPresent = builder.create<fir::IsPresentOp>(
938             loc, builder.getI1Type(), fir::getBase(extVal));
939         builder.genIfThen(loc, isPresent)
940             .genThen([&]() {
941               Fortran::lower::genDeallocateIfAllocated(converter, *mutBox, loc);
942             })
943             .end();
944       } else {
945         Fortran::lower::genDeallocateIfAllocated(converter, *mutBox, loc);
946       }
947     }
948   }
949 }
950 
951 /// Instantiate a local variable. Precondition: Each variable will be visited
952 /// such that if its properties depend on other variables, the variables upon
953 /// which its properties depend will already have been visited.
954 static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
955                              const Fortran::lower::pft::Variable &var,
956                              Fortran::lower::SymMap &symMap) {
957   assert(!var.isAlias());
958   Fortran::lower::StatementContext stmtCtx;
959   mapSymbolAttributes(converter, var, symMap, stmtCtx);
960   deallocateIntentOut(converter, var, symMap);
961   if (needDummyIntentoutFinalization(var))
962     finalizeAtRuntime(converter, var, symMap);
963   if (mustBeDefaultInitializedAtRuntime(var))
964     Fortran::lower::defaultInitializeAtRuntime(converter, var.getSymbol(),
965                                                symMap);
966   if (Fortran::semantics::NeedCUDAAlloc(var.getSymbol())) {
967     auto *builder = &converter.getFirOpBuilder();
968     mlir::Location loc = converter.getCurrentLocation();
969     fir::ExtendedValue exv =
970         converter.getSymbolExtendedValue(var.getSymbol(), &symMap);
971     auto *sym = &var.getSymbol();
972     converter.getFctCtx().attachCleanup([builder, loc, exv, sym]() {
973       cuf::DataAttributeAttr dataAttr =
974           Fortran::lower::translateSymbolCUFDataAttribute(builder->getContext(),
975                                                           *sym);
976       builder->create<cuf::FreeOp>(loc, fir::getBase(exv), dataAttr);
977     });
978   }
979   if (std::optional<VariableCleanUp> cleanup =
980           needDeallocationOrFinalization(var)) {
981     auto *builder = &converter.getFirOpBuilder();
982     mlir::Location loc = converter.getCurrentLocation();
983     fir::ExtendedValue exv =
984         converter.getSymbolExtendedValue(var.getSymbol(), &symMap);
985     switch (*cleanup) {
986     case VariableCleanUp::Finalize:
987       converter.getFctCtx().attachCleanup([builder, loc, exv]() {
988         mlir::Value box = builder->createBox(loc, exv);
989         fir::runtime::genDerivedTypeDestroy(*builder, loc, box);
990       });
991       break;
992     case VariableCleanUp::Deallocate:
993       auto *converterPtr = &converter;
994       auto *sym = &var.getSymbol();
995       converter.getFctCtx().attachCleanup([converterPtr, loc, exv, sym]() {
996         const fir::MutableBoxValue *mutableBox =
997             exv.getBoxOf<fir::MutableBoxValue>();
998         assert(mutableBox &&
999                "trying to deallocate entity not lowered as allocatable");
1000         Fortran::lower::genDeallocateIfAllocated(*converterPtr, *mutableBox,
1001                                                  loc, sym);
1002 
1003       });
1004     }
1005   }
1006 }
1007 
1008 //===----------------------------------------------------------------===//
1009 // Aliased (EQUIVALENCE) variables instantiation
1010 //===----------------------------------------------------------------===//
1011 
1012 /// Insert \p aggregateStore instance into an AggregateStoreMap.
1013 static void insertAggregateStore(Fortran::lower::AggregateStoreMap &storeMap,
1014                                  const Fortran::lower::pft::Variable &var,
1015                                  mlir::Value aggregateStore) {
1016   std::size_t off = var.getAggregateStore().getOffset();
1017   Fortran::lower::AggregateStoreKey key = {var.getOwningScope(), off};
1018   storeMap[key] = aggregateStore;
1019 }
1020 
1021 /// Retrieve the aggregate store instance of \p alias from an
1022 /// AggregateStoreMap.
1023 static mlir::Value
1024 getAggregateStore(Fortran::lower::AggregateStoreMap &storeMap,
1025                   const Fortran::lower::pft::Variable &alias) {
1026   Fortran::lower::AggregateStoreKey key = {alias.getOwningScope(),
1027                                            alias.getAliasOffset()};
1028   auto iter = storeMap.find(key);
1029   assert(iter != storeMap.end());
1030   return iter->second;
1031 }
1032 
1033 /// Build the name for the storage of a global equivalence.
1034 static std::string mangleGlobalAggregateStore(
1035     Fortran::lower::AbstractConverter &converter,
1036     const Fortran::lower::pft::Variable::AggregateStore &st) {
1037   return converter.mangleName(st.getNamingSymbol());
1038 }
1039 
1040 /// Build the type for the storage of an equivalence.
1041 static mlir::Type
1042 getAggregateType(Fortran::lower::AbstractConverter &converter,
1043                  const Fortran::lower::pft::Variable::AggregateStore &st) {
1044   if (const Fortran::semantics::Symbol *initSym = st.getInitialValueSymbol())
1045     return converter.genType(*initSym);
1046   mlir::IntegerType byteTy = converter.getFirOpBuilder().getIntegerType(8);
1047   return fir::SequenceType::get(std::get<1>(st.interval), byteTy);
1048 }
1049 
1050 /// Define a GlobalOp for the storage of a global equivalence described
1051 /// by \p aggregate. The global is named \p aggName and is created with
1052 /// the provided \p linkage.
1053 /// If any of the equivalence members are initialized, an initializer is
1054 /// created for the equivalence.
1055 /// This is to be used when lowering the scope that owns the equivalence
1056 /// (as opposed to simply using it through host or use association).
1057 /// This is not to be used for equivalence of common block members (they
1058 /// already have the common block GlobalOp for them, see defineCommonBlock).
1059 static fir::GlobalOp defineGlobalAggregateStore(
1060     Fortran::lower::AbstractConverter &converter,
1061     const Fortran::lower::pft::Variable::AggregateStore &aggregate,
1062     llvm::StringRef aggName, mlir::StringAttr linkage) {
1063   assert(aggregate.isGlobal() && "not a global interval");
1064   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1065   fir::GlobalOp global = builder.getNamedGlobal(aggName);
1066   if (global && globalIsInitialized(global))
1067     return global;
1068   mlir::Location loc = converter.getCurrentLocation();
1069   mlir::Type aggTy = getAggregateType(converter, aggregate);
1070   if (!global)
1071     global = builder.createGlobal(loc, aggTy, aggName, linkage);
1072 
1073   if (const Fortran::semantics::Symbol *initSym =
1074           aggregate.getInitialValueSymbol())
1075     if (const auto *objectDetails =
1076             initSym->detailsIf<Fortran::semantics::ObjectEntityDetails>())
1077       if (objectDetails->init()) {
1078         Fortran::lower::createGlobalInitialization(
1079             builder, global, [&](fir::FirOpBuilder &builder) {
1080               Fortran::lower::StatementContext stmtCtx;
1081               mlir::Value initVal = fir::getBase(genInitializerExprValue(
1082                   converter, loc, objectDetails->init().value(), stmtCtx));
1083               builder.create<fir::HasValueOp>(loc, initVal);
1084             });
1085         return global;
1086       }
1087   // Equivalence has no Fortran initial value. Create an undefined FIR initial
1088   // value to ensure this is consider an object definition in the IR regardless
1089   // of the linkage.
1090   Fortran::lower::createGlobalInitialization(
1091       builder, global, [&](fir::FirOpBuilder &builder) {
1092         Fortran::lower::StatementContext stmtCtx;
1093         mlir::Value initVal = builder.create<fir::ZeroOp>(loc, aggTy);
1094         builder.create<fir::HasValueOp>(loc, initVal);
1095       });
1096   return global;
1097 }
1098 
1099 /// Declare a GlobalOp for the storage of a global equivalence described
1100 /// by \p aggregate. The global is named \p aggName and is created with
1101 /// the provided \p linkage.
1102 /// No initializer is built for the created GlobalOp.
1103 /// This is to be used when lowering the scope that uses members of an
1104 /// equivalence it through host or use association.
1105 /// This is not to be used for equivalence of common block members (they
1106 /// already have the common block GlobalOp for them, see defineCommonBlock).
1107 static fir::GlobalOp declareGlobalAggregateStore(
1108     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
1109     const Fortran::lower::pft::Variable::AggregateStore &aggregate,
1110     llvm::StringRef aggName, mlir::StringAttr linkage) {
1111   assert(aggregate.isGlobal() && "not a global interval");
1112   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1113   if (fir::GlobalOp global = builder.getNamedGlobal(aggName))
1114     return global;
1115   mlir::Type aggTy = getAggregateType(converter, aggregate);
1116   return builder.createGlobal(loc, aggTy, aggName, linkage);
1117 }
1118 
1119 /// This is an aggregate store for a set of EQUIVALENCED variables. Create the
1120 /// storage on the stack or global memory and add it to the map.
1121 static void
1122 instantiateAggregateStore(Fortran::lower::AbstractConverter &converter,
1123                           const Fortran::lower::pft::Variable &var,
1124                           Fortran::lower::AggregateStoreMap &storeMap) {
1125   assert(var.isAggregateStore() && "not an interval");
1126   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1127   mlir::IntegerType i8Ty = builder.getIntegerType(8);
1128   mlir::Location loc = converter.getCurrentLocation();
1129   std::string aggName =
1130       mangleGlobalAggregateStore(converter, var.getAggregateStore());
1131   if (var.isGlobal()) {
1132     fir::GlobalOp global;
1133     auto &aggregate = var.getAggregateStore();
1134     mlir::StringAttr linkage = getLinkageAttribute(builder, var);
1135     if (var.isModuleOrSubmoduleVariable()) {
1136       // A module global was or will be defined when lowering the module. Emit
1137       // only a declaration if the global does not exist at that point.
1138       global = declareGlobalAggregateStore(converter, loc, aggregate, aggName,
1139                                            linkage);
1140     } else {
1141       global =
1142           defineGlobalAggregateStore(converter, aggregate, aggName, linkage);
1143     }
1144     auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(),
1145                                               global.getSymbol());
1146     auto size = std::get<1>(var.getInterval());
1147     fir::SequenceType::Shape shape(1, size);
1148     auto seqTy = fir::SequenceType::get(shape, i8Ty);
1149     mlir::Type refTy = builder.getRefType(seqTy);
1150     mlir::Value aggregateStore = builder.createConvert(loc, refTy, addr);
1151     insertAggregateStore(storeMap, var, aggregateStore);
1152     return;
1153   }
1154   // This is a local aggregate, allocate an anonymous block of memory.
1155   auto size = std::get<1>(var.getInterval());
1156   fir::SequenceType::Shape shape(1, size);
1157   auto seqTy = fir::SequenceType::get(shape, i8Ty);
1158   mlir::Value local =
1159       builder.allocateLocal(loc, seqTy, aggName, "", std::nullopt, std::nullopt,
1160                             /*target=*/false);
1161   insertAggregateStore(storeMap, var, local);
1162 }
1163 
1164 /// Cast an alias address (variable part of an equivalence) to fir.ptr so that
1165 /// the optimizer is conservative and avoids doing copy elision in assignment
1166 /// involving equivalenced variables.
1167 /// TODO: Represent the equivalence aliasing constraint in another way to avoid
1168 /// pessimizing array assignments involving equivalenced variables.
1169 static mlir::Value castAliasToPointer(fir::FirOpBuilder &builder,
1170                                       mlir::Location loc, mlir::Type aliasType,
1171                                       mlir::Value aliasAddr) {
1172   return builder.createConvert(loc, fir::PointerType::get(aliasType),
1173                                aliasAddr);
1174 }
1175 
1176 /// Instantiate a member of an equivalence. Compute its address in its
1177 /// aggregate storage and lower its attributes.
1178 static void instantiateAlias(Fortran::lower::AbstractConverter &converter,
1179                              const Fortran::lower::pft::Variable &var,
1180                              Fortran::lower::SymMap &symMap,
1181                              Fortran::lower::AggregateStoreMap &storeMap) {
1182   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1183   assert(var.isAlias());
1184   const Fortran::semantics::Symbol &sym = var.getSymbol();
1185   const mlir::Location loc = genLocation(converter, sym);
1186   mlir::IndexType idxTy = builder.getIndexType();
1187   mlir::IntegerType i8Ty = builder.getIntegerType(8);
1188   mlir::Type i8Ptr = builder.getRefType(i8Ty);
1189   mlir::Type symType = converter.genType(sym);
1190   std::size_t off = sym.GetUltimate().offset() - var.getAliasOffset();
1191   mlir::Value storeAddr = getAggregateStore(storeMap, var);
1192   mlir::Value offset = builder.createIntegerConstant(loc, idxTy, off);
1193   mlir::Value bytePtr = builder.create<fir::CoordinateOp>(
1194       loc, i8Ptr, storeAddr, mlir::ValueRange{offset});
1195   mlir::Value typedPtr = castAliasToPointer(builder, loc, symType, bytePtr);
1196   Fortran::lower::StatementContext stmtCtx;
1197   mapSymbolAttributes(converter, var, symMap, stmtCtx, typedPtr);
1198   // Default initialization is possible for equivalence members: see
1199   // F2018 19.5.3.4. Note that if several equivalenced entities have
1200   // default initialization, they must have the same type, and the standard
1201   // allows the storage to be default initialized several times (this has
1202   // no consequences other than wasting some execution time). For now,
1203   // do not try optimizing this to single default initializations of
1204   // the equivalenced storages. Keep lowering simple.
1205   if (mustBeDefaultInitializedAtRuntime(var))
1206     Fortran::lower::defaultInitializeAtRuntime(converter, var.getSymbol(),
1207                                                symMap);
1208 }
1209 
1210 //===--------------------------------------------------------------===//
1211 // COMMON blocks instantiation
1212 //===--------------------------------------------------------------===//
1213 
1214 /// Does any member of the common block has an initializer ?
1215 static bool
1216 commonBlockHasInit(const Fortran::semantics::MutableSymbolVector &cmnBlkMems) {
1217   for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
1218     if (const auto *memDet =
1219             mem->detailsIf<Fortran::semantics::ObjectEntityDetails>())
1220       if (memDet->init())
1221         return true;
1222   }
1223   return false;
1224 }
1225 
1226 /// Build a tuple type for a common block based on the common block
1227 /// members and the common block size.
1228 /// This type is only needed to build common block initializers where
1229 /// the initial value is the collection of the member initial values.
1230 static mlir::TupleType getTypeOfCommonWithInit(
1231     Fortran::lower::AbstractConverter &converter,
1232     const Fortran::semantics::MutableSymbolVector &cmnBlkMems,
1233     std::size_t commonSize) {
1234   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1235   llvm::SmallVector<mlir::Type> members;
1236   std::size_t counter = 0;
1237   for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
1238     if (const auto *memDet =
1239             mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
1240       if (mem->offset() > counter) {
1241         fir::SequenceType::Shape len = {
1242             static_cast<fir::SequenceType::Extent>(mem->offset() - counter)};
1243         mlir::IntegerType byteTy = builder.getIntegerType(8);
1244         auto memTy = fir::SequenceType::get(len, byteTy);
1245         members.push_back(memTy);
1246         counter = mem->offset();
1247       }
1248       if (memDet->init()) {
1249         mlir::Type memTy = converter.genType(*mem);
1250         members.push_back(memTy);
1251         counter = mem->offset() + mem->size();
1252       }
1253     }
1254   }
1255   if (counter < commonSize) {
1256     fir::SequenceType::Shape len = {
1257         static_cast<fir::SequenceType::Extent>(commonSize - counter)};
1258     mlir::IntegerType byteTy = builder.getIntegerType(8);
1259     auto memTy = fir::SequenceType::get(len, byteTy);
1260     members.push_back(memTy);
1261   }
1262   return mlir::TupleType::get(builder.getContext(), members);
1263 }
1264 
1265 /// Common block members may have aliases. They are not in the common block
1266 /// member list from the symbol. We need to know about these aliases if they
1267 /// have initializer to generate the common initializer.
1268 /// This function takes care of adding aliases with initializer to the member
1269 /// list.
1270 static Fortran::semantics::MutableSymbolVector
1271 getCommonMembersWithInitAliases(const Fortran::semantics::Symbol &common) {
1272   const auto &commonDetails =
1273       common.get<Fortran::semantics::CommonBlockDetails>();
1274   auto members = commonDetails.objects();
1275 
1276   // The number and size of equivalence and common is expected to be small, so
1277   // no effort is given to optimize this loop of complexity equivalenced
1278   // common members * common members
1279   for (const Fortran::semantics::EquivalenceSet &set :
1280        common.owner().equivalenceSets())
1281     for (const Fortran::semantics::EquivalenceObject &obj : set) {
1282       if (!obj.symbol.test(Fortran::semantics::Symbol::Flag::CompilerCreated)) {
1283         if (const auto &details =
1284                 obj.symbol
1285                     .detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
1286           const Fortran::semantics::Symbol *com =
1287               FindCommonBlockContaining(obj.symbol);
1288           if (!details->init() || com != &common)
1289             continue;
1290           // This is an alias with an init that belongs to the list
1291           if (!llvm::is_contained(members, obj.symbol))
1292             members.emplace_back(obj.symbol);
1293         }
1294       }
1295     }
1296   return members;
1297 }
1298 
1299 /// Return the fir::GlobalOp that was created of COMMON block \p common.
1300 /// It is an error if the fir::GlobalOp was not created before this is
1301 /// called (it cannot be created on the flight because it is not known here
1302 /// what mlir type the GlobalOp should have to satisfy all the
1303 /// appearances in the program).
1304 static fir::GlobalOp
1305 getCommonBlockGlobal(Fortran::lower::AbstractConverter &converter,
1306                      const Fortran::semantics::Symbol &common) {
1307   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1308   std::string commonName = converter.mangleName(common);
1309   fir::GlobalOp global = builder.getNamedGlobal(commonName);
1310   // Common blocks are lowered before any subprograms to deal with common
1311   // whose size may not be the same in every subprograms.
1312   if (!global)
1313     fir::emitFatalError(converter.genLocation(common.name()),
1314                         "COMMON block was not lowered before its usage");
1315   return global;
1316 }
1317 
1318 /// Create the fir::GlobalOp for COMMON block \p common. If \p common has an
1319 /// initial value, it is not created yet. Instead, the common block list
1320 /// members is returned to later create the initial value in
1321 /// finalizeCommonBlockDefinition.
1322 static std::optional<std::tuple<
1323     fir::GlobalOp, Fortran::semantics::MutableSymbolVector, mlir::Location>>
1324 declareCommonBlock(Fortran::lower::AbstractConverter &converter,
1325                    const Fortran::semantics::Symbol &common,
1326                    std::size_t commonSize) {
1327   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1328   std::string commonName = converter.mangleName(common);
1329   fir::GlobalOp global = builder.getNamedGlobal(commonName);
1330   if (global)
1331     return std::nullopt;
1332   Fortran::semantics::MutableSymbolVector cmnBlkMems =
1333       getCommonMembersWithInitAliases(common);
1334   mlir::Location loc = converter.genLocation(common.name());
1335   mlir::StringAttr linkage = builder.createCommonLinkage();
1336   const auto *details =
1337       common.detailsIf<Fortran::semantics::CommonBlockDetails>();
1338   assert(details && "Expect CommonBlockDetails on the common symbol");
1339   if (!commonBlockHasInit(cmnBlkMems)) {
1340     // A COMMON block sans initializers is initialized to zero.
1341     // mlir::Vector types must have a strictly positive size, so at least
1342     // temporarily, force a zero size COMMON block to have one byte.
1343     const auto sz =
1344         static_cast<fir::SequenceType::Extent>(commonSize > 0 ? commonSize : 1);
1345     fir::SequenceType::Shape shape = {sz};
1346     mlir::IntegerType i8Ty = builder.getIntegerType(8);
1347     auto commonTy = fir::SequenceType::get(shape, i8Ty);
1348     auto vecTy = mlir::VectorType::get(sz, i8Ty);
1349     mlir::Attribute zero = builder.getIntegerAttr(i8Ty, 0);
1350     auto init = mlir::DenseElementsAttr::get(vecTy, llvm::ArrayRef(zero));
1351     global = builder.createGlobal(loc, commonTy, commonName, linkage, init);
1352     global.setAlignment(details->alignment());
1353     // No need to add any initial value later.
1354     return std::nullopt;
1355   }
1356   // COMMON block with initializer (note that initialized blank common are
1357   // accepted as an extension by semantics). Sort members by offset before
1358   // generating the type and initializer.
1359   std::sort(cmnBlkMems.begin(), cmnBlkMems.end(),
1360             [](auto &s1, auto &s2) { return s1->offset() < s2->offset(); });
1361   mlir::TupleType commonTy =
1362       getTypeOfCommonWithInit(converter, cmnBlkMems, commonSize);
1363   // Create the global object, the initial value will be added later.
1364   global = builder.createGlobal(loc, commonTy, commonName);
1365   global.setAlignment(details->alignment());
1366   return std::make_tuple(global, std::move(cmnBlkMems), loc);
1367 }
1368 
1369 /// Add initial value to a COMMON block fir::GlobalOp \p global given the list
1370 /// \p cmnBlkMems of the common block member symbols that contains symbols with
1371 /// an initial value.
1372 static void finalizeCommonBlockDefinition(
1373     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
1374     fir::GlobalOp global,
1375     const Fortran::semantics::MutableSymbolVector &cmnBlkMems) {
1376   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1377   mlir::TupleType commonTy = mlir::cast<mlir::TupleType>(global.getType());
1378   auto initFunc = [&](fir::FirOpBuilder &builder) {
1379     mlir::IndexType idxTy = builder.getIndexType();
1380     mlir::Value cb = builder.create<fir::ZeroOp>(loc, commonTy);
1381     unsigned tupIdx = 0;
1382     std::size_t offset = 0;
1383     LLVM_DEBUG(llvm::dbgs() << "block {\n");
1384     for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
1385       if (const auto *memDet =
1386               mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
1387         if (mem->offset() > offset) {
1388           ++tupIdx;
1389           offset = mem->offset();
1390         }
1391         if (memDet->init()) {
1392           LLVM_DEBUG(llvm::dbgs()
1393                      << "offset: " << mem->offset() << " is " << *mem << '\n');
1394           Fortran::lower::StatementContext stmtCtx;
1395           auto initExpr = memDet->init().value();
1396           fir::ExtendedValue initVal =
1397               Fortran::semantics::IsPointer(*mem)
1398                   ? Fortran::lower::genInitialDataTarget(
1399                         converter, loc, converter.genType(*mem), initExpr)
1400                   : genInitializerExprValue(converter, loc, initExpr, stmtCtx);
1401           mlir::IntegerAttr offVal = builder.getIntegerAttr(idxTy, tupIdx);
1402           mlir::Value castVal = builder.createConvert(
1403               loc, commonTy.getType(tupIdx), fir::getBase(initVal));
1404           cb = builder.create<fir::InsertValueOp>(loc, commonTy, cb, castVal,
1405                                                   builder.getArrayAttr(offVal));
1406           ++tupIdx;
1407           offset = mem->offset() + mem->size();
1408         }
1409       }
1410     }
1411     LLVM_DEBUG(llvm::dbgs() << "}\n");
1412     builder.create<fir::HasValueOp>(loc, cb);
1413   };
1414   Fortran::lower::createGlobalInitialization(builder, global, initFunc);
1415 }
1416 
1417 void Fortran::lower::defineCommonBlocks(
1418     Fortran::lower::AbstractConverter &converter,
1419     const Fortran::semantics::CommonBlockList &commonBlocks) {
1420   // Common blocks may depend on another common block address (if they contain
1421   // pointers with initial targets). To cover this case, create all common block
1422   // fir::Global before creating the initial values (if any).
1423   std::vector<std::tuple<fir::GlobalOp, Fortran::semantics::MutableSymbolVector,
1424                          mlir::Location>>
1425       delayedInitializations;
1426   for (const auto &[common, size] : commonBlocks)
1427     if (auto delayedInit = declareCommonBlock(converter, common, size))
1428       delayedInitializations.emplace_back(std::move(*delayedInit));
1429   for (auto &[global, cmnBlkMems, loc] : delayedInitializations)
1430     finalizeCommonBlockDefinition(loc, converter, global, cmnBlkMems);
1431 }
1432 
1433 mlir::Value Fortran::lower::genCommonBlockMember(
1434     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
1435     const Fortran::semantics::Symbol &sym, mlir::Value commonValue) {
1436   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1437 
1438   std::size_t byteOffset = sym.GetUltimate().offset();
1439   mlir::IntegerType i8Ty = builder.getIntegerType(8);
1440   mlir::Type i8Ptr = builder.getRefType(i8Ty);
1441   mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(i8Ty));
1442   mlir::Value base = builder.createConvert(loc, seqTy, commonValue);
1443 
1444   mlir::Value offs =
1445       builder.createIntegerConstant(loc, builder.getIndexType(), byteOffset);
1446   mlir::Value varAddr = builder.create<fir::CoordinateOp>(
1447       loc, i8Ptr, base, mlir::ValueRange{offs});
1448   mlir::Type symType = converter.genType(sym);
1449 
1450   return Fortran::semantics::FindEquivalenceSet(sym) != nullptr
1451              ? castAliasToPointer(builder, loc, symType, varAddr)
1452              : builder.createConvert(loc, builder.getRefType(symType), varAddr);
1453 }
1454 
1455 /// The COMMON block is a global structure. `var` will be at some offset
1456 /// within the COMMON block. Adds the address of `var` (COMMON + offset) to
1457 /// the symbol map.
1458 static void instantiateCommon(Fortran::lower::AbstractConverter &converter,
1459                               const Fortran::semantics::Symbol &common,
1460                               const Fortran::lower::pft::Variable &var,
1461                               Fortran::lower::SymMap &symMap) {
1462   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1463   const Fortran::semantics::Symbol &varSym = var.getSymbol();
1464   mlir::Location loc = converter.genLocation(varSym.name());
1465 
1466   mlir::Value commonAddr;
1467   if (Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(common))
1468     commonAddr = symBox.getAddr();
1469   if (!commonAddr) {
1470     // introduce a local AddrOf and add it to the map
1471     fir::GlobalOp global = getCommonBlockGlobal(converter, common);
1472     commonAddr = builder.create<fir::AddrOfOp>(loc, global.resultType(),
1473                                                global.getSymbol());
1474 
1475     symMap.addSymbol(common, commonAddr);
1476   }
1477 
1478   mlir::Value local = genCommonBlockMember(converter, loc, varSym, commonAddr);
1479   Fortran::lower::StatementContext stmtCtx;
1480   mapSymbolAttributes(converter, var, symMap, stmtCtx, local);
1481 }
1482 
1483 //===--------------------------------------------------------------===//
1484 // Lower Variables specification expressions and attributes
1485 //===--------------------------------------------------------------===//
1486 
1487 /// Helper to decide if a dummy argument must be tracked in an BoxValue.
1488 static bool lowerToBoxValue(const Fortran::semantics::Symbol &sym,
1489                             mlir::Value dummyArg,
1490                             Fortran::lower::AbstractConverter &converter) {
1491   // Only dummy arguments coming as fir.box can be tracked in an BoxValue.
1492   if (!dummyArg || !mlir::isa<fir::BaseBoxType>(dummyArg.getType()))
1493     return false;
1494   // Non contiguous arrays must be tracked in an BoxValue.
1495   if (sym.Rank() > 0 && !Fortran::evaluate::IsSimplyContiguous(
1496                             sym, converter.getFoldingContext()))
1497     return true;
1498   // Assumed rank and optional fir.box cannot yet be read while lowering the
1499   // specifications.
1500   if (Fortran::evaluate::IsAssumedRank(sym) ||
1501       Fortran::semantics::IsOptional(sym))
1502     return true;
1503   // Polymorphic entity should be tracked through a fir.box that has the
1504   // dynamic type info.
1505   if (const Fortran::semantics::DeclTypeSpec *type = sym.GetType())
1506     if (type->IsPolymorphic())
1507       return true;
1508   return false;
1509 }
1510 
1511 /// Compute extent from lower and upper bound.
1512 static mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc,
1513                                  mlir::Value lb, mlir::Value ub) {
1514   mlir::IndexType idxTy = builder.getIndexType();
1515   // Let the folder deal with the common `ub - <const> + 1` case.
1516   auto diff = builder.create<mlir::arith::SubIOp>(loc, idxTy, ub, lb);
1517   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
1518   auto rawExtent = builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one);
1519   return fir::factory::genMaxWithZero(builder, loc, rawExtent);
1520 }
1521 
1522 /// Lower explicit lower bounds into \p result. Does nothing if this is not an
1523 /// array, or if the lower bounds are deferred, or all implicit or one.
1524 static void lowerExplicitLowerBounds(
1525     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
1526     const Fortran::lower::BoxAnalyzer &box,
1527     llvm::SmallVectorImpl<mlir::Value> &result, Fortran::lower::SymMap &symMap,
1528     Fortran::lower::StatementContext &stmtCtx) {
1529   if (!box.isArray() || box.lboundIsAllOnes())
1530     return;
1531   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1532   mlir::IndexType idxTy = builder.getIndexType();
1533   if (box.isStaticArray()) {
1534     for (int64_t lb : box.staticLBound())
1535       result.emplace_back(builder.createIntegerConstant(loc, idxTy, lb));
1536     return;
1537   }
1538   for (const Fortran::semantics::ShapeSpec *spec : box.dynamicBound()) {
1539     if (auto low = spec->lbound().GetExplicit()) {
1540       auto expr = Fortran::lower::SomeExpr{*low};
1541       mlir::Value lb = builder.createConvert(
1542           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
1543       result.emplace_back(lb);
1544     }
1545   }
1546   assert(result.empty() || result.size() == box.dynamicBound().size());
1547 }
1548 
1549 /// Return -1 for the last dimension extent/upper bound of assumed-size arrays.
1550 /// This value is required to fulfill the requirements for assumed-rank
1551 /// associated with assumed-size (see for instance UBOUND in 16.9.196, and
1552 /// CFI_desc_t requirements in 18.5.3 point 5.).
1553 static mlir::Value getAssumedSizeExtent(mlir::Location loc,
1554                                         fir::FirOpBuilder &builder) {
1555   return builder.createMinusOneInteger(loc, builder.getIndexType());
1556 }
1557 
1558 /// Lower explicit extents into \p result if this is an explicit-shape or
1559 /// assumed-size array. Does nothing if this is not an explicit-shape or
1560 /// assumed-size array.
1561 static void
1562 lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
1563                      mlir::Location loc, const Fortran::lower::BoxAnalyzer &box,
1564                      llvm::SmallVectorImpl<mlir::Value> &lowerBounds,
1565                      llvm::SmallVectorImpl<mlir::Value> &result,
1566                      Fortran::lower::SymMap &symMap,
1567                      Fortran::lower::StatementContext &stmtCtx) {
1568   if (!box.isArray())
1569     return;
1570   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1571   mlir::IndexType idxTy = builder.getIndexType();
1572   if (box.isStaticArray()) {
1573     for (int64_t extent : box.staticShape())
1574       result.emplace_back(builder.createIntegerConstant(loc, idxTy, extent));
1575     return;
1576   }
1577   for (const auto &spec : llvm::enumerate(box.dynamicBound())) {
1578     if (auto up = spec.value()->ubound().GetExplicit()) {
1579       auto expr = Fortran::lower::SomeExpr{*up};
1580       mlir::Value ub = builder.createConvert(
1581           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
1582       if (lowerBounds.empty())
1583         result.emplace_back(fir::factory::genMaxWithZero(builder, loc, ub));
1584       else
1585         result.emplace_back(
1586             computeExtent(builder, loc, lowerBounds[spec.index()], ub));
1587     } else if (spec.value()->ubound().isStar()) {
1588       result.emplace_back(getAssumedSizeExtent(loc, builder));
1589     }
1590   }
1591   assert(result.empty() || result.size() == box.dynamicBound().size());
1592 }
1593 
1594 /// Lower explicit character length if any. Return empty mlir::Value if no
1595 /// explicit length.
1596 static mlir::Value
1597 lowerExplicitCharLen(Fortran::lower::AbstractConverter &converter,
1598                      mlir::Location loc, const Fortran::lower::BoxAnalyzer &box,
1599                      Fortran::lower::SymMap &symMap,
1600                      Fortran::lower::StatementContext &stmtCtx) {
1601   if (!box.isChar())
1602     return mlir::Value{};
1603   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1604   mlir::Type lenTy = builder.getCharacterLengthType();
1605   if (std::optional<int64_t> len = box.getCharLenConst())
1606     return builder.createIntegerConstant(loc, lenTy, *len);
1607   if (std::optional<Fortran::lower::SomeExpr> lenExpr = box.getCharLenExpr())
1608     // If the length expression is negative, the length is zero. See F2018
1609     // 7.4.4.2 point 5.
1610     return fir::factory::genMaxWithZero(
1611         builder, loc,
1612         genScalarValue(converter, loc, *lenExpr, symMap, stmtCtx));
1613   return mlir::Value{};
1614 }
1615 
1616 /// Assumed size arrays last extent is -1 in the front end.
1617 static mlir::Value genExtentValue(fir::FirOpBuilder &builder,
1618                                   mlir::Location loc, mlir::Type idxTy,
1619                                   long frontEndExtent) {
1620   if (frontEndExtent >= 0)
1621     return builder.createIntegerConstant(loc, idxTy, frontEndExtent);
1622   return getAssumedSizeExtent(loc, builder);
1623 }
1624 
1625 /// If a symbol is an array, it may have been declared with unknown extent
1626 /// parameters (e.g., `*`), but if it has an initial value then the actual size
1627 /// may be available from the initial array value's type.
1628 inline static llvm::SmallVector<std::int64_t>
1629 recoverShapeVector(llvm::ArrayRef<std::int64_t> shapeVec, mlir::Value initVal) {
1630   llvm::SmallVector<std::int64_t> result;
1631   if (initVal) {
1632     if (auto seqTy = fir::unwrapUntilSeqType(initVal.getType())) {
1633       for (auto [fst, snd] : llvm::zip(shapeVec, seqTy.getShape()))
1634         result.push_back(fst == fir::SequenceType::getUnknownExtent() ? snd
1635                                                                       : fst);
1636       return result;
1637     }
1638   }
1639   result.assign(shapeVec.begin(), shapeVec.end());
1640   return result;
1641 }
1642 
1643 fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
1644     mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym,
1645     fir::FortranVariableFlagsEnum extraFlags) {
1646   fir::FortranVariableFlagsEnum flags = extraFlags;
1647   if (sym.test(Fortran::semantics::Symbol::Flag::CrayPointee)) {
1648     // CrayPointee are represented as pointers.
1649     flags = flags | fir::FortranVariableFlagsEnum::pointer;
1650     return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
1651   }
1652   const auto &attrs = sym.attrs();
1653   if (attrs.test(Fortran::semantics::Attr::ALLOCATABLE))
1654     flags = flags | fir::FortranVariableFlagsEnum::allocatable;
1655   if (attrs.test(Fortran::semantics::Attr::ASYNCHRONOUS))
1656     flags = flags | fir::FortranVariableFlagsEnum::asynchronous;
1657   if (attrs.test(Fortran::semantics::Attr::BIND_C))
1658     flags = flags | fir::FortranVariableFlagsEnum::bind_c;
1659   if (attrs.test(Fortran::semantics::Attr::CONTIGUOUS))
1660     flags = flags | fir::FortranVariableFlagsEnum::contiguous;
1661   if (attrs.test(Fortran::semantics::Attr::INTENT_IN))
1662     flags = flags | fir::FortranVariableFlagsEnum::intent_in;
1663   if (attrs.test(Fortran::semantics::Attr::INTENT_INOUT))
1664     flags = flags | fir::FortranVariableFlagsEnum::intent_inout;
1665   if (attrs.test(Fortran::semantics::Attr::INTENT_OUT))
1666     flags = flags | fir::FortranVariableFlagsEnum::intent_out;
1667   if (attrs.test(Fortran::semantics::Attr::OPTIONAL))
1668     flags = flags | fir::FortranVariableFlagsEnum::optional;
1669   if (attrs.test(Fortran::semantics::Attr::PARAMETER))
1670     flags = flags | fir::FortranVariableFlagsEnum::parameter;
1671   if (attrs.test(Fortran::semantics::Attr::POINTER))
1672     flags = flags | fir::FortranVariableFlagsEnum::pointer;
1673   if (attrs.test(Fortran::semantics::Attr::TARGET))
1674     flags = flags | fir::FortranVariableFlagsEnum::target;
1675   if (attrs.test(Fortran::semantics::Attr::VALUE))
1676     flags = flags | fir::FortranVariableFlagsEnum::value;
1677   if (attrs.test(Fortran::semantics::Attr::VOLATILE))
1678     flags = flags | fir::FortranVariableFlagsEnum::fortran_volatile;
1679   if (flags == fir::FortranVariableFlagsEnum::None)
1680     return {};
1681   return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
1682 }
1683 
1684 cuf::DataAttributeAttr Fortran::lower::translateSymbolCUFDataAttribute(
1685     mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym) {
1686   std::optional<Fortran::common::CUDADataAttr> cudaAttr =
1687       Fortran::semantics::GetCUDADataAttr(&sym.GetUltimate());
1688   return cuf::getDataAttribute(mlirContext, cudaAttr);
1689 }
1690 
1691 static bool
1692 isCapturedInInternalProcedure(Fortran::lower::AbstractConverter &converter,
1693                               const Fortran::semantics::Symbol &sym) {
1694   const Fortran::lower::pft::FunctionLikeUnit *funit =
1695       converter.getCurrentFunctionUnit();
1696   if (!funit || funit->getHostAssoc().empty())
1697     return false;
1698   if (funit->getHostAssoc().isAssociated(sym))
1699     return true;
1700   // Consider that any capture of a variable that is in an equivalence with the
1701   // symbol imply that the storage of the symbol may also be accessed inside
1702   // symbol implies that the storage of the symbol may also be accessed inside
1703 
1704   // the internal procedure and flag it as captured.
1705   if (const auto *equivSet = Fortran::semantics::FindEquivalenceSet(sym))
1706     for (const Fortran::semantics::EquivalenceObject &eqObj : *equivSet)
1707       if (funit->getHostAssoc().isAssociated(eqObj.symbol))
1708         return true;
1709   return false;
1710 }
1711 
1712 /// Map a symbol to its FIR address and evaluated specification expressions.
1713 /// Not for symbols lowered to fir.box.
1714 /// Will optionally create fir.declare.
1715 static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
1716                              Fortran::lower::SymMap &symMap,
1717                              const Fortran::semantics::Symbol &sym,
1718                              mlir::Value base, mlir::Value len = {},
1719                              llvm::ArrayRef<mlir::Value> shape = std::nullopt,
1720                              llvm::ArrayRef<mlir::Value> lbounds = std::nullopt,
1721                              bool force = false) {
1722   // In HLFIR, procedure dummy symbols are not added with an hlfir.declare
1723   // because they are "values", and hlfir.declare is intended for variables. It
1724   // would add too much complexity to hlfir.declare to support this case, and
1725   // this would bring very little (the only point being debug info, that are not
1726   // yet emitted) since alias analysis is meaningless for those.
1727   // Commonblock names are not variables, but in some lowerings (like OpenMP) it
1728   // is useful to maintain the address of the commonblock in an MLIR value and
1729   // query it. hlfir.declare need not be created for these.
1730   if (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
1731       (!Fortran::semantics::IsProcedure(sym) ||
1732        Fortran::semantics::IsPointer(sym)) &&
1733       !sym.detailsIf<Fortran::semantics::CommonBlockDetails>()) {
1734     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1735     const mlir::Location loc = genLocation(converter, sym);
1736     mlir::Value shapeOrShift;
1737     if (!shape.empty() && !lbounds.empty())
1738       shapeOrShift = builder.genShape(loc, lbounds, shape);
1739     else if (!shape.empty())
1740       shapeOrShift = builder.genShape(loc, shape);
1741     else if (!lbounds.empty())
1742       shapeOrShift = builder.genShift(loc, lbounds);
1743     llvm::SmallVector<mlir::Value> lenParams;
1744     if (len)
1745       lenParams.emplace_back(len);
1746     auto name = converter.mangleName(sym);
1747     fir::FortranVariableFlagsEnum extraFlags = {};
1748     if (isCapturedInInternalProcedure(converter, sym))
1749       extraFlags = extraFlags | fir::FortranVariableFlagsEnum::internal_assoc;
1750     fir::FortranVariableFlagsAttr attributes =
1751         Fortran::lower::translateSymbolAttributes(builder.getContext(), sym,
1752                                                   extraFlags);
1753     cuf::DataAttributeAttr dataAttr =
1754         Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
1755                                                         sym);
1756 
1757     if (sym.test(Fortran::semantics::Symbol::Flag::CrayPointee)) {
1758       mlir::Type ptrBoxType =
1759           Fortran::lower::getCrayPointeeBoxType(base.getType());
1760       mlir::Value boxAlloc = builder.createTemporary(
1761           loc, ptrBoxType,
1762           /*name=*/{}, /*shape=*/{}, /*lenParams=*/{}, /*attrs=*/{},
1763           Fortran::semantics::GetCUDADataAttr(&sym.GetUltimate()));
1764 
1765       // Declare a local pointer variable.
1766       auto newBase = builder.create<hlfir::DeclareOp>(
1767           loc, boxAlloc, name, /*shape=*/nullptr, lenParams,
1768           /*dummy_scope=*/nullptr, attributes);
1769       mlir::Value nullAddr = builder.createNullConstant(
1770           loc, llvm::cast<fir::BaseBoxType>(ptrBoxType).getEleTy());
1771 
1772       // If the element type is known-length character, then
1773       // EmboxOp does not need the length parameters.
1774       if (auto charType = mlir::dyn_cast<fir::CharacterType>(
1775               hlfir::getFortranElementType(base.getType())))
1776         if (!charType.hasDynamicLen())
1777           lenParams.clear();
1778 
1779       // Inherit the shape (and maybe length parameters) from the pointee
1780       // declaration.
1781       mlir::Value initVal =
1782           builder.create<fir::EmboxOp>(loc, ptrBoxType, nullAddr, shapeOrShift,
1783                                        /*slice=*/nullptr, lenParams);
1784       builder.create<fir::StoreOp>(loc, initVal, newBase.getBase());
1785 
1786       // Any reference to the pointee is going to be using the pointer
1787       // box from now on. The base_addr of the descriptor must be updated
1788       // to hold the value of the Cray pointer at the point of the pointee
1789       // access.
1790       // Note that the same Cray pointer may be associated with
1791       // multiple pointees and each of them has its own descriptor.
1792       symMap.addVariableDefinition(sym, newBase, force);
1793       return;
1794     }
1795     mlir::Value dummyScope;
1796     if (converter.isRegisteredDummySymbol(sym))
1797       dummyScope = converter.dummyArgsScopeValue();
1798     auto newBase = builder.create<hlfir::DeclareOp>(
1799         loc, base, name, shapeOrShift, lenParams, dummyScope, attributes,
1800         dataAttr);
1801     symMap.addVariableDefinition(sym, newBase, force);
1802     return;
1803   }
1804 
1805   if (len) {
1806     if (!shape.empty()) {
1807       if (!lbounds.empty())
1808         symMap.addCharSymbolWithBounds(sym, base, len, shape, lbounds, force);
1809       else
1810         symMap.addCharSymbolWithShape(sym, base, len, shape, force);
1811     } else {
1812       symMap.addCharSymbol(sym, base, len, force);
1813     }
1814   } else {
1815     if (!shape.empty()) {
1816       if (!lbounds.empty())
1817         symMap.addSymbolWithBounds(sym, base, shape, lbounds, force);
1818       else
1819         symMap.addSymbolWithShape(sym, base, shape, force);
1820     } else {
1821       symMap.addSymbol(sym, base, force);
1822     }
1823   }
1824 }
1825 
1826 /// Map a symbol to its FIR address and evaluated specification expressions
1827 /// provided as a fir::ExtendedValue. Will optionally create fir.declare.
1828 void Fortran::lower::genDeclareSymbol(
1829     Fortran::lower::AbstractConverter &converter,
1830     Fortran::lower::SymMap &symMap, const Fortran::semantics::Symbol &sym,
1831     const fir::ExtendedValue &exv, fir::FortranVariableFlagsEnum extraFlags,
1832     bool force) {
1833   if (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
1834       (!Fortran::semantics::IsProcedure(sym) ||
1835        Fortran::semantics::IsPointer(sym)) &&
1836       !sym.detailsIf<Fortran::semantics::CommonBlockDetails>()) {
1837     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1838     const mlir::Location loc = genLocation(converter, sym);
1839     if (isCapturedInInternalProcedure(converter, sym))
1840       extraFlags = extraFlags | fir::FortranVariableFlagsEnum::internal_assoc;
1841     // FIXME: Using the ultimate symbol for translating symbol attributes will
1842     // lead to situations where the VOLATILE/ASYNCHRONOUS attributes are not
1843     // propagated to the hlfir.declare (these attributes can be added when
1844     // using module variables).
1845     fir::FortranVariableFlagsAttr attributes =
1846         Fortran::lower::translateSymbolAttributes(
1847             builder.getContext(), sym.GetUltimate(), extraFlags);
1848     cuf::DataAttributeAttr dataAttr =
1849         Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
1850                                                         sym.GetUltimate());
1851     auto name = converter.mangleName(sym);
1852     mlir::Value dummyScope;
1853     if (converter.isRegisteredDummySymbol(sym))
1854       dummyScope = converter.dummyArgsScopeValue();
1855     hlfir::EntityWithAttributes declare = hlfir::genDeclare(
1856         loc, builder, exv, name, attributes, dummyScope, dataAttr);
1857     symMap.addVariableDefinition(sym, declare.getIfVariableInterface(), force);
1858     return;
1859   }
1860   symMap.addSymbol(sym, exv, force);
1861 }
1862 
1863 /// Map an allocatable or pointer symbol to its FIR address and evaluated
1864 /// specification expressions. Will optionally create fir.declare.
1865 static void
1866 genAllocatableOrPointerDeclare(Fortran::lower::AbstractConverter &converter,
1867                                Fortran::lower::SymMap &symMap,
1868                                const Fortran::semantics::Symbol &sym,
1869                                fir::MutableBoxValue box, bool force = false) {
1870   if (!converter.getLoweringOptions().getLowerToHighLevelFIR()) {
1871     symMap.addAllocatableOrPointer(sym, box, force);
1872     return;
1873   }
1874   assert(!box.isDescribedByVariables() &&
1875          "HLFIR alloctables/pointers must be fir.ref<fir.box>");
1876   mlir::Value base = box.getAddr();
1877   mlir::Value explictLength;
1878   if (box.hasNonDeferredLenParams()) {
1879     if (!box.isCharacter())
1880       TODO(genLocation(converter, sym),
1881            "Pointer or Allocatable parametrized derived type");
1882     explictLength = box.nonDeferredLenParams()[0];
1883   }
1884   genDeclareSymbol(converter, symMap, sym, base, explictLength,
1885                    /*shape=*/std::nullopt,
1886                    /*lbounds=*/std::nullopt, force);
1887 }
1888 
1889 /// Map a procedure pointer
1890 static void genProcPointer(Fortran::lower::AbstractConverter &converter,
1891                            Fortran::lower::SymMap &symMap,
1892                            const Fortran::semantics::Symbol &sym,
1893                            mlir::Value addr, bool force = false) {
1894   genDeclareSymbol(converter, symMap, sym, addr, mlir::Value{},
1895                    /*shape=*/std::nullopt,
1896                    /*lbounds=*/std::nullopt, force);
1897 }
1898 
1899 /// Map a symbol represented with a runtime descriptor to its FIR fir.box and
1900 /// evaluated specification expressions. Will optionally create fir.declare.
1901 static void genBoxDeclare(Fortran::lower::AbstractConverter &converter,
1902                           Fortran::lower::SymMap &symMap,
1903                           const Fortran::semantics::Symbol &sym,
1904                           mlir::Value box, llvm::ArrayRef<mlir::Value> lbounds,
1905                           llvm::ArrayRef<mlir::Value> explicitParams,
1906                           llvm::ArrayRef<mlir::Value> explicitExtents,
1907                           bool replace = false) {
1908   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
1909     fir::BoxValue boxValue{box, lbounds, explicitParams, explicitExtents};
1910     Fortran::lower::genDeclareSymbol(
1911         converter, symMap, sym, std::move(boxValue),
1912         fir::FortranVariableFlagsEnum::None, replace);
1913     return;
1914   }
1915   symMap.addBoxSymbol(sym, box, lbounds, explicitParams, explicitExtents,
1916                       replace);
1917 }
1918 
1919 static unsigned getAllocatorIdx(const Fortran::semantics::Symbol &sym) {
1920   std::optional<Fortran::common::CUDADataAttr> cudaAttr =
1921       Fortran::semantics::GetCUDADataAttr(&sym.GetUltimate());
1922   if (cudaAttr) {
1923     if (*cudaAttr == Fortran::common::CUDADataAttr::Pinned)
1924       return kPinnedAllocatorPos;
1925     if (*cudaAttr == Fortran::common::CUDADataAttr::Device)
1926       return kDeviceAllocatorPos;
1927     if (*cudaAttr == Fortran::common::CUDADataAttr::Managed)
1928       return kManagedAllocatorPos;
1929     if (*cudaAttr == Fortran::common::CUDADataAttr::Unified)
1930       return kUnifiedAllocatorPos;
1931   }
1932   return kDefaultAllocator;
1933 }
1934 
1935 /// Lower specification expressions and attributes of variable \p var and
1936 /// add it to the symbol map. For a global or an alias, the address must be
1937 /// pre-computed and provided in \p preAlloc. A dummy argument for the current
1938 /// entry point has already been mapped to an mlir block argument in
1939 /// mapDummiesAndResults. Its mapping may be updated here.
1940 void Fortran::lower::mapSymbolAttributes(
1941     AbstractConverter &converter, const Fortran::lower::pft::Variable &var,
1942     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
1943     mlir::Value preAlloc) {
1944   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1945   const Fortran::semantics::Symbol &sym = var.getSymbol();
1946   const mlir::Location loc = genLocation(converter, sym);
1947   mlir::IndexType idxTy = builder.getIndexType();
1948   const bool isDeclaredDummy = Fortran::semantics::IsDummy(sym);
1949   // An active dummy from the current entry point.
1950   const bool isDummy = isDeclaredDummy && symMap.lookupSymbol(sym).getAddr();
1951   // An unused dummy from another entry point.
1952   const bool isUnusedEntryDummy = isDeclaredDummy && !isDummy;
1953   const bool isResult = Fortran::semantics::IsFunctionResult(sym);
1954   const bool replace = isDummy || isResult;
1955   fir::factory::CharacterExprHelper charHelp{builder, loc};
1956 
1957   if (Fortran::semantics::IsProcedure(sym)) {
1958     if (isUnusedEntryDummy) {
1959       // Additional discussion below.
1960       mlir::Type dummyProcType =
1961           Fortran::lower::getDummyProcedureType(sym, converter);
1962       mlir::Value undefOp = builder.create<fir::UndefOp>(loc, dummyProcType);
1963 
1964       Fortran::lower::genDeclareSymbol(converter, symMap, sym, undefOp);
1965     }
1966 
1967     // Procedure pointer.
1968     if (Fortran::semantics::IsPointer(sym)) {
1969       // global
1970       mlir::Value boxAlloc = preAlloc;
1971       // dummy or passed result
1972       if (!boxAlloc)
1973         if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
1974           boxAlloc = symbox.getAddr();
1975       // local
1976       if (!boxAlloc)
1977         boxAlloc = createNewLocal(converter, loc, var, preAlloc);
1978       genProcPointer(converter, symMap, sym, boxAlloc, replace);
1979     }
1980     return;
1981   }
1982 
1983   const bool isAssumedRank = Fortran::evaluate::IsAssumedRank(sym);
1984   if (isAssumedRank && !allowAssumedRank)
1985     TODO(loc, "assumed-rank variable in procedure implemented in Fortran");
1986 
1987   Fortran::lower::BoxAnalyzer ba;
1988   ba.analyze(sym);
1989 
1990   // First deal with pointers and allocatables, because their handling here
1991   // is the same regardless of their rank.
1992   if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
1993     // Get address of fir.box describing the entity.
1994     // global
1995     mlir::Value boxAlloc = preAlloc;
1996     // dummy or passed result
1997     if (!boxAlloc)
1998       if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
1999         boxAlloc = symbox.getAddr();
2000     assert((boxAlloc || !isAssumedRank) && "assumed-ranks cannot be local");
2001     // local
2002     if (!boxAlloc)
2003       boxAlloc = createNewLocal(converter, loc, var, preAlloc);
2004     // Lower non deferred parameters.
2005     llvm::SmallVector<mlir::Value> nonDeferredLenParams;
2006     if (ba.isChar()) {
2007       if (mlir::Value len =
2008               lowerExplicitCharLen(converter, loc, ba, symMap, stmtCtx))
2009         nonDeferredLenParams.push_back(len);
2010       else if (Fortran::semantics::IsAssumedLengthCharacter(sym))
2011         nonDeferredLenParams.push_back(
2012             Fortran::lower::getAssumedCharAllocatableOrPointerLen(
2013                 builder, loc, sym, boxAlloc));
2014     } else if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) {
2015       if (const Fortran::semantics::DerivedTypeSpec *derived =
2016               declTy->AsDerived())
2017         if (Fortran::semantics::CountLenParameters(*derived) != 0)
2018           TODO(loc,
2019                "derived type allocatable or pointer with length parameters");
2020     }
2021     fir::MutableBoxValue box = Fortran::lower::createMutableBox(
2022         converter, loc, var, boxAlloc, nonDeferredLenParams,
2023         /*alwaysUseBox=*/
2024         converter.getLoweringOptions().getLowerToHighLevelFIR(),
2025         getAllocatorIdx(var.getSymbol()));
2026     genAllocatableOrPointerDeclare(converter, symMap, var.getSymbol(), box,
2027                                    replace);
2028     return;
2029   }
2030 
2031   if (isDummy) {
2032     mlir::Value dummyArg = symMap.lookupSymbol(sym).getAddr();
2033     if (lowerToBoxValue(sym, dummyArg, converter)) {
2034       llvm::SmallVector<mlir::Value> lbounds;
2035       llvm::SmallVector<mlir::Value> explicitExtents;
2036       llvm::SmallVector<mlir::Value> explicitParams;
2037       // Lower lower bounds, explicit type parameters and explicit
2038       // extents if any.
2039       if (ba.isChar()) {
2040         if (mlir::Value len =
2041                 lowerExplicitCharLen(converter, loc, ba, symMap, stmtCtx))
2042           explicitParams.push_back(len);
2043         if (!isAssumedRank && sym.Rank() == 0) {
2044           // Do not keep scalar characters as fir.box (even when optional).
2045           // Lowering and FIR is not meant to deal with scalar characters as
2046           // fir.box outside of calls.
2047           auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(dummyArg.getType());
2048           mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
2049           mlir::Type lenType = builder.getCharacterLengthType();
2050           mlir::Value addr, len;
2051           if (Fortran::semantics::IsOptional(sym)) {
2052             auto isPresent = builder.create<fir::IsPresentOp>(
2053                 loc, builder.getI1Type(), dummyArg);
2054             auto addrAndLen =
2055                 builder
2056                     .genIfOp(loc, {refTy, lenType}, isPresent,
2057                              /*withElseRegion=*/true)
2058                     .genThen([&]() {
2059                       mlir::Value readAddr =
2060                           builder.create<fir::BoxAddrOp>(loc, refTy, dummyArg);
2061                       mlir::Value readLength =
2062                           charHelp.readLengthFromBox(dummyArg);
2063                       builder.create<fir::ResultOp>(
2064                           loc, mlir::ValueRange{readAddr, readLength});
2065                     })
2066                     .genElse([&] {
2067                       mlir::Value readAddr = builder.genAbsentOp(loc, refTy);
2068                       mlir::Value readLength =
2069                           fir::factory::createZeroValue(builder, loc, lenType);
2070                       builder.create<fir::ResultOp>(
2071                           loc, mlir::ValueRange{readAddr, readLength});
2072                     })
2073                     .getResults();
2074             addr = addrAndLen[0];
2075             len = addrAndLen[1];
2076           } else {
2077             addr = builder.create<fir::BoxAddrOp>(loc, refTy, dummyArg);
2078             len = charHelp.readLengthFromBox(dummyArg);
2079           }
2080           if (!explicitParams.empty())
2081             len = explicitParams[0];
2082           ::genDeclareSymbol(converter, symMap, sym, addr, len, /*extents=*/{},
2083                              /*lbounds=*/{}, replace);
2084           return;
2085         }
2086       }
2087       // TODO: derived type length parameters.
2088       if (!isAssumedRank) {
2089         lowerExplicitLowerBounds(converter, loc, ba, lbounds, symMap, stmtCtx);
2090         lowerExplicitExtents(converter, loc, ba, lbounds, explicitExtents,
2091                              symMap, stmtCtx);
2092       }
2093       genBoxDeclare(converter, symMap, sym, dummyArg, lbounds, explicitParams,
2094                     explicitExtents, replace);
2095       return;
2096     }
2097   }
2098 
2099   // A dummy from another entry point that is not declared in the current
2100   // entry point requires a skeleton definition. Most such "unused" dummies
2101   // will not survive into final generated code, but some will. It is illegal
2102   // to reference one at run time if it does. Such a dummy is mapped to a
2103   // value in one of three ways:
2104   //
2105   //  - Generate a fir::UndefOp value. This is lightweight, easy to clean up,
2106   //    and often valid, but it may fail for a dummy with dynamic bounds,
2107   //    or a dummy used to define another dummy. Information to distinguish
2108   //    valid cases is not generally available here, with the exception of
2109   //    dummy procedures. See the first function exit above.
2110   //
2111   //  - Allocate an uninitialized stack slot. This is an intermediate-weight
2112   //    solution that is harder to clean up. It is often valid, but may fail
2113   //    for an object with dynamic bounds. This option is "automatically"
2114   //    used by default for cases that do not use one of the other options.
2115   //
2116   //  - Allocate a heap box/descriptor, initialized to zero. This always
2117   //    works, but is more heavyweight and harder to clean up. It is used
2118   //    for dynamic objects via calls to genUnusedEntryPointBox.
2119 
2120   auto genUnusedEntryPointBox = [&]() {
2121     if (isUnusedEntryDummy) {
2122       assert(!Fortran::semantics::IsAllocatableOrPointer(sym) &&
2123              "handled above");
2124       // The box is read right away because lowering code does not expect
2125       // a non pointer/allocatable symbol to be mapped to a MutableBox.
2126       mlir::Type ty = converter.genType(var);
2127       bool isPolymorphic = false;
2128       if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) {
2129         isPolymorphic = mlir::isa<fir::ClassType>(ty);
2130         ty = boxTy.getEleTy();
2131       }
2132       Fortran::lower::genDeclareSymbol(
2133           converter, symMap, sym,
2134           fir::factory::genMutableBoxRead(
2135               builder, loc,
2136               fir::factory::createTempMutableBox(builder, loc, ty, {}, {},
2137                                                  isPolymorphic)),
2138           fir::FortranVariableFlagsEnum::None,
2139           converter.isRegisteredDummySymbol(sym));
2140       return true;
2141     }
2142     return false;
2143   };
2144 
2145   if (isAssumedRank) {
2146     assert(isUnusedEntryDummy && "assumed rank must be pointers/allocatables "
2147                                  "or descriptor dummy arguments");
2148     genUnusedEntryPointBox();
2149     return;
2150   }
2151 
2152   // Helper to generate scalars for the symbol properties.
2153   auto genValue = [&](const Fortran::lower::SomeExpr &expr) {
2154     return genScalarValue(converter, loc, expr, symMap, stmtCtx);
2155   };
2156 
2157   // For symbols reaching this point, all properties are constant and can be
2158   // read/computed already into ssa values.
2159 
2160   // The origin must be \vec{1}.
2161   auto populateShape = [&](auto &shapes, const auto &bounds, mlir::Value box) {
2162     for (auto iter : llvm::enumerate(bounds)) {
2163       auto *spec = iter.value();
2164       assert(spec->lbound().GetExplicit() &&
2165              "lbound must be explicit with constant value 1");
2166       if (auto high = spec->ubound().GetExplicit()) {
2167         Fortran::lower::SomeExpr highEx{*high};
2168         mlir::Value ub = genValue(highEx);
2169         ub = builder.createConvert(loc, idxTy, ub);
2170         shapes.emplace_back(fir::factory::genMaxWithZero(builder, loc, ub));
2171       } else if (spec->ubound().isColon()) {
2172         assert(box && "assumed bounds require a descriptor");
2173         mlir::Value dim =
2174             builder.createIntegerConstant(loc, idxTy, iter.index());
2175         auto dimInfo =
2176             builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
2177         shapes.emplace_back(dimInfo.getResult(1));
2178       } else if (spec->ubound().isStar()) {
2179         shapes.emplace_back(getAssumedSizeExtent(loc, builder));
2180       } else {
2181         llvm::report_fatal_error("unknown bound category");
2182       }
2183     }
2184   };
2185 
2186   // The origin is not \vec{1}.
2187   auto populateLBoundsExtents = [&](auto &lbounds, auto &extents,
2188                                     const auto &bounds, mlir::Value box) {
2189     for (auto iter : llvm::enumerate(bounds)) {
2190       auto *spec = iter.value();
2191       fir::BoxDimsOp dimInfo;
2192       mlir::Value ub, lb;
2193       if (spec->lbound().isColon() || spec->ubound().isColon()) {
2194         // This is an assumed shape because allocatables and pointers extents
2195         // are not constant in the scope and are not read here.
2196         assert(box && "deferred bounds require a descriptor");
2197         mlir::Value dim =
2198             builder.createIntegerConstant(loc, idxTy, iter.index());
2199         dimInfo =
2200             builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
2201         extents.emplace_back(dimInfo.getResult(1));
2202         if (auto low = spec->lbound().GetExplicit()) {
2203           auto expr = Fortran::lower::SomeExpr{*low};
2204           mlir::Value lb = builder.createConvert(loc, idxTy, genValue(expr));
2205           lbounds.emplace_back(lb);
2206         } else {
2207           // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
2208           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, 1));
2209         }
2210       } else {
2211         if (auto low = spec->lbound().GetExplicit()) {
2212           auto expr = Fortran::lower::SomeExpr{*low};
2213           lb = builder.createConvert(loc, idxTy, genValue(expr));
2214         } else {
2215           TODO(loc, "support for assumed rank entities");
2216         }
2217         lbounds.emplace_back(lb);
2218 
2219         if (auto high = spec->ubound().GetExplicit()) {
2220           auto expr = Fortran::lower::SomeExpr{*high};
2221           ub = builder.createConvert(loc, idxTy, genValue(expr));
2222           extents.emplace_back(computeExtent(builder, loc, lb, ub));
2223         } else {
2224           // An assumed size array. The extent is not computed.
2225           assert(spec->ubound().isStar() && "expected assumed size");
2226           extents.emplace_back(getAssumedSizeExtent(loc, builder));
2227         }
2228       }
2229     }
2230   };
2231 
2232   //===--------------------------------------------------------------===//
2233   // Non Pointer non allocatable scalar, explicit shape, and assumed
2234   // size arrays.
2235   // Lower the specification expressions.
2236   //===--------------------------------------------------------------===//
2237 
2238   mlir::Value len;
2239   llvm::SmallVector<mlir::Value> extents;
2240   llvm::SmallVector<mlir::Value> lbounds;
2241   auto arg = symMap.lookupSymbol(sym).getAddr();
2242   mlir::Value addr = preAlloc;
2243 
2244   if (arg)
2245     if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(arg.getType())) {
2246       // Contiguous assumed shape that can be tracked without a fir.box.
2247       mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
2248       addr = builder.create<fir::BoxAddrOp>(loc, refTy, arg);
2249     }
2250 
2251   // Compute/Extract character length.
2252   if (ba.isChar()) {
2253     if (arg) {
2254       assert(!preAlloc && "dummy cannot be pre-allocated");
2255       if (mlir::isa<fir::BoxCharType>(arg.getType())) {
2256         std::tie(addr, len) = charHelp.createUnboxChar(arg);
2257       } else if (mlir::isa<fir::CharacterType>(arg.getType())) {
2258         // fir.char<1> passed by value (BIND(C) with VALUE attribute).
2259         addr = builder.create<fir::AllocaOp>(loc, arg.getType());
2260         builder.create<fir::StoreOp>(loc, arg, addr);
2261       } else if (!addr) {
2262         addr = arg;
2263       }
2264       // Ensure proper type is given to array/scalar that was transmitted as a
2265       // fir.boxchar arg or is a statement function actual argument with
2266       // a different length than the dummy.
2267       mlir::Type castTy = builder.getRefType(converter.genType(var));
2268       addr = builder.createConvert(loc, castTy, addr);
2269     }
2270     if (std::optional<int64_t> cstLen = ba.getCharLenConst()) {
2271       // Static length
2272       len = builder.createIntegerConstant(loc, idxTy, *cstLen);
2273     } else {
2274       // Dynamic length
2275       if (genUnusedEntryPointBox())
2276         return;
2277       if (std::optional<Fortran::lower::SomeExpr> charLenExpr =
2278               ba.getCharLenExpr()) {
2279         // Explicit length
2280         mlir::Value rawLen = genValue(*charLenExpr);
2281         // If the length expression is negative, the length is zero. See
2282         // F2018 7.4.4.2 point 5.
2283         len = fir::factory::genMaxWithZero(builder, loc, rawLen);
2284       } else if (!len) {
2285         // Assumed length fir.box (possible for contiguous assumed shapes).
2286         // Read length from box.
2287         assert(arg && mlir::isa<fir::BoxType>(arg.getType()) &&
2288                "must be character dummy fir.box");
2289         len = charHelp.readLengthFromBox(arg);
2290       }
2291     }
2292   }
2293 
2294   // Compute array extents and lower bounds.
2295   if (ba.isArray()) {
2296     if (ba.isStaticArray()) {
2297       if (ba.lboundIsAllOnes()) {
2298         for (std::int64_t extent :
2299              recoverShapeVector(ba.staticShape(), preAlloc))
2300           extents.push_back(genExtentValue(builder, loc, idxTy, extent));
2301       } else {
2302         for (auto [lb, extent] :
2303              llvm::zip(ba.staticLBound(),
2304                        recoverShapeVector(ba.staticShape(), preAlloc))) {
2305           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, lb));
2306           extents.emplace_back(genExtentValue(builder, loc, idxTy, extent));
2307         }
2308       }
2309     } else {
2310       // Non compile time constant shape.
2311       if (genUnusedEntryPointBox())
2312         return;
2313       if (ba.lboundIsAllOnes())
2314         populateShape(extents, ba.dynamicBound(), arg);
2315       else
2316         populateLBoundsExtents(lbounds, extents, ba.dynamicBound(), arg);
2317     }
2318   }
2319 
2320   // Allocate or extract raw address for the entity
2321   if (!addr) {
2322     if (arg) {
2323       mlir::Type argType = arg.getType();
2324       const bool isCptrByVal = Fortran::semantics::IsBuiltinCPtr(sym) &&
2325                                Fortran::lower::isCPtrArgByValueType(argType);
2326       if (isCptrByVal || !fir::conformsWithPassByRef(argType)) {
2327         // Dummy argument passed in register. Place the value in memory at that
2328         // point since lowering expect symbols to be mapped to memory addresses.
2329         mlir::Type symType = converter.genType(sym);
2330         addr = builder.create<fir::AllocaOp>(loc, symType);
2331         if (isCptrByVal) {
2332           // Place the void* address into the CPTR address component.
2333           mlir::Value addrComponent =
2334               fir::factory::genCPtrOrCFunptrAddr(builder, loc, addr, symType);
2335           builder.createStoreWithConvert(loc, arg, addrComponent);
2336         } else {
2337           builder.createStoreWithConvert(loc, arg, addr);
2338         }
2339       } else {
2340         // Dummy address, or address of result whose storage is passed by the
2341         // caller.
2342         assert(fir::isa_ref_type(argType) && "must be a memory address");
2343         addr = arg;
2344       }
2345     } else {
2346       // Local variables
2347       llvm::SmallVector<mlir::Value> typeParams;
2348       if (len)
2349         typeParams.emplace_back(len);
2350       addr = createNewLocal(converter, loc, var, preAlloc, extents, typeParams);
2351     }
2352   }
2353 
2354   ::genDeclareSymbol(converter, symMap, sym, addr, len, extents, lbounds,
2355                      replace);
2356   return;
2357 }
2358 
2359 void Fortran::lower::defineModuleVariable(
2360     AbstractConverter &converter, const Fortran::lower::pft::Variable &var) {
2361   // Use empty linkage for module variables, which makes them available
2362   // for use in another unit.
2363   mlir::StringAttr linkage =
2364       getLinkageAttribute(converter.getFirOpBuilder(), var);
2365   if (!var.isGlobal())
2366     fir::emitFatalError(converter.getCurrentLocation(),
2367                         "attempting to lower module variable as local");
2368   // Define aggregate storages for equivalenced objects.
2369   if (var.isAggregateStore()) {
2370     const Fortran::lower::pft::Variable::AggregateStore &aggregate =
2371         var.getAggregateStore();
2372     std::string aggName = mangleGlobalAggregateStore(converter, aggregate);
2373     defineGlobalAggregateStore(converter, aggregate, aggName, linkage);
2374     return;
2375   }
2376   const Fortran::semantics::Symbol &sym = var.getSymbol();
2377   if (const Fortran::semantics::Symbol *common =
2378           Fortran::semantics::FindCommonBlockContaining(var.getSymbol())) {
2379     // Nothing to do, common block are generated before everything. Ensure
2380     // this was done by calling getCommonBlockGlobal.
2381     getCommonBlockGlobal(converter, *common);
2382   } else if (var.isAlias()) {
2383     // Do nothing. Mapping will be done on user side.
2384   } else {
2385     std::string globalName = converter.mangleName(sym);
2386     cuf::DataAttributeAttr dataAttr =
2387         Fortran::lower::translateSymbolCUFDataAttribute(
2388             converter.getFirOpBuilder().getContext(), sym);
2389     defineGlobal(converter, var, globalName, linkage, dataAttr);
2390   }
2391 }
2392 
2393 void Fortran::lower::instantiateVariable(AbstractConverter &converter,
2394                                          const pft::Variable &var,
2395                                          Fortran::lower::SymMap &symMap,
2396                                          AggregateStoreMap &storeMap) {
2397   if (var.hasSymbol()) {
2398     // Do not try to instantiate symbols twice, except for dummies and results,
2399     // that may have been mapped to the MLIR entry block arguments, and for
2400     // which the explicit specifications, if any, has not yet been lowered.
2401     const auto &sym = var.getSymbol();
2402     if (!IsDummy(sym) && !IsFunctionResult(sym) && symMap.lookupSymbol(sym))
2403       return;
2404   }
2405   LLVM_DEBUG(llvm::dbgs() << "instantiateVariable: "; var.dump());
2406   if (var.isAggregateStore())
2407     instantiateAggregateStore(converter, var, storeMap);
2408   else if (const Fortran::semantics::Symbol *common =
2409                Fortran::semantics::FindCommonBlockContaining(
2410                    var.getSymbol().GetUltimate()))
2411     instantiateCommon(converter, *common, var, symMap);
2412   else if (var.isAlias())
2413     instantiateAlias(converter, var, symMap, storeMap);
2414   else if (var.isGlobal())
2415     instantiateGlobal(converter, var, symMap);
2416   else
2417     instantiateLocal(converter, var, symMap);
2418 }
2419 
2420 static void
2421 mapCallInterfaceSymbol(const Fortran::semantics::Symbol &interfaceSymbol,
2422                        Fortran::lower::AbstractConverter &converter,
2423                        const Fortran::lower::CallerInterface &caller,
2424                        Fortran::lower::SymMap &symMap) {
2425   Fortran::lower::AggregateStoreMap storeMap;
2426   for (Fortran::lower::pft::Variable var :
2427        Fortran::lower::pft::getDependentVariableList(interfaceSymbol)) {
2428     if (var.isAggregateStore()) {
2429       instantiateVariable(converter, var, symMap, storeMap);
2430       continue;
2431     }
2432     const Fortran::semantics::Symbol &sym = var.getSymbol();
2433     if (&sym == &interfaceSymbol)
2434       continue;
2435     const auto *hostDetails =
2436         sym.detailsIf<Fortran::semantics::HostAssocDetails>();
2437     if (hostDetails && !var.isModuleOrSubmoduleVariable()) {
2438       // The callee is an internal procedure `A` whose result properties
2439       // depend on host variables. The caller may be the host, or another
2440       // internal procedure `B` contained in the same host. In the first
2441       // case, the host symbol is obviously mapped, in the second case, it
2442       // must also be mapped because
2443       // HostAssociations::internalProcedureBindings that was called when
2444       // lowering `B` will have mapped all host symbols of captured variables
2445       // to the tuple argument containing the composite of all host associated
2446       // variables, whether or not the host symbol is actually referred to in
2447       // `B`. Hence it is possible to simply lookup the variable associated to
2448       // the host symbol without having to go back to the tuple argument.
2449       symMap.copySymbolBinding(hostDetails->symbol(), sym);
2450       // The SymbolBox associated to the host symbols is complete, skip
2451       // instantiateVariable that would try to allocate a new storage.
2452       continue;
2453     }
2454     if (Fortran::semantics::IsDummy(sym) &&
2455         sym.owner() == interfaceSymbol.owner()) {
2456       // Get the argument for the dummy argument symbols of the current call.
2457       symMap.addSymbol(sym, caller.getArgumentValue(sym));
2458       // All the properties of the dummy variable may not come from the actual
2459       // argument, let instantiateVariable handle this.
2460     }
2461     // If this is neither a host associated or dummy symbol, it must be a
2462     // module or common block variable to satisfy specification expression
2463     // requirements in 10.1.11, instantiateVariable will get its address and
2464     // properties.
2465     instantiateVariable(converter, var, symMap, storeMap);
2466   }
2467 }
2468 
2469 void Fortran::lower::mapCallInterfaceSymbolsForResult(
2470     AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
2471     SymMap &symMap) {
2472   const Fortran::semantics::Symbol &result = caller.getResultSymbol();
2473   mapCallInterfaceSymbol(result, converter, caller, symMap);
2474 }
2475 
2476 void Fortran::lower::mapCallInterfaceSymbolsForDummyArgument(
2477     AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
2478     SymMap &symMap, const Fortran::semantics::Symbol &dummySymbol) {
2479   mapCallInterfaceSymbol(dummySymbol, converter, caller, symMap);
2480 }
2481 
2482 void Fortran::lower::mapSymbolAttributes(
2483     AbstractConverter &converter, const Fortran::semantics::SymbolRef &symbol,
2484     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
2485     mlir::Value preAlloc) {
2486   mapSymbolAttributes(converter, pft::Variable{symbol}, symMap, stmtCtx,
2487                       preAlloc);
2488 }
2489 
2490 void Fortran::lower::createIntrinsicModuleGlobal(
2491     Fortran::lower::AbstractConverter &converter, const pft::Variable &var) {
2492   defineGlobal(converter, var, converter.mangleName(var.getSymbol()),
2493                converter.getFirOpBuilder().createLinkOnceODRLinkage());
2494 }
2495 
2496 void Fortran::lower::createRuntimeTypeInfoGlobal(
2497     Fortran::lower::AbstractConverter &converter,
2498     const Fortran::semantics::Symbol &typeInfoSym) {
2499   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
2500   std::string globalName = converter.mangleName(typeInfoSym);
2501   auto var = Fortran::lower::pft::Variable(typeInfoSym, /*global=*/true);
2502   mlir::StringAttr linkage = getLinkageAttribute(builder, var);
2503   defineGlobal(converter, var, globalName, linkage);
2504 }
2505 
2506 mlir::Type Fortran::lower::getCrayPointeeBoxType(mlir::Type fortranType) {
2507   mlir::Type baseType = hlfir::getFortranElementOrSequenceType(fortranType);
2508   if (auto seqType = mlir::dyn_cast<fir::SequenceType>(baseType)) {
2509     // The pointer box's sequence type must be with unknown shape.
2510     llvm::SmallVector<int64_t> shape(seqType.getDimension(),
2511                                      fir::SequenceType::getUnknownExtent());
2512     baseType = fir::SequenceType::get(shape, seqType.getEleTy());
2513   }
2514   return fir::BoxType::get(fir::PointerType::get(baseType));
2515 }
2516