xref: /llvm-project/flang/lib/Lower/ConvertVariable.cpp (revision ce32625966a922fe96aababe0ed975ada004901f)
12c2e5a5dSValentin Clement //===-- ConvertVariable.cpp -- bridge to lower to MLIR --------------------===//
22c2e5a5dSValentin Clement //
32c2e5a5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42c2e5a5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
52c2e5a5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62c2e5a5dSValentin Clement //
72c2e5a5dSValentin Clement //===----------------------------------------------------------------------===//
82c2e5a5dSValentin Clement //
92c2e5a5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
102c2e5a5dSValentin Clement //
112c2e5a5dSValentin Clement //===----------------------------------------------------------------------===//
122c2e5a5dSValentin Clement 
132c2e5a5dSValentin Clement #include "flang/Lower/ConvertVariable.h"
142c2e5a5dSValentin Clement #include "flang/Lower/AbstractConverter.h"
152a59ead1SValentin Clement #include "flang/Lower/Allocatable.h"
162a59ead1SValentin Clement #include "flang/Lower/BoxAnalyzer.h"
172c2e5a5dSValentin Clement #include "flang/Lower/CallInterface.h"
18af91b193SJean Perier #include "flang/Lower/ConvertConstant.h"
192c2e5a5dSValentin Clement #include "flang/Lower/ConvertExpr.h"
2034d3f3fbSJean Perier #include "flang/Lower/ConvertExprToHLFIR.h"
21af09219eSDaniel Chen #include "flang/Lower/ConvertProcedureDesignator.h"
222c2e5a5dSValentin Clement #include "flang/Lower/Mangler.h"
232c2e5a5dSValentin Clement #include "flang/Lower/PFTBuilder.h"
242a59ead1SValentin Clement #include "flang/Lower/StatementContext.h"
252c2e5a5dSValentin Clement #include "flang/Lower/Support/Utils.h"
262c2e5a5dSValentin Clement #include "flang/Lower/SymbolMap.h"
272c2e5a5dSValentin Clement #include "flang/Optimizer/Builder/Character.h"
282c2e5a5dSValentin Clement #include "flang/Optimizer/Builder/FIRBuilder.h"
2934d3f3fbSJean Perier #include "flang/Optimizer/Builder/HLFIRTools.h"
306dcb31deSTom Eccles #include "flang/Optimizer/Builder/IntrinsicCall.h"
312c2e5a5dSValentin Clement #include "flang/Optimizer/Builder/Runtime/Derived.h"
325b66cc10SValentin Clement #include "flang/Optimizer/Builder/Todo.h"
3345daa4fdSValentin Clement (バレンタイン クレメン) #include "flang/Optimizer/Dialect/CUF/CUFOps.h"
342c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
352c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIRDialect.h"
362c2e5a5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
37b07ef9e7SRenaud-K #include "flang/Optimizer/Dialect/Support/FIRContext.h"
3834d3f3fbSJean Perier #include "flang/Optimizer/HLFIR/HLFIROps.h"
392c2e5a5dSValentin Clement #include "flang/Optimizer/Support/FatalError.h"
4001e8e50cSValentin Clement #include "flang/Optimizer/Support/InternalNames.h"
41c560ce46SValentin Clement (バレンタイン クレメン) #include "flang/Optimizer/Support/Utils.h"
42c91ba043SMichael Kruse #include "flang/Runtime/allocator-registry-consts.h"
43a1425019SValentin Clement #include "flang/Semantics/runtime-type-info.h"
442c2e5a5dSValentin Clement #include "flang/Semantics/tools.h"
455aba0dedSjeanPerier #include "llvm/Support/CommandLine.h"
462c2e5a5dSValentin Clement #include "llvm/Support/Debug.h"
474d4d4785SKazu Hirata #include <optional>
482c2e5a5dSValentin Clement 
49ccca3c63SjeanPerier static llvm::cl::opt<bool>
50ccca3c63SjeanPerier     allowAssumedRank("allow-assumed-rank",
51ccca3c63SjeanPerier                      llvm::cl::desc("Enable assumed rank lowering"),
52ccca3c63SjeanPerier                      llvm::cl::init(true));
535aba0dedSjeanPerier 
542c2e5a5dSValentin Clement #define DEBUG_TYPE "flang-lower-variable"
552c2e5a5dSValentin Clement 
562a59ead1SValentin Clement /// Helper to lower a scalar expression using a specific symbol mapping.
572a59ead1SValentin Clement static mlir::Value genScalarValue(Fortran::lower::AbstractConverter &converter,
582a59ead1SValentin Clement                                   mlir::Location loc,
592a59ead1SValentin Clement                                   const Fortran::lower::SomeExpr &expr,
602a59ead1SValentin Clement                                   Fortran::lower::SymMap &symMap,
612a59ead1SValentin Clement                                   Fortran::lower::StatementContext &context) {
622a59ead1SValentin Clement   // This does not use the AbstractConverter member function to override the
632a59ead1SValentin Clement   // symbol mapping to be used expression lowering.
6434d3f3fbSJean Perier   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
6534d3f3fbSJean Perier     hlfir::EntityWithAttributes loweredExpr =
6634d3f3fbSJean Perier         Fortran::lower::convertExprToHLFIR(loc, converter, expr, symMap,
6734d3f3fbSJean Perier                                            context);
6834d3f3fbSJean Perier     return hlfir::loadTrivialScalar(loc, converter.getFirOpBuilder(),
6934d3f3fbSJean Perier                                     loweredExpr);
7034d3f3fbSJean Perier   }
712a59ead1SValentin Clement   return fir::getBase(Fortran::lower::createSomeExtendedExpression(
722a59ead1SValentin Clement       loc, converter, expr, symMap, context));
732a59ead1SValentin Clement }
7497492fd1SValentin Clement 
758c22cb84SValentin Clement /// Does this variable have a default initialization?
7698e733eaSTom Eccles bool Fortran::lower::hasDefaultInitialization(
7798e733eaSTom Eccles     const Fortran::semantics::Symbol &sym) {
788c22cb84SValentin Clement   if (sym.has<Fortran::semantics::ObjectEntityDetails>() && sym.size())
798c22cb84SValentin Clement     if (!Fortran::semantics::IsAllocatableOrPointer(sym))
808c22cb84SValentin Clement       if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
818c22cb84SValentin Clement         if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
82b9031d32SJean Perier                 declTypeSpec->AsDerived()) {
83b9031d32SJean Perier           // Pointer assignments in the runtime may hit undefined behaviors if
84b9031d32SJean Perier           // the RHS contains garbage. Pointer objects are always established by
85b9031d32SJean Perier           // lowering to NULL() (in Fortran::lower::createMutableBox). However,
86b9031d32SJean Perier           // pointer components need special care here so that local and global
87b9031d32SJean Perier           // derived type containing pointers are always initialized.
88b9031d32SJean Perier           // Intent(out), however, do not need to be initialized since the
89b9031d32SJean Perier           // related descriptor storage comes from a local or global that has
90b9031d32SJean Perier           // been initialized (it may not be NULL() anymore, but the rank, type,
91b9031d32SJean Perier           // and non deferred length parameters are still correct in a
92b9031d32SJean Perier           // conformant program, and that is what matters).
93b9031d32SJean Perier           const bool ignorePointer = Fortran::semantics::IsIntentOut(sym);
94b9031d32SJean Perier           return derivedTypeSpec->HasDefaultInitialization(
95b9031d32SJean Perier               /*ignoreAllocatable=*/false, ignorePointer);
96b9031d32SJean Perier         }
978c22cb84SValentin Clement   return false;
988c22cb84SValentin Clement }
998c22cb84SValentin Clement 
10097492fd1SValentin Clement // Does this variable have a finalization?
10197492fd1SValentin Clement static bool hasFinalization(const Fortran::semantics::Symbol &sym) {
102973ca4e4SValentin Clement (バレンタイン クレメン)   if (sym.has<Fortran::semantics::ObjectEntityDetails>())
10397492fd1SValentin Clement     if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
10497492fd1SValentin Clement       if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
10597492fd1SValentin Clement               declTypeSpec->AsDerived())
10697492fd1SValentin Clement         return Fortran::semantics::IsFinalizable(*derivedTypeSpec);
10797492fd1SValentin Clement   return false;
10897492fd1SValentin Clement }
10997492fd1SValentin Clement 
110be66a2f6SSlava Zakharin // Does this variable have an allocatable direct component?
111be66a2f6SSlava Zakharin static bool
112be66a2f6SSlava Zakharin hasAllocatableDirectComponent(const Fortran::semantics::Symbol &sym) {
113be66a2f6SSlava Zakharin   if (sym.has<Fortran::semantics::ObjectEntityDetails>())
114be66a2f6SSlava Zakharin     if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
115be66a2f6SSlava Zakharin       if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
116be66a2f6SSlava Zakharin               declTypeSpec->AsDerived())
117be66a2f6SSlava Zakharin         return Fortran::semantics::HasAllocatableDirectComponent(
118be66a2f6SSlava Zakharin             *derivedTypeSpec);
119be66a2f6SSlava Zakharin   return false;
120be66a2f6SSlava Zakharin }
1218c22cb84SValentin Clement //===----------------------------------------------------------------===//
1228c22cb84SValentin Clement // Global variables instantiation (not for alias and common)
1238c22cb84SValentin Clement //===----------------------------------------------------------------===//
1248c22cb84SValentin Clement 
1258c22cb84SValentin Clement /// Helper to generate expression value inside global initializer.
1268c22cb84SValentin Clement static fir::ExtendedValue
1278c22cb84SValentin Clement genInitializerExprValue(Fortran::lower::AbstractConverter &converter,
1288c22cb84SValentin Clement                         mlir::Location loc,
1298c22cb84SValentin Clement                         const Fortran::lower::SomeExpr &expr,
1308c22cb84SValentin Clement                         Fortran::lower::StatementContext &stmtCtx) {
1318c22cb84SValentin Clement   // Data initializer are constant value and should not depend on other symbols
1328c22cb84SValentin Clement   // given the front-end fold parameter references. In any case, the "current"
1338c22cb84SValentin Clement   // map of the converter should not be used since it holds mapping to
1348c22cb84SValentin Clement   // mlir::Value from another mlir region. If these value are used by accident
1358c22cb84SValentin Clement   // in the initializer, this will lead to segfaults in mlir code.
1368c22cb84SValentin Clement   Fortran::lower::SymMap emptyMap;
1378c22cb84SValentin Clement   return Fortran::lower::createSomeInitializerExpression(loc, converter, expr,
1388c22cb84SValentin Clement                                                          emptyMap, stmtCtx);
1398c22cb84SValentin Clement }
1408c22cb84SValentin Clement 
1418c22cb84SValentin Clement /// Can this symbol constant be placed in read-only memory?
1428c22cb84SValentin Clement static bool isConstant(const Fortran::semantics::Symbol &sym) {
1438c22cb84SValentin Clement   return sym.attrs().test(Fortran::semantics::Attr::PARAMETER) ||
1448c22cb84SValentin Clement          sym.test(Fortran::semantics::Symbol::Flag::ReadOnly);
1458c22cb84SValentin Clement }
1468c22cb84SValentin Clement 
147a1425019SValentin Clement static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
148a1425019SValentin Clement                                   const Fortran::lower::pft::Variable &var,
149a1425019SValentin Clement                                   llvm::StringRef globalName,
150314ef961SValentin Clement (バレンタイン クレメン)                                   mlir::StringAttr linkage,
15145daa4fdSValentin Clement (バレンタイン クレメン)                                   cuf::DataAttributeAttr dataAttr = {});
152a1425019SValentin Clement 
15353804e42SValentin Clement static mlir::Location genLocation(Fortran::lower::AbstractConverter &converter,
15453804e42SValentin Clement                                   const Fortran::semantics::Symbol &sym) {
15553804e42SValentin Clement   // Compiler generated name cannot be used as source location, their name
15653804e42SValentin Clement   // is not pointing to the source files.
15753804e42SValentin Clement   if (!sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated))
15853804e42SValentin Clement     return converter.genLocation(sym.name());
15953804e42SValentin Clement   return converter.getCurrentLocation();
16053804e42SValentin Clement }
16153804e42SValentin Clement 
1628c22cb84SValentin Clement /// Create the global op declaration without any initializer
1638c22cb84SValentin Clement static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
1648c22cb84SValentin Clement                                    const Fortran::lower::pft::Variable &var,
1658c22cb84SValentin Clement                                    llvm::StringRef globalName,
1668c22cb84SValentin Clement                                    mlir::StringAttr linkage) {
1678c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1688c22cb84SValentin Clement   if (fir::GlobalOp global = builder.getNamedGlobal(globalName))
1698c22cb84SValentin Clement     return global;
1703a47d948SValentin Clement (バレンタイン クレメン)   const Fortran::semantics::Symbol &sym = var.getSymbol();
1713a47d948SValentin Clement (バレンタイン クレメン)   cuf::DataAttributeAttr dataAttr =
1723a47d948SValentin Clement (バレンタイン クレメン)       Fortran::lower::translateSymbolCUFDataAttribute(
1733a47d948SValentin Clement (バレンタイン クレメン)           converter.getFirOpBuilder().getContext(), sym);
174a1425019SValentin Clement   // Always define linkonce data since it may be optimized out from the module
175a1425019SValentin Clement   // that actually owns the variable if it does not refers to it.
176a1425019SValentin Clement   if (linkage == builder.createLinkOnceODRLinkage() ||
177a1425019SValentin Clement       linkage == builder.createLinkOnceLinkage())
1783a47d948SValentin Clement (バレンタイン クレメン)     return defineGlobal(converter, var, globalName, linkage, dataAttr);
17953804e42SValentin Clement   mlir::Location loc = genLocation(converter, sym);
1808c22cb84SValentin Clement   // Resolve potential host and module association before checking that this
1818c22cb84SValentin Clement   // symbol is an object of a function pointer.
1828c22cb84SValentin Clement   const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
1838c22cb84SValentin Clement   if (!ultimate.has<Fortran::semantics::ObjectEntityDetails>() &&
1841e1f60c6SV Donaldson       !Fortran::semantics::IsProcedurePointer(ultimate))
18539377d52SValentin Clement     mlir::emitError(loc, "processing global declaration: symbol '")
1868c22cb84SValentin Clement         << toStringRef(sym.name()) << "' has unexpected details\n";
1878c22cb84SValentin Clement   return builder.createGlobal(loc, converter.genType(var), globalName, linkage,
188ac76fa48SSlava Zakharin                               mlir::Attribute{}, isConstant(ultimate),
18945daa4fdSValentin Clement (バレンタイン クレメン)                               var.isTarget(), dataAttr);
1908c22cb84SValentin Clement }
1918c22cb84SValentin Clement 
1928c22cb84SValentin Clement /// Temporary helper to catch todos in initial data target lowering.
1938c22cb84SValentin Clement static bool
1948c22cb84SValentin Clement hasDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol &sym) {
1958c22cb84SValentin Clement   if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
1968c22cb84SValentin Clement     if (const Fortran::semantics::DerivedTypeSpec *derived =
1978c22cb84SValentin Clement             declTy->AsDerived())
1988c22cb84SValentin Clement       return Fortran::semantics::CountLenParameters(*derived) > 0;
1998c22cb84SValentin Clement   return false;
2008c22cb84SValentin Clement }
2018c22cb84SValentin Clement 
20272276bdaSValentin Clement fir::ExtendedValue Fortran::lower::genExtAddrInInitializer(
20372276bdaSValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
20472276bdaSValentin Clement     const Fortran::lower::SomeExpr &addr) {
20572276bdaSValentin Clement   Fortran::lower::SymMap globalOpSymMap;
20672276bdaSValentin Clement   Fortran::lower::AggregateStoreMap storeMap;
20772276bdaSValentin Clement   Fortran::lower::StatementContext stmtCtx;
20872276bdaSValentin Clement   if (const Fortran::semantics::Symbol *sym =
20972276bdaSValentin Clement           Fortran::evaluate::GetFirstSymbol(addr)) {
21072276bdaSValentin Clement     // Length parameters processing will need care in global initializer
21172276bdaSValentin Clement     // context.
21272276bdaSValentin Clement     if (hasDerivedTypeWithLengthParameters(*sym))
21372276bdaSValentin Clement       TODO(loc, "initial-data-target with derived type length parameters");
21472276bdaSValentin Clement 
21572276bdaSValentin Clement     auto var = Fortran::lower::pft::Variable(*sym, /*global=*/true);
21672276bdaSValentin Clement     Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
21772276bdaSValentin Clement                                         storeMap);
21872276bdaSValentin Clement   }
2194e78f885SJean Perier 
2204e78f885SJean Perier   if (converter.getLoweringOptions().getLowerToHighLevelFIR())
2214e78f885SJean Perier     return Fortran::lower::convertExprToAddress(loc, converter, addr,
2224e78f885SJean Perier                                                 globalOpSymMap, stmtCtx);
22372276bdaSValentin Clement   return Fortran::lower::createInitializerAddress(loc, converter, addr,
22472276bdaSValentin Clement                                                   globalOpSymMap, stmtCtx);
22572276bdaSValentin Clement }
22672276bdaSValentin Clement 
2278c22cb84SValentin Clement /// create initial-data-target fir.box in a global initializer region.
2288c22cb84SValentin Clement mlir::Value Fortran::lower::genInitialDataTarget(
2298c22cb84SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
230518e6f12SV Donaldson     mlir::Type boxType, const Fortran::lower::SomeExpr &initialTarget,
231518e6f12SV Donaldson     bool couldBeInEquivalence) {
2328c22cb84SValentin Clement   Fortran::lower::SymMap globalOpSymMap;
2338c22cb84SValentin Clement   Fortran::lower::AggregateStoreMap storeMap;
2348c22cb84SValentin Clement   Fortran::lower::StatementContext stmtCtx;
2358c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
2368c22cb84SValentin Clement   if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
2378c22cb84SValentin Clement           initialTarget))
2389a417395SKazu Hirata     return fir::factory::createUnallocatedBox(
2399a417395SKazu Hirata         builder, loc, boxType,
2409a417395SKazu Hirata         /*nonDeferredParams=*/std::nullopt);
2418c22cb84SValentin Clement   // Pointer initial data target, and NULL(mold).
242e657acd4SValentin Clement   for (const auto &sym : Fortran::evaluate::CollectSymbols(initialTarget)) {
24341096d19SjeanPerier     // Derived type component symbols should not be instantiated as objects
24441096d19SjeanPerier     // on their own.
24541096d19SjeanPerier     if (sym->owner().IsDerivedType())
24641096d19SjeanPerier       continue;
2478c22cb84SValentin Clement     // Length parameters processing will need care in global initializer
2488c22cb84SValentin Clement     // context.
249e657acd4SValentin Clement     if (hasDerivedTypeWithLengthParameters(sym))
2508c22cb84SValentin Clement       TODO(loc, "initial-data-target with derived type length parameters");
251e657acd4SValentin Clement     auto var = Fortran::lower::pft::Variable(sym, /*global=*/true);
252518e6f12SV Donaldson     if (couldBeInEquivalence) {
253518e6f12SV Donaldson       auto dependentVariableList =
254518e6f12SV Donaldson           Fortran::lower::pft::getDependentVariableList(sym);
255518e6f12SV Donaldson       for (Fortran::lower::pft::Variable var : dependentVariableList) {
256518e6f12SV Donaldson         if (!var.isAggregateStore())
257518e6f12SV Donaldson           break;
258518e6f12SV Donaldson         instantiateVariable(converter, var, globalOpSymMap, storeMap);
259518e6f12SV Donaldson       }
260518e6f12SV Donaldson       var = dependentVariableList.back();
261518e6f12SV Donaldson       assert(var.getSymbol().name() == sym->name() &&
262518e6f12SV Donaldson              "missing symbol in dependence list");
263518e6f12SV Donaldson     }
2648c22cb84SValentin Clement     Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
2658c22cb84SValentin Clement                                         storeMap);
2668c22cb84SValentin Clement   }
267e657acd4SValentin Clement 
268e657acd4SValentin Clement   // Handle NULL(mold) as a special case. Return an unallocated box of MOLD
269e657acd4SValentin Clement   // type. The return box is correctly created as a fir.box<fir.ptr<T>> where
270e657acd4SValentin Clement   // T is extracted from the MOLD argument.
271e657acd4SValentin Clement   if (const Fortran::evaluate::ProcedureRef *procRef =
272f025e411SPeter Klausler           Fortran::evaluate::UnwrapProcedureRef(initialTarget)) {
273e657acd4SValentin Clement     const Fortran::evaluate::SpecificIntrinsic *intrinsic =
274e657acd4SValentin Clement         procRef->proc().GetSpecificIntrinsic();
275e657acd4SValentin Clement     if (intrinsic && intrinsic->name == "null") {
276e657acd4SValentin Clement       assert(procRef->arguments().size() == 1 &&
277e657acd4SValentin Clement              "Expecting mold argument for NULL intrinsic");
278e657acd4SValentin Clement       const auto *argExpr = procRef->arguments()[0].value().UnwrapExpr();
279e657acd4SValentin Clement       assert(argExpr);
280e657acd4SValentin Clement       const Fortran::semantics::Symbol *sym =
281e657acd4SValentin Clement           Fortran::evaluate::GetFirstSymbol(*argExpr);
282ab9c4e9fSJean Perier       assert(sym && "MOLD must be a pointer or allocatable symbol");
283ab9c4e9fSJean Perier       mlir::Type boxType = converter.genType(*sym);
284e657acd4SValentin Clement       mlir::Value box =
285e657acd4SValentin Clement           fir::factory::createUnallocatedBox(builder, loc, boxType, {});
286e657acd4SValentin Clement       return box;
287e657acd4SValentin Clement     }
288e657acd4SValentin Clement   }
289e657acd4SValentin Clement 
290de2811eeSJean Perier   mlir::Value targetBox;
291de2811eeSJean Perier   mlir::Value targetShift;
2924e78f885SJean Perier   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
2934e78f885SJean Perier     auto target = Fortran::lower::convertExprToBox(
2944e78f885SJean Perier         loc, converter, initialTarget, globalOpSymMap, stmtCtx);
2954e78f885SJean Perier     targetBox = fir::getBase(target);
2964e78f885SJean Perier     targetShift = builder.createShape(loc, target);
2974e78f885SJean Perier   } else {
2988c22cb84SValentin Clement     if (initialTarget.Rank() > 0) {
299de2811eeSJean Perier       auto target = Fortran::lower::createSomeArrayBox(converter, initialTarget,
300de2811eeSJean Perier                                                        globalOpSymMap, stmtCtx);
301de2811eeSJean Perier       targetBox = fir::getBase(target);
302de2811eeSJean Perier       targetShift = builder.createShape(loc, target);
3038c22cb84SValentin Clement     } else {
3048c22cb84SValentin Clement       fir::ExtendedValue addr = Fortran::lower::createInitializerAddress(
3058c22cb84SValentin Clement           loc, converter, initialTarget, globalOpSymMap, stmtCtx);
306de2811eeSJean Perier       targetBox = builder.createBox(loc, addr);
307de2811eeSJean Perier       // Nothing to do for targetShift, the target is a scalar.
3088c22cb84SValentin Clement     }
3094e78f885SJean Perier   }
310de2811eeSJean Perier   // The targetBox is a fir.box<T>, not a fir.box<fir.ptr<T>> as it should for
311de2811eeSJean Perier   // pointers (this matters to get the POINTER attribute correctly inside the
312de2811eeSJean Perier   // initial value of the descriptor).
313de2811eeSJean Perier   // Create a fir.rebox to set the attribute correctly, and use targetShift
314de2811eeSJean Perier   // to preserve the target lower bounds if any.
315de2811eeSJean Perier   return builder.create<fir::ReboxOp>(loc, boxType, targetBox, targetShift,
316de2811eeSJean Perier                                       /*slice=*/mlir::Value{});
3178c22cb84SValentin Clement }
3188c22cb84SValentin Clement 
319e45f6e93SjeanPerier /// Generate default initial value for a derived type object \p sym with mlir
320e45f6e93SjeanPerier /// type \p symTy.
3218c22cb84SValentin Clement static mlir::Value genDefaultInitializerValue(
3228c22cb84SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
3238c22cb84SValentin Clement     const Fortran::semantics::Symbol &sym, mlir::Type symTy,
324e45f6e93SjeanPerier     Fortran::lower::StatementContext &stmtCtx);
325e45f6e93SjeanPerier 
326e45f6e93SjeanPerier /// Generate the initial value of a derived component \p component and insert
327e45f6e93SjeanPerier /// it into the derived type initial value \p insertInto of type \p recTy.
328e45f6e93SjeanPerier /// Return the new derived type initial value after the insertion.
329e45f6e93SjeanPerier static mlir::Value genComponentDefaultInit(
330e45f6e93SjeanPerier     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
331e45f6e93SjeanPerier     const Fortran::semantics::Symbol &component, fir::RecordType recTy,
332e45f6e93SjeanPerier     mlir::Value insertInto, Fortran::lower::StatementContext &stmtCtx) {
3338c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
33499a54b83SjeanPerier   std::string name = converter.getRecordTypeFieldName(component);
3358c22cb84SValentin Clement   mlir::Type componentTy = recTy.getType(name);
3368c22cb84SValentin Clement   assert(componentTy && "component not found in type");
337e45f6e93SjeanPerier   mlir::Value componentValue;
3388c22cb84SValentin Clement   if (const auto *object{
3398c22cb84SValentin Clement           component.detailsIf<Fortran::semantics::ObjectEntityDetails>()}) {
3408c22cb84SValentin Clement     if (const auto &init = object->init()) {
3418c22cb84SValentin Clement       // Component has explicit initialization.
3428c22cb84SValentin Clement       if (Fortran::semantics::IsPointer(component))
3438c22cb84SValentin Clement         // Initial data target.
3448c22cb84SValentin Clement         componentValue =
3458c22cb84SValentin Clement             genInitialDataTarget(converter, loc, componentTy, *init);
3468c22cb84SValentin Clement       else
3478c22cb84SValentin Clement         // Initial value.
3488c22cb84SValentin Clement         componentValue = fir::getBase(
3498c22cb84SValentin Clement             genInitializerExprValue(converter, loc, *init, stmtCtx));
3508c22cb84SValentin Clement     } else if (Fortran::semantics::IsAllocatableOrPointer(component)) {
3518c22cb84SValentin Clement       // Pointer or allocatable without initialization.
3528c22cb84SValentin Clement       // Create deallocated/disassociated value.
3538c22cb84SValentin Clement       // From a standard point of view, pointer without initialization do not
3548c22cb84SValentin Clement       // need to be disassociated, but for sanity and simplicity, do it in
3558c22cb84SValentin Clement       // global constructor since this has no runtime cost.
3568c22cb84SValentin Clement       componentValue = fir::factory::createUnallocatedBox(
3579a417395SKazu Hirata           builder, loc, componentTy, std::nullopt);
35898e733eaSTom Eccles     } else if (Fortran::lower::hasDefaultInitialization(component)) {
3598c22cb84SValentin Clement       // Component type has default initialization.
3608c22cb84SValentin Clement       componentValue = genDefaultInitializerValue(converter, loc, component,
3618c22cb84SValentin Clement                                                   componentTy, stmtCtx);
3628c22cb84SValentin Clement     } else {
36387e25210SjeanPerier       // Component has no initial value. Set its bits to zero by extension
36487e25210SjeanPerier       // to match what is expected because other compilers are doing it.
36587e25210SjeanPerier       componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
3668c22cb84SValentin Clement     }
3678c22cb84SValentin Clement   } else if (const auto *proc{
3688c22cb84SValentin Clement                  component
3698c22cb84SValentin Clement                      .detailsIf<Fortran::semantics::ProcEntityDetails>()}) {
3707ec87c47SDaniel Chen     if (proc->init().has_value()) {
3717ec87c47SDaniel Chen       auto sym{*proc->init()};
3727ec87c47SDaniel Chen       if (sym) // Has a procedure target.
3737ec87c47SDaniel Chen         componentValue =
3747ec87c47SDaniel Chen             Fortran::lower::convertProcedureDesignatorInitialTarget(converter,
3757ec87c47SDaniel Chen                                                                     loc, *sym);
3767ec87c47SDaniel Chen       else // Has NULL() target.
3777ec87c47SDaniel Chen         componentValue =
3787ec87c47SDaniel Chen             fir::factory::createNullBoxProc(builder, loc, componentTy);
3797ec87c47SDaniel Chen     } else
38087e25210SjeanPerier       componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
3818c22cb84SValentin Clement   }
3828c22cb84SValentin Clement   assert(componentValue && "must have been computed");
3838c22cb84SValentin Clement   componentValue = builder.createConvert(loc, componentTy, componentValue);
384e45f6e93SjeanPerier   auto fieldTy = fir::FieldType::get(recTy.getContext());
3858c22cb84SValentin Clement   // FIXME: type parameters must come from the derived-type-spec
3868c22cb84SValentin Clement   auto field = builder.create<fir::FieldIndexOp>(
387e45f6e93SjeanPerier       loc, fieldTy, name, recTy,
3888c22cb84SValentin Clement       /*typeParams=*/mlir::ValueRange{} /*TODO*/);
389e45f6e93SjeanPerier   return builder.create<fir::InsertValueOp>(
390e45f6e93SjeanPerier       loc, recTy, insertInto, componentValue,
3918c22cb84SValentin Clement       builder.getArrayAttr(field.getAttributes()));
3928c22cb84SValentin Clement }
3938c22cb84SValentin Clement 
394e45f6e93SjeanPerier static mlir::Value genDefaultInitializerValue(
395e45f6e93SjeanPerier     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
396e45f6e93SjeanPerier     const Fortran::semantics::Symbol &sym, mlir::Type symTy,
397e45f6e93SjeanPerier     Fortran::lower::StatementContext &stmtCtx) {
398e45f6e93SjeanPerier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
399e45f6e93SjeanPerier   mlir::Type scalarType = symTy;
400e45f6e93SjeanPerier   fir::SequenceType sequenceType;
401fac349a1SChristian Sigg   if (auto ty = mlir::dyn_cast<fir::SequenceType>(symTy)) {
402e45f6e93SjeanPerier     sequenceType = ty;
403e45f6e93SjeanPerier     scalarType = ty.getEleTy();
404e45f6e93SjeanPerier   }
405e45f6e93SjeanPerier   // Build a scalar default value of the symbol type, looping through the
406e45f6e93SjeanPerier   // components to build each component initial value.
407fac349a1SChristian Sigg   auto recTy = mlir::cast<fir::RecordType>(scalarType);
408e45f6e93SjeanPerier   mlir::Value initialValue = builder.create<fir::UndefOp>(loc, scalarType);
409e45f6e93SjeanPerier   const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
410e45f6e93SjeanPerier   assert(declTy && "var with default initialization must have a type");
411e45f6e93SjeanPerier 
412e45f6e93SjeanPerier   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
413e45f6e93SjeanPerier     // In HLFIR, the parent type is the first component, while in FIR there is
414e45f6e93SjeanPerier     // not parent component in the fir.type and the component of the parent are
415e45f6e93SjeanPerier     // "inlined" at the beginning of the fir.type.
416e45f6e93SjeanPerier     const Fortran::semantics::Symbol &typeSymbol =
417e45f6e93SjeanPerier         declTy->derivedTypeSpec().typeSymbol();
418e45f6e93SjeanPerier     const Fortran::semantics::Scope *derivedScope =
419e45f6e93SjeanPerier         declTy->derivedTypeSpec().GetScope();
420e45f6e93SjeanPerier     assert(derivedScope && "failed to retrieve derived type scope");
421e45f6e93SjeanPerier     for (const auto &componentName :
422e45f6e93SjeanPerier          typeSymbol.get<Fortran::semantics::DerivedTypeDetails>()
423e45f6e93SjeanPerier              .componentNames()) {
424e45f6e93SjeanPerier       auto scopeIter = derivedScope->find(componentName);
425e45f6e93SjeanPerier       assert(scopeIter != derivedScope->cend() &&
426e45f6e93SjeanPerier              "failed to find derived type component symbol");
427e45f6e93SjeanPerier       const Fortran::semantics::Symbol &component = scopeIter->second.get();
428e45f6e93SjeanPerier       initialValue = genComponentDefaultInit(converter, loc, component, recTy,
429e45f6e93SjeanPerier                                              initialValue, stmtCtx);
430e45f6e93SjeanPerier     }
431e45f6e93SjeanPerier   } else {
432e45f6e93SjeanPerier     Fortran::semantics::OrderedComponentIterator components(
433e45f6e93SjeanPerier         declTy->derivedTypeSpec());
434e45f6e93SjeanPerier     for (const auto &component : components) {
435e45f6e93SjeanPerier       // Skip parent components, the sub-components of parent types are part of
436e45f6e93SjeanPerier       // components and will be looped through right after.
437e45f6e93SjeanPerier       if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
438e45f6e93SjeanPerier         continue;
439e45f6e93SjeanPerier       initialValue = genComponentDefaultInit(converter, loc, component, recTy,
440e45f6e93SjeanPerier                                              initialValue, stmtCtx);
441e45f6e93SjeanPerier     }
442e45f6e93SjeanPerier   }
443e45f6e93SjeanPerier 
4448c22cb84SValentin Clement   if (sequenceType) {
4458c22cb84SValentin Clement     // For arrays, duplicate the scalar value to all elements with an
4468c22cb84SValentin Clement     // fir.insert_range covering the whole array.
4478c22cb84SValentin Clement     auto arrayInitialValue = builder.create<fir::UndefOp>(loc, sequenceType);
4488c22cb84SValentin Clement     llvm::SmallVector<int64_t> rangeBounds;
4498c22cb84SValentin Clement     for (int64_t extent : sequenceType.getShape()) {
4508c22cb84SValentin Clement       if (extent == fir::SequenceType::getUnknownExtent())
4518c22cb84SValentin Clement         TODO(loc,
4528c22cb84SValentin Clement              "default initial value of array component with length parameters");
4538c22cb84SValentin Clement       rangeBounds.push_back(0);
4548c22cb84SValentin Clement       rangeBounds.push_back(extent - 1);
4558c22cb84SValentin Clement     }
4568c22cb84SValentin Clement     return builder.create<fir::InsertOnRangeOp>(
4578c22cb84SValentin Clement         loc, sequenceType, arrayInitialValue, initialValue,
4588c22cb84SValentin Clement         builder.getIndexVectorAttr(rangeBounds));
4598c22cb84SValentin Clement   }
4608c22cb84SValentin Clement   return initialValue;
4618c22cb84SValentin Clement }
4628c22cb84SValentin Clement 
4638c22cb84SValentin Clement /// Does this global already have an initializer ?
4648c22cb84SValentin Clement static bool globalIsInitialized(fir::GlobalOp global) {
4658c22cb84SValentin Clement   return !global.getRegion().empty() || global.getInitVal();
4668c22cb84SValentin Clement }
4678c22cb84SValentin Clement 
4688c22cb84SValentin Clement /// Call \p genInit to generate code inside \p global initializer region.
4698f119da5SPeixin Qiao void Fortran::lower::createGlobalInitialization(
4708f119da5SPeixin Qiao     fir::FirOpBuilder &builder, fir::GlobalOp global,
4718c22cb84SValentin Clement     std::function<void(fir::FirOpBuilder &)> genInit) {
4728c22cb84SValentin Clement   mlir::Region &region = global.getRegion();
4738c22cb84SValentin Clement   region.push_back(new mlir::Block);
4748c22cb84SValentin Clement   mlir::Block &block = region.back();
4758c22cb84SValentin Clement   auto insertPt = builder.saveInsertionPoint();
4768c22cb84SValentin Clement   builder.setInsertionPointToStart(&block);
4778c22cb84SValentin Clement   genInit(builder);
4788c22cb84SValentin Clement   builder.restoreInsertionPoint(insertPt);
4798c22cb84SValentin Clement }
4808c22cb84SValentin Clement 
4810dcd68c2SValentin Clement (バレンタイン クレメン) static unsigned getAllocatorIdx(cuf::DataAttributeAttr dataAttr) {
4820dcd68c2SValentin Clement (バレンタイン クレメン)   if (dataAttr) {
4830dcd68c2SValentin Clement (バレンタイン クレメン)     if (dataAttr.getValue() == cuf::DataAttribute::Pinned)
4840dcd68c2SValentin Clement (バレンタイン クレメン)       return kPinnedAllocatorPos;
4850dcd68c2SValentin Clement (バレンタイン クレメン)     if (dataAttr.getValue() == cuf::DataAttribute::Device)
4860dcd68c2SValentin Clement (バレンタイン クレメン)       return kDeviceAllocatorPos;
4870dcd68c2SValentin Clement (バレンタイン クレメン)     if (dataAttr.getValue() == cuf::DataAttribute::Managed)
4880dcd68c2SValentin Clement (バレンタイン クレメン)       return kManagedAllocatorPos;
4890dcd68c2SValentin Clement (バレンタイン クレメン)     if (dataAttr.getValue() == cuf::DataAttribute::Unified)
4900dcd68c2SValentin Clement (バレンタイン クレメン)       return kUnifiedAllocatorPos;
4910dcd68c2SValentin Clement (バレンタイン クレメン)   }
4920dcd68c2SValentin Clement (バレンタイン クレメン)   return kDefaultAllocator;
4930dcd68c2SValentin Clement (バレンタイン クレメン) }
4940dcd68c2SValentin Clement (バレンタイン クレメン) 
4958c22cb84SValentin Clement /// Create the global op and its init if it has one
4968c22cb84SValentin Clement static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
4978c22cb84SValentin Clement                                   const Fortran::lower::pft::Variable &var,
4988c22cb84SValentin Clement                                   llvm::StringRef globalName,
499314ef961SValentin Clement (バレンタイン クレメン)                                   mlir::StringAttr linkage,
50045daa4fdSValentin Clement (バレンタイン クレメン)                                   cuf::DataAttributeAttr dataAttr) {
5018c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
5028c22cb84SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
50353804e42SValentin Clement   mlir::Location loc = genLocation(converter, sym);
5048c22cb84SValentin Clement   bool isConst = isConstant(sym);
5058c22cb84SValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(globalName);
5068c22cb84SValentin Clement   mlir::Type symTy = converter.genType(var);
5078c22cb84SValentin Clement 
5088c22cb84SValentin Clement   if (global && globalIsInitialized(global))
5098c22cb84SValentin Clement     return global;
5101e1f60c6SV Donaldson 
511af09219eSDaniel Chen   if (!converter.getLoweringOptions().getLowerToHighLevelFIR() &&
512af09219eSDaniel Chen       Fortran::semantics::IsProcedurePointer(sym))
5131e1f60c6SV Donaldson     TODO(loc, "procedure pointer globals");
5141e1f60c6SV Donaldson 
5158c22cb84SValentin Clement   // If this is an array, check to see if we can use a dense attribute
5168c22cb84SValentin Clement   // with a tensor mlir type. This optimization currently only supports
517c8517f17SLeandro Lupori   // Fortran arrays of integer, real, complex, or logical. The tensor
518c8517f17SLeandro Lupori   // type does not support nested structures.
519fac349a1SChristian Sigg   if (mlir::isa<fir::SequenceType>(symTy) &&
5208c22cb84SValentin Clement       !Fortran::semantics::IsAllocatableOrPointer(sym)) {
521e6a4346bSScott Manley     mlir::Type eleTy = mlir::cast<fir::SequenceType>(symTy).getElementType();
522c4204c0bSjeanPerier     if (mlir::isa<mlir::IntegerType, mlir::FloatType, mlir::ComplexType,
523bd9fdce6SChristian Sigg                   fir::LogicalType>(eleTy)) {
5248c22cb84SValentin Clement       const auto *details =
5258c22cb84SValentin Clement           sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
5268c22cb84SValentin Clement       if (details->init()) {
527af91b193SJean Perier         global = Fortran::lower::tryCreatingDenseGlobal(
528af91b193SJean Perier             builder, loc, symTy, globalName, linkage, isConst,
5293a47d948SValentin Clement (バレンタイン クレメン)             details->init().value(), dataAttr);
5308c22cb84SValentin Clement         if (global) {
5318c22cb84SValentin Clement           global.setVisibility(mlir::SymbolTable::Visibility::Public);
5328c22cb84SValentin Clement           return global;
5338c22cb84SValentin Clement         }
5348c22cb84SValentin Clement       }
5358c22cb84SValentin Clement     }
5368c22cb84SValentin Clement   }
5378c22cb84SValentin Clement   if (!global)
538314ef961SValentin Clement (バレンタイン クレメン)     global =
539314ef961SValentin Clement (バレンタイン クレメン)         builder.createGlobal(loc, symTy, globalName, linkage, mlir::Attribute{},
54045daa4fdSValentin Clement (バレンタイン クレメン)                              isConst, var.isTarget(), dataAttr);
541af09219eSDaniel Chen   if (Fortran::semantics::IsAllocatableOrPointer(sym) &&
542af09219eSDaniel Chen       !Fortran::semantics::IsProcedure(sym)) {
5438c22cb84SValentin Clement     const auto *details =
5448c22cb84SValentin Clement         sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
5458c22cb84SValentin Clement     if (details && details->init()) {
5468c22cb84SValentin Clement       auto expr = *details->init();
5478f119da5SPeixin Qiao       Fortran::lower::createGlobalInitialization(
5488f119da5SPeixin Qiao           builder, global, [&](fir::FirOpBuilder &b) {
5498f119da5SPeixin Qiao             mlir::Value box = Fortran::lower::genInitialDataTarget(
5508f119da5SPeixin Qiao                 converter, loc, symTy, expr);
5518c22cb84SValentin Clement             b.create<fir::HasValueOp>(loc, box);
5528c22cb84SValentin Clement           });
5538c22cb84SValentin Clement     } else {
5548c22cb84SValentin Clement       // Create unallocated/disassociated descriptor if no explicit init
5558f119da5SPeixin Qiao       Fortran::lower::createGlobalInitialization(
5568f119da5SPeixin Qiao           builder, global, [&](fir::FirOpBuilder &b) {
5570dcd68c2SValentin Clement (バレンタイン クレメン)             mlir::Value box = fir::factory::createUnallocatedBox(
5580dcd68c2SValentin Clement (バレンタイン クレメン)                 b, loc, symTy,
5590dcd68c2SValentin Clement (バレンタイン クレメン)                 /*nonDeferredParams=*/std::nullopt,
5600dcd68c2SValentin Clement (バレンタイン クレメン)                 /*typeSourceBox=*/{}, getAllocatorIdx(dataAttr));
5618c22cb84SValentin Clement             b.create<fir::HasValueOp>(loc, box);
5628c22cb84SValentin Clement           });
5638c22cb84SValentin Clement     }
5648c22cb84SValentin Clement   } else if (const auto *details =
5658c22cb84SValentin Clement                  sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
5668c22cb84SValentin Clement     if (details->init()) {
5678f119da5SPeixin Qiao       Fortran::lower::createGlobalInitialization(
5688c22cb84SValentin Clement           builder, global, [&](fir::FirOpBuilder &builder) {
5698c22cb84SValentin Clement             Fortran::lower::StatementContext stmtCtx(
5708c22cb84SValentin Clement                 /*cleanupProhibited=*/true);
5718c22cb84SValentin Clement             fir::ExtendedValue initVal = genInitializerExprValue(
5728c22cb84SValentin Clement                 converter, loc, details->init().value(), stmtCtx);
5738c22cb84SValentin Clement             mlir::Value castTo =
5748c22cb84SValentin Clement                 builder.createConvert(loc, symTy, fir::getBase(initVal));
5758c22cb84SValentin Clement             builder.create<fir::HasValueOp>(loc, castTo);
5768c22cb84SValentin Clement           });
57798e733eaSTom Eccles     } else if (Fortran::lower::hasDefaultInitialization(sym)) {
5788f119da5SPeixin Qiao       Fortran::lower::createGlobalInitialization(
5798c22cb84SValentin Clement           builder, global, [&](fir::FirOpBuilder &builder) {
5808c22cb84SValentin Clement             Fortran::lower::StatementContext stmtCtx(
5818c22cb84SValentin Clement                 /*cleanupProhibited=*/true);
5828c22cb84SValentin Clement             mlir::Value initVal =
5838c22cb84SValentin Clement                 genDefaultInitializerValue(converter, loc, sym, symTy, stmtCtx);
5848c22cb84SValentin Clement             mlir::Value castTo = builder.createConvert(loc, symTy, initVal);
5858c22cb84SValentin Clement             builder.create<fir::HasValueOp>(loc, castTo);
5868c22cb84SValentin Clement           });
5878c22cb84SValentin Clement     }
588af09219eSDaniel Chen   } else if (Fortran::semantics::IsProcedurePointer(sym)) {
589af09219eSDaniel Chen     const auto *details{sym.detailsIf<Fortran::semantics::ProcEntityDetails>()};
590af09219eSDaniel Chen     if (details && details->init()) {
591af09219eSDaniel Chen       auto sym{*details->init()};
592af09219eSDaniel Chen       if (sym) // Has a procedure target.
593af09219eSDaniel Chen         Fortran::lower::createGlobalInitialization(
594af09219eSDaniel Chen             builder, global, [&](fir::FirOpBuilder &b) {
595af09219eSDaniel Chen               Fortran::lower::StatementContext stmtCtx(
596af09219eSDaniel Chen                   /*cleanupProhibited=*/true);
597af09219eSDaniel Chen               auto box{Fortran::lower::convertProcedureDesignatorInitialTarget(
598af09219eSDaniel Chen                   converter, loc, *sym)};
599af09219eSDaniel Chen               auto castTo{builder.createConvert(loc, symTy, box)};
600af09219eSDaniel Chen               b.create<fir::HasValueOp>(loc, castTo);
601af09219eSDaniel Chen             });
602af09219eSDaniel Chen       else { // Has NULL() target.
603af09219eSDaniel Chen         Fortran::lower::createGlobalInitialization(
604af09219eSDaniel Chen             builder, global, [&](fir::FirOpBuilder &b) {
605af09219eSDaniel Chen               auto box{fir::factory::createNullBoxProc(b, loc, symTy)};
606af09219eSDaniel Chen               b.create<fir::HasValueOp>(loc, box);
607af09219eSDaniel Chen             });
608af09219eSDaniel Chen       }
609af09219eSDaniel Chen     } else {
610af09219eSDaniel Chen       // No initialization.
611af09219eSDaniel Chen       Fortran::lower::createGlobalInitialization(
612af09219eSDaniel Chen           builder, global, [&](fir::FirOpBuilder &b) {
613af09219eSDaniel Chen             auto box{fir::factory::createNullBoxProc(b, loc, symTy)};
614af09219eSDaniel Chen             b.create<fir::HasValueOp>(loc, box);
615af09219eSDaniel Chen           });
616af09219eSDaniel Chen     }
6178c22cb84SValentin Clement   } else if (sym.has<Fortran::semantics::CommonBlockDetails>()) {
6188c22cb84SValentin Clement     mlir::emitError(loc, "COMMON symbol processed elsewhere");
6198c22cb84SValentin Clement   } else {
620af09219eSDaniel Chen     TODO(loc, "global"); // Something else
6218c22cb84SValentin Clement   }
622bb38f268SjeanPerier   // Creates zero initializer for globals without initializers, this is a common
623bb38f268SjeanPerier   // and expected behavior (although not required by the standard)
62410b23ae8SValentin Clement   if (!globalIsInitialized(global)) {
625a96b4671SjeanPerier     // Fortran does not provide means to specify that a BIND(C) module
626a96b4671SjeanPerier     // uninitialized variables will be defined in C.
627a96b4671SjeanPerier     // Add the common linkage to those to allow some level of support
628a96b4671SjeanPerier     // for this use case. Note that this use case will not work if the Fortran
629a96b4671SjeanPerier     // module code is placed in a shared library since, at least for the ELF
630a96b4671SjeanPerier     // format, common symbols are assigned a section in shared libraries.
631a96b4671SjeanPerier     // The best is still to declare C defined variables in a Fortran module file
632a96b4671SjeanPerier     // with no other definitions, and to never link the resulting module object
633a96b4671SjeanPerier     // file.
63410b23ae8SValentin Clement     if (sym.attrs().test(Fortran::semantics::Attr::BIND_C))
635a96b4671SjeanPerier       global.setLinkName(builder.createCommonLinkage());
6368f119da5SPeixin Qiao     Fortran::lower::createGlobalInitialization(
6378c22cb84SValentin Clement         builder, global, [&](fir::FirOpBuilder &builder) {
638*ce326259SKiran Chandramohan           mlir::Value initValue;
639*ce326259SKiran Chandramohan           if (converter.getLoweringOptions().getInitGlobalZero())
640*ce326259SKiran Chandramohan             initValue = builder.create<fir::ZeroOp>(loc, symTy);
641*ce326259SKiran Chandramohan           else
642*ce326259SKiran Chandramohan             initValue = builder.create<fir::UndefOp>(loc, symTy);
64343cf32a1SMats Petersson           builder.create<fir::HasValueOp>(loc, initValue);
6448c22cb84SValentin Clement         });
64510b23ae8SValentin Clement   }
6468c22cb84SValentin Clement   // Set public visibility to prevent global definition to be optimized out
6478c22cb84SValentin Clement   // even if they have no initializer and are unused in this compilation unit.
6488c22cb84SValentin Clement   global.setVisibility(mlir::SymbolTable::Visibility::Public);
6498c22cb84SValentin Clement   return global;
6508c22cb84SValentin Clement }
6518c22cb84SValentin Clement 
6528c22cb84SValentin Clement /// Return linkage attribute for \p var.
6538c22cb84SValentin Clement static mlir::StringAttr
6548c22cb84SValentin Clement getLinkageAttribute(fir::FirOpBuilder &builder,
6558c22cb84SValentin Clement                     const Fortran::lower::pft::Variable &var) {
656a1425019SValentin Clement   // Runtime type info for a same derived type is identical in each compilation
657a1425019SValentin Clement   // unit. It desired to avoid having to link against module that only define a
658a1425019SValentin Clement   // type. Therefore the runtime type info is generated everywhere it is needed
659a1425019SValentin Clement   // with `linkonce_odr` LLVM linkage.
6600a45d172SjeanPerier   if (var.isRuntimeTypeInfoData())
661a1425019SValentin Clement     return builder.createLinkOnceODRLinkage();
662518e6f12SV Donaldson   if (var.isModuleOrSubmoduleVariable())
6638c22cb84SValentin Clement     return {}; // external linkage
6648c22cb84SValentin Clement   // Otherwise, the variable is owned by a procedure and must not be visible in
6658c22cb84SValentin Clement   // other compilation units.
6668c22cb84SValentin Clement   return builder.createInternalLinkage();
6678c22cb84SValentin Clement }
6688c22cb84SValentin Clement 
6698c22cb84SValentin Clement /// Instantiate a global variable. If it hasn't already been processed, add
6708c22cb84SValentin Clement /// the global to the ModuleOp as a new uniqued symbol and initialize it with
6718c22cb84SValentin Clement /// the correct value. It will be referenced on demand using `fir.addr_of`.
6728c22cb84SValentin Clement static void instantiateGlobal(Fortran::lower::AbstractConverter &converter,
6738c22cb84SValentin Clement                               const Fortran::lower::pft::Variable &var,
6748c22cb84SValentin Clement                               Fortran::lower::SymMap &symMap) {
6758c22cb84SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
6768c22cb84SValentin Clement   assert(!var.isAlias() && "must be handled in instantiateAlias");
6778c22cb84SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
6782c143345SV Donaldson   std::string globalName = converter.mangleName(sym);
67953804e42SValentin Clement   mlir::Location loc = genLocation(converter, sym);
6808c22cb84SValentin Clement   mlir::StringAttr linkage = getLinkageAttribute(builder, var);
6813aba9264Svdonaldson   fir::GlobalOp global;
682518e6f12SV Donaldson   if (var.isModuleOrSubmoduleVariable()) {
6833aba9264Svdonaldson     // A non-intrinsic module global is defined when lowering the module.
6843aba9264Svdonaldson     // Emit only a declaration if the global does not exist.
6858c22cb84SValentin Clement     global = declareGlobal(converter, var, globalName, linkage);
6868c22cb84SValentin Clement   } else {
687702198fcSValentin Clement (バレンタイン クレメン)     cuf::DataAttributeAttr dataAttr =
688702198fcSValentin Clement (バレンタイン クレメン)         Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
689702198fcSValentin Clement (バレンタイン クレメン)                                                         sym);
690702198fcSValentin Clement (バレンタイン クレメン)     global = defineGlobal(converter, var, globalName, linkage, dataAttr);
6918c22cb84SValentin Clement   }
6928c22cb84SValentin Clement   auto addrOf = builder.create<fir::AddrOfOp>(loc, global.resultType(),
6938c22cb84SValentin Clement                                               global.getSymbol());
6948c22cb84SValentin Clement   Fortran::lower::StatementContext stmtCtx;
6958c22cb84SValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx, addrOf);
6968c22cb84SValentin Clement }
6978c22cb84SValentin Clement 
6982c2e5a5dSValentin Clement //===----------------------------------------------------------------===//
6992c2e5a5dSValentin Clement // Local variables instantiation (not for alias)
7002c2e5a5dSValentin Clement //===----------------------------------------------------------------===//
7012c2e5a5dSValentin Clement 
7022c2e5a5dSValentin Clement /// Create a stack slot for a local variable. Precondition: the insertion
7032c2e5a5dSValentin Clement /// point of the builder must be in the entry block, which is currently being
7042c2e5a5dSValentin Clement /// constructed.
7052c2e5a5dSValentin Clement static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
7062c2e5a5dSValentin Clement                                   mlir::Location loc,
7072c2e5a5dSValentin Clement                                   const Fortran::lower::pft::Variable &var,
7082c2e5a5dSValentin Clement                                   mlir::Value preAlloc,
7092c2e5a5dSValentin Clement                                   llvm::ArrayRef<mlir::Value> shape = {},
7102c2e5a5dSValentin Clement                                   llvm::ArrayRef<mlir::Value> lenParams = {}) {
7112c2e5a5dSValentin Clement   if (preAlloc)
7122c2e5a5dSValentin Clement     return preAlloc;
7132c2e5a5dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
7142c143345SV Donaldson   std::string nm = converter.mangleName(var.getSymbol());
7152c2e5a5dSValentin Clement   mlir::Type ty = converter.genType(var);
7162c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &ultimateSymbol =
7172c2e5a5dSValentin Clement       var.getSymbol().GetUltimate();
7182c2e5a5dSValentin Clement   llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
7192c2e5a5dSValentin Clement   bool isTarg = var.isTarget();
720af09219eSDaniel Chen 
72127cfe7a0SjeanPerier   // Do not allocate storage for cray pointee. The address inside the cray
72227cfe7a0SjeanPerier   // pointer will be used instead when using the pointee. Allocating space
72327cfe7a0SjeanPerier   // would be a waste of space, and incorrect if the pointee is a non dummy
72427cfe7a0SjeanPerier   // assumed-size (possible with cray pointee).
72527cfe7a0SjeanPerier   if (ultimateSymbol.test(Fortran::semantics::Symbol::Flag::CrayPointee))
72627cfe7a0SjeanPerier     return builder.create<fir::ZeroOp>(loc, fir::ReferenceType::get(ty));
72727cfe7a0SjeanPerier 
72826060de0SValentin Clement (バレンタイン クレメン)   if (Fortran::semantics::NeedCUDAAlloc(ultimateSymbol)) {
72945daa4fdSValentin Clement (バレンタイン クレメン)     cuf::DataAttributeAttr dataAttr =
73045daa4fdSValentin Clement (バレンタイン クレメン)         Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
73126060de0SValentin Clement (バレンタイン クレメン)                                                         ultimateSymbol);
73226060de0SValentin Clement (バレンタイン クレメン)     llvm::SmallVector<mlir::Value> indices;
73326060de0SValentin Clement (バレンタイン クレメン)     llvm::SmallVector<mlir::Value> elidedShape =
73426060de0SValentin Clement (バレンタイン クレメン)         fir::factory::elideExtentsAlreadyInType(ty, shape);
73526060de0SValentin Clement (バレンタイン クレメン)     llvm::SmallVector<mlir::Value> elidedLenParams =
73626060de0SValentin Clement (バレンタイン クレメン)         fir::factory::elideLengthsAlreadyInType(ty, lenParams);
73726060de0SValentin Clement (バレンタイン クレメン)     auto idxTy = builder.getIndexType();
73826060de0SValentin Clement (バレンタイン クレメン)     for (mlir::Value sh : elidedShape)
73926060de0SValentin Clement (バレンタイン クレメン)       indices.push_back(builder.createConvert(loc, idxTy, sh));
74033cb29ccSValentin Clement (バレンタイン クレメン)     mlir::Value alloc = builder.create<cuf::AllocOp>(
74133cb29ccSValentin Clement (バレンタイン クレメン)         loc, ty, nm, symNm, dataAttr, lenParams, indices);
74233cb29ccSValentin Clement (バレンタイン クレメン)     return alloc;
74326060de0SValentin Clement (バレンタイン クレメン)   }
74426060de0SValentin Clement (バレンタイン クレメン) 
7452c2e5a5dSValentin Clement   // Let the builder do all the heavy lifting.
746af09219eSDaniel Chen   if (!Fortran::semantics::IsProcedurePointer(ultimateSymbol))
7472c2e5a5dSValentin Clement     return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg);
748af09219eSDaniel Chen 
749af09219eSDaniel Chen   // Local procedure pointer.
750af09219eSDaniel Chen   auto res{builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg)};
751af09219eSDaniel Chen   auto box{fir::factory::createNullBoxProc(builder, loc, ty)};
752af09219eSDaniel Chen   builder.create<fir::StoreOp>(loc, box, res);
753af09219eSDaniel Chen   return res;
7542c2e5a5dSValentin Clement }
7552c2e5a5dSValentin Clement 
756a1425019SValentin Clement /// Must \p var be default initialized at runtime when entering its scope.
757a1425019SValentin Clement static bool
758a1425019SValentin Clement mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable &var) {
759a1425019SValentin Clement   if (!var.hasSymbol())
760a1425019SValentin Clement     return false;
761a1425019SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
762a1425019SValentin Clement   if (var.isGlobal())
763a1425019SValentin Clement     // Global variables are statically initialized.
764a1425019SValentin Clement     return false;
765a1425019SValentin Clement   if (Fortran::semantics::IsDummy(sym) && !Fortran::semantics::IsIntentOut(sym))
766a1425019SValentin Clement     return false;
767fdc3dd70SValentin Clement   // Polymorphic intent(out) dummy might need default initialization
768fdc3dd70SValentin Clement   // at runtime.
769fdc3dd70SValentin Clement   if (Fortran::semantics::IsPolymorphic(sym) &&
770287e9e98SValentin Clement       Fortran::semantics::IsDummy(sym) &&
771287e9e98SValentin Clement       Fortran::semantics::IsIntentOut(sym) &&
772287e9e98SValentin Clement       !Fortran::semantics::IsAllocatable(sym) &&
773287e9e98SValentin Clement       !Fortran::semantics::IsPointer(sym))
774fdc3dd70SValentin Clement     return true;
775a1425019SValentin Clement   // Local variables (including function results), and intent(out) dummies must
776a1425019SValentin Clement   // be default initialized at runtime if their type has default initialization.
77798e733eaSTom Eccles   return Fortran::lower::hasDefaultInitialization(sym);
778a1425019SValentin Clement }
779a1425019SValentin Clement 
780a1425019SValentin Clement /// Call default initialization runtime routine to initialize \p var.
78198e733eaSTom Eccles void Fortran::lower::defaultInitializeAtRuntime(
78298e733eaSTom Eccles     Fortran::lower::AbstractConverter &converter,
78398e733eaSTom Eccles     const Fortran::semantics::Symbol &sym, Fortran::lower::SymMap &symMap) {
784a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
785a1425019SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
786ab9c4e9fSJean Perier   fir::ExtendedValue exv = converter.getSymbolExtendedValue(sym, &symMap);
787a1425019SValentin Clement   if (Fortran::semantics::IsOptional(sym)) {
788a1425019SValentin Clement     // 15.5.2.12 point 3, absent optional dummies are not initialized.
789a1425019SValentin Clement     // Creating descriptor/passing null descriptor to the runtime would
790a1425019SValentin Clement     // create runtime crashes.
791a1425019SValentin Clement     auto isPresent = builder.create<fir::IsPresentOp>(loc, builder.getI1Type(),
792a1425019SValentin Clement                                                       fir::getBase(exv));
793a1425019SValentin Clement     builder.genIfThen(loc, isPresent)
794a1425019SValentin Clement         .genThen([&]() {
795a1425019SValentin Clement           auto box = builder.createBox(loc, exv);
796a1425019SValentin Clement           fir::runtime::genDerivedTypeInitialize(builder, loc, box);
797a1425019SValentin Clement         })
798a1425019SValentin Clement         .end();
799a1425019SValentin Clement   } else {
800a1425019SValentin Clement     mlir::Value box = builder.createBox(loc, exv);
801a1425019SValentin Clement     fir::runtime::genDerivedTypeInitialize(builder, loc, box);
802a1425019SValentin Clement   }
803a1425019SValentin Clement }
804a1425019SValentin Clement 
8051fcb6a97SLeandro Lupori /// Call clone initialization runtime routine to initialize \p sym's value.
8061fcb6a97SLeandro Lupori void Fortran::lower::initializeCloneAtRuntime(
8071fcb6a97SLeandro Lupori     Fortran::lower::AbstractConverter &converter,
8081fcb6a97SLeandro Lupori     const Fortran::semantics::Symbol &sym, Fortran::lower::SymMap &symMap) {
8091fcb6a97SLeandro Lupori   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
8101fcb6a97SLeandro Lupori   mlir::Location loc = converter.getCurrentLocation();
8111fcb6a97SLeandro Lupori   fir::ExtendedValue exv = converter.getSymbolExtendedValue(sym, &symMap);
8121fcb6a97SLeandro Lupori   mlir::Value newBox = builder.createBox(loc, exv);
8131fcb6a97SLeandro Lupori   lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol(sym);
8141fcb6a97SLeandro Lupori   fir::ExtendedValue hexv = converter.symBoxToExtendedValue(hsb);
8151fcb6a97SLeandro Lupori   mlir::Value box = builder.createBox(loc, hexv);
8161fcb6a97SLeandro Lupori   fir::runtime::genDerivedTypeInitializeClone(builder, loc, newBox, box);
8171fcb6a97SLeandro Lupori }
8181fcb6a97SLeandro Lupori 
8190c7d0ad9SjeanPerier enum class VariableCleanUp { Finalize, Deallocate };
8200c7d0ad9SjeanPerier /// Check whether a local variable needs to be finalized according to clause
8210c7d0ad9SjeanPerier /// 7.5.6.3 point 3 or if it is an allocatable that must be deallocated. Note
8220c7d0ad9SjeanPerier /// that deallocation will trigger finalization if the type has any.
8230c7d0ad9SjeanPerier static std::optional<VariableCleanUp>
8240c7d0ad9SjeanPerier needDeallocationOrFinalization(const Fortran::lower::pft::Variable &var) {
82597492fd1SValentin Clement   if (!var.hasSymbol())
8260c7d0ad9SjeanPerier     return std::nullopt;
82797492fd1SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
8288730fe95SSlava Zakharin   const Fortran::semantics::Scope &owner = sym.owner();
8298730fe95SSlava Zakharin   if (owner.kind() == Fortran::semantics::Scope::Kind::MainProgram) {
8308730fe95SSlava Zakharin     // The standard does not require finalizing main program variables.
8310c7d0ad9SjeanPerier     return std::nullopt;
8328730fe95SSlava Zakharin   }
83397492fd1SValentin Clement   if (!Fortran::semantics::IsPointer(sym) &&
83497492fd1SValentin Clement       !Fortran::semantics::IsDummy(sym) &&
83597492fd1SValentin Clement       !Fortran::semantics::IsFunctionResult(sym) &&
8360c7d0ad9SjeanPerier       !Fortran::semantics::IsSaved(sym)) {
8370c7d0ad9SjeanPerier     if (Fortran::semantics::IsAllocatable(sym))
8380c7d0ad9SjeanPerier       return VariableCleanUp::Deallocate;
8390c7d0ad9SjeanPerier     if (hasFinalization(sym))
8400c7d0ad9SjeanPerier       return VariableCleanUp::Finalize;
841be66a2f6SSlava Zakharin     // hasFinalization() check above handled all cases that require
842be66a2f6SSlava Zakharin     // finalization, but we also have to deallocate all allocatable
843be66a2f6SSlava Zakharin     // components of local variables (since they are also local variables
844be66a2f6SSlava Zakharin     // according to F18 5.4.3.2.2, p. 2, note 1).
845be66a2f6SSlava Zakharin     // Here, the variable itself is not allocatable. If it has an allocatable
846be66a2f6SSlava Zakharin     // component the Destroy runtime does the job. Use the Finalize clean-up,
847be66a2f6SSlava Zakharin     // though there will be no finalization in runtime.
848be66a2f6SSlava Zakharin     if (hasAllocatableDirectComponent(sym))
849be66a2f6SSlava Zakharin       return VariableCleanUp::Finalize;
8500c7d0ad9SjeanPerier   }
8510c7d0ad9SjeanPerier   return std::nullopt;
85297492fd1SValentin Clement }
85397492fd1SValentin Clement 
85497492fd1SValentin Clement /// Check whether a variable needs the be finalized according to clause 7.5.6.3
85597492fd1SValentin Clement /// point 7.
85697492fd1SValentin Clement /// Must be nonpointer, nonallocatable, INTENT (OUT) dummy argument.
85797492fd1SValentin Clement static bool
85897492fd1SValentin Clement needDummyIntentoutFinalization(const Fortran::lower::pft::Variable &var) {
85997492fd1SValentin Clement   if (!var.hasSymbol())
86097492fd1SValentin Clement     return false;
86197492fd1SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
86297492fd1SValentin Clement   if (!Fortran::semantics::IsDummy(sym) ||
86397492fd1SValentin Clement       !Fortran::semantics::IsIntentOut(sym) ||
86497492fd1SValentin Clement       Fortran::semantics::IsAllocatable(sym) ||
86597492fd1SValentin Clement       Fortran::semantics::IsPointer(sym))
86697492fd1SValentin Clement     return false;
86797492fd1SValentin Clement   // Polymorphic and unlimited polymorphic intent(out) dummy argument might need
86897492fd1SValentin Clement   // finalization at runtime.
86997492fd1SValentin Clement   if (Fortran::semantics::IsPolymorphic(sym) ||
87097492fd1SValentin Clement       Fortran::semantics::IsUnlimitedPolymorphic(sym))
87197492fd1SValentin Clement     return true;
87297492fd1SValentin Clement   // Intent(out) dummies must be finalized at runtime if their type has a
87397492fd1SValentin Clement   // finalization.
8748e674e8aSjeanPerier   // Allocatable components of INTENT(OUT) dummies must be deallocated (9.7.3.2
8758e674e8aSjeanPerier   // p6). Calling finalization runtime for this works even if the components
8768e674e8aSjeanPerier   // have no final procedures.
8778e674e8aSjeanPerier   return hasFinalization(sym) || hasAllocatableDirectComponent(sym);
87897492fd1SValentin Clement }
87997492fd1SValentin Clement 
88097492fd1SValentin Clement /// Call default initialization runtime routine to initialize \p var.
88197492fd1SValentin Clement static void finalizeAtRuntime(Fortran::lower::AbstractConverter &converter,
88297492fd1SValentin Clement                               const Fortran::lower::pft::Variable &var,
88397492fd1SValentin Clement                               Fortran::lower::SymMap &symMap) {
88497492fd1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
88597492fd1SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
88697492fd1SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
887ab9c4e9fSJean Perier   fir::ExtendedValue exv = converter.getSymbolExtendedValue(sym, &symMap);
88897492fd1SValentin Clement   if (Fortran::semantics::IsOptional(sym)) {
88997492fd1SValentin Clement     // Only finalize if present.
89097492fd1SValentin Clement     auto isPresent = builder.create<fir::IsPresentOp>(loc, builder.getI1Type(),
89197492fd1SValentin Clement                                                       fir::getBase(exv));
89297492fd1SValentin Clement     builder.genIfThen(loc, isPresent)
89397492fd1SValentin Clement         .genThen([&]() {
89497492fd1SValentin Clement           auto box = builder.createBox(loc, exv);
89597492fd1SValentin Clement           fir::runtime::genDerivedTypeDestroy(builder, loc, box);
89697492fd1SValentin Clement         })
89797492fd1SValentin Clement         .end();
89897492fd1SValentin Clement   } else {
89997492fd1SValentin Clement     mlir::Value box = builder.createBox(loc, exv);
90097492fd1SValentin Clement     fir::runtime::genDerivedTypeDestroy(builder, loc, box);
90197492fd1SValentin Clement   }
90297492fd1SValentin Clement }
90397492fd1SValentin Clement 
904273b3350SValentin Clement // Fortran 2018 - 9.7.3.2 point 6
905273b3350SValentin Clement // When a procedure is invoked, any allocated allocatable object that is an
906273b3350SValentin Clement // actual argument corresponding to an INTENT(OUT) allocatable dummy argument
907273b3350SValentin Clement // is deallocated; any allocated allocatable object that is a subobject of an
908273b3350SValentin Clement // actual argument corresponding to an INTENT(OUT) dummy argument is
909273b3350SValentin Clement // deallocated.
9108e674e8aSjeanPerier // Note that allocatable components of non-ALLOCATABLE INTENT(OUT) dummy
9118e674e8aSjeanPerier // arguments are dealt with needDummyIntentoutFinalization (finalization runtime
9128e674e8aSjeanPerier // is called to reach the intended component deallocation effect).
913273b3350SValentin Clement static void deallocateIntentOut(Fortran::lower::AbstractConverter &converter,
914273b3350SValentin Clement                                 const Fortran::lower::pft::Variable &var,
915273b3350SValentin Clement                                 Fortran::lower::SymMap &symMap) {
916f3222be4SValentin Clement   if (!var.hasSymbol())
917f3222be4SValentin Clement     return;
918f3222be4SValentin Clement 
919273b3350SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
920273b3350SValentin Clement   if (Fortran::semantics::IsDummy(sym) &&
921273b3350SValentin Clement       Fortran::semantics::IsIntentOut(sym) &&
922273b3350SValentin Clement       Fortran::semantics::IsAllocatable(sym)) {
923ab9c4e9fSJean Perier     fir::ExtendedValue extVal = converter.getSymbolExtendedValue(sym, &symMap);
924273b3350SValentin Clement     if (auto mutBox = extVal.getBoxOf<fir::MutableBoxValue>()) {
925f3222be4SValentin Clement       // The dummy argument is not passed in the ENTRY so it should not be
926f3222be4SValentin Clement       // deallocated.
927d311cb64SSlava Zakharin       if (mlir::Operation *op = mutBox->getAddr().getDefiningOp()) {
928d311cb64SSlava Zakharin         if (auto declOp = mlir::dyn_cast<hlfir::DeclareOp>(op))
929d311cb64SSlava Zakharin           op = declOp.getMemref().getDefiningOp();
930d311cb64SSlava Zakharin         if (op && mlir::isa<fir::AllocaOp>(op))
931f3222be4SValentin Clement           return;
932d311cb64SSlava Zakharin       }
933273b3350SValentin Clement       mlir::Location loc = converter.getCurrentLocation();
934273b3350SValentin Clement       fir::FirOpBuilder &builder = converter.getFirOpBuilder();
935dd8a2434SValentin Clement 
936dd8a2434SValentin Clement       if (Fortran::semantics::IsOptional(sym)) {
937dd8a2434SValentin Clement         auto isPresent = builder.create<fir::IsPresentOp>(
938dd8a2434SValentin Clement             loc, builder.getI1Type(), fir::getBase(extVal));
939dd8a2434SValentin Clement         builder.genIfThen(loc, isPresent)
9402cb31fe8SjeanPerier             .genThen([&]() {
9412cb31fe8SjeanPerier               Fortran::lower::genDeallocateIfAllocated(converter, *mutBox, loc);
9422cb31fe8SjeanPerier             })
943dd8a2434SValentin Clement             .end();
944dd8a2434SValentin Clement       } else {
9452cb31fe8SjeanPerier         Fortran::lower::genDeallocateIfAllocated(converter, *mutBox, loc);
946273b3350SValentin Clement       }
947273b3350SValentin Clement     }
948273b3350SValentin Clement   }
949273b3350SValentin Clement }
950273b3350SValentin Clement 
9512c2e5a5dSValentin Clement /// Instantiate a local variable. Precondition: Each variable will be visited
9522c2e5a5dSValentin Clement /// such that if its properties depend on other variables, the variables upon
9532c2e5a5dSValentin Clement /// which its properties depend will already have been visited.
9542c2e5a5dSValentin Clement static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
9552c2e5a5dSValentin Clement                              const Fortran::lower::pft::Variable &var,
9562c2e5a5dSValentin Clement                              Fortran::lower::SymMap &symMap) {
9572c2e5a5dSValentin Clement   assert(!var.isAlias());
9582a59ead1SValentin Clement   Fortran::lower::StatementContext stmtCtx;
9592a59ead1SValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx);
960273b3350SValentin Clement   deallocateIntentOut(converter, var, symMap);
96197492fd1SValentin Clement   if (needDummyIntentoutFinalization(var))
96297492fd1SValentin Clement     finalizeAtRuntime(converter, var, symMap);
963a1425019SValentin Clement   if (mustBeDefaultInitializedAtRuntime(var))
96498e733eaSTom Eccles     Fortran::lower::defaultInitializeAtRuntime(converter, var.getSymbol(),
96598e733eaSTom Eccles                                                symMap);
96633cb29ccSValentin Clement (バレンタイン クレメン)   if (Fortran::semantics::NeedCUDAAlloc(var.getSymbol())) {
96733cb29ccSValentin Clement (バレンタイン クレメン)     auto *builder = &converter.getFirOpBuilder();
96833cb29ccSValentin Clement (バレンタイン クレメン)     mlir::Location loc = converter.getCurrentLocation();
96933cb29ccSValentin Clement (バレンタイン クレメン)     fir::ExtendedValue exv =
97033cb29ccSValentin Clement (バレンタイン クレメン)         converter.getSymbolExtendedValue(var.getSymbol(), &symMap);
97133cb29ccSValentin Clement (バレンタイン クレメン)     auto *sym = &var.getSymbol();
97233cb29ccSValentin Clement (バレンタイン クレメン)     converter.getFctCtx().attachCleanup([builder, loc, exv, sym]() {
97333cb29ccSValentin Clement (バレンタイン クレメン)       cuf::DataAttributeAttr dataAttr =
97433cb29ccSValentin Clement (バレンタイン クレメン)           Fortran::lower::translateSymbolCUFDataAttribute(builder->getContext(),
97533cb29ccSValentin Clement (バレンタイン クレメン)                                                           *sym);
97633cb29ccSValentin Clement (バレンタイン クレメン)       builder->create<cuf::FreeOp>(loc, fir::getBase(exv), dataAttr);
97733cb29ccSValentin Clement (バレンタイン クレメン)     });
97833cb29ccSValentin Clement (バレンタイン クレメン)   }
9790c7d0ad9SjeanPerier   if (std::optional<VariableCleanUp> cleanup =
9800c7d0ad9SjeanPerier           needDeallocationOrFinalization(var)) {
98197492fd1SValentin Clement     auto *builder = &converter.getFirOpBuilder();
98297492fd1SValentin Clement     mlir::Location loc = converter.getCurrentLocation();
98397492fd1SValentin Clement     fir::ExtendedValue exv =
984ab9c4e9fSJean Perier         converter.getSymbolExtendedValue(var.getSymbol(), &symMap);
9850c7d0ad9SjeanPerier     switch (*cleanup) {
9860c7d0ad9SjeanPerier     case VariableCleanUp::Finalize:
98797492fd1SValentin Clement       converter.getFctCtx().attachCleanup([builder, loc, exv]() {
98897492fd1SValentin Clement         mlir::Value box = builder->createBox(loc, exv);
98997492fd1SValentin Clement         fir::runtime::genDerivedTypeDestroy(*builder, loc, box);
99097492fd1SValentin Clement       });
9910c7d0ad9SjeanPerier       break;
9920c7d0ad9SjeanPerier     case VariableCleanUp::Deallocate:
9930c7d0ad9SjeanPerier       auto *converterPtr = &converter;
9947c0da799SValentin Clement (バレンタイン クレメン)       auto *sym = &var.getSymbol();
9957c0da799SValentin Clement (バレンタイン クレメン)       converter.getFctCtx().attachCleanup([converterPtr, loc, exv, sym]() {
9960c7d0ad9SjeanPerier         const fir::MutableBoxValue *mutableBox =
9970c7d0ad9SjeanPerier             exv.getBoxOf<fir::MutableBoxValue>();
9980c7d0ad9SjeanPerier         assert(mutableBox &&
9990c7d0ad9SjeanPerier                "trying to deallocate entity not lowered as allocatable");
10000c7d0ad9SjeanPerier         Fortran::lower::genDeallocateIfAllocated(*converterPtr, *mutableBox,
10017c0da799SValentin Clement (バレンタイン クレメン)                                                  loc, sym);
100233cb29ccSValentin Clement (バレンタイン クレメン) 
10030c7d0ad9SjeanPerier       });
10040c7d0ad9SjeanPerier     }
100597492fd1SValentin Clement   }
1006a1425019SValentin Clement }
1007a1425019SValentin Clement 
1008a1425019SValentin Clement //===----------------------------------------------------------------===//
1009a1425019SValentin Clement // Aliased (EQUIVALENCE) variables instantiation
1010a1425019SValentin Clement //===----------------------------------------------------------------===//
1011a1425019SValentin Clement 
1012a1425019SValentin Clement /// Insert \p aggregateStore instance into an AggregateStoreMap.
1013a1425019SValentin Clement static void insertAggregateStore(Fortran::lower::AggregateStoreMap &storeMap,
1014a1425019SValentin Clement                                  const Fortran::lower::pft::Variable &var,
1015a1425019SValentin Clement                                  mlir::Value aggregateStore) {
1016a1425019SValentin Clement   std::size_t off = var.getAggregateStore().getOffset();
1017a1425019SValentin Clement   Fortran::lower::AggregateStoreKey key = {var.getOwningScope(), off};
1018a1425019SValentin Clement   storeMap[key] = aggregateStore;
1019a1425019SValentin Clement }
1020a1425019SValentin Clement 
1021a1425019SValentin Clement /// Retrieve the aggregate store instance of \p alias from an
1022a1425019SValentin Clement /// AggregateStoreMap.
1023a1425019SValentin Clement static mlir::Value
1024a1425019SValentin Clement getAggregateStore(Fortran::lower::AggregateStoreMap &storeMap,
1025a1425019SValentin Clement                   const Fortran::lower::pft::Variable &alias) {
1026a1425019SValentin Clement   Fortran::lower::AggregateStoreKey key = {alias.getOwningScope(),
1027518e6f12SV Donaldson                                            alias.getAliasOffset()};
1028a1425019SValentin Clement   auto iter = storeMap.find(key);
1029a1425019SValentin Clement   assert(iter != storeMap.end());
1030a1425019SValentin Clement   return iter->second;
1031a1425019SValentin Clement }
1032a1425019SValentin Clement 
1033a1425019SValentin Clement /// Build the name for the storage of a global equivalence.
1034a1425019SValentin Clement static std::string mangleGlobalAggregateStore(
10352c143345SV Donaldson     Fortran::lower::AbstractConverter &converter,
1036a1425019SValentin Clement     const Fortran::lower::pft::Variable::AggregateStore &st) {
10372c143345SV Donaldson   return converter.mangleName(st.getNamingSymbol());
1038a1425019SValentin Clement }
1039a1425019SValentin Clement 
1040a1425019SValentin Clement /// Build the type for the storage of an equivalence.
1041a1425019SValentin Clement static mlir::Type
1042a1425019SValentin Clement getAggregateType(Fortran::lower::AbstractConverter &converter,
1043a1425019SValentin Clement                  const Fortran::lower::pft::Variable::AggregateStore &st) {
1044a1425019SValentin Clement   if (const Fortran::semantics::Symbol *initSym = st.getInitialValueSymbol())
1045a1425019SValentin Clement     return converter.genType(*initSym);
1046a1425019SValentin Clement   mlir::IntegerType byteTy = converter.getFirOpBuilder().getIntegerType(8);
1047a1425019SValentin Clement   return fir::SequenceType::get(std::get<1>(st.interval), byteTy);
1048a1425019SValentin Clement }
1049a1425019SValentin Clement 
1050a1425019SValentin Clement /// Define a GlobalOp for the storage of a global equivalence described
1051a1425019SValentin Clement /// by \p aggregate. The global is named \p aggName and is created with
1052a1425019SValentin Clement /// the provided \p linkage.
1053a1425019SValentin Clement /// If any of the equivalence members are initialized, an initializer is
1054a1425019SValentin Clement /// created for the equivalence.
1055a1425019SValentin Clement /// This is to be used when lowering the scope that owns the equivalence
1056a1425019SValentin Clement /// (as opposed to simply using it through host or use association).
1057a1425019SValentin Clement /// This is not to be used for equivalence of common block members (they
1058a1425019SValentin Clement /// already have the common block GlobalOp for them, see defineCommonBlock).
1059a1425019SValentin Clement static fir::GlobalOp defineGlobalAggregateStore(
1060a1425019SValentin Clement     Fortran::lower::AbstractConverter &converter,
1061a1425019SValentin Clement     const Fortran::lower::pft::Variable::AggregateStore &aggregate,
1062a1425019SValentin Clement     llvm::StringRef aggName, mlir::StringAttr linkage) {
1063a1425019SValentin Clement   assert(aggregate.isGlobal() && "not a global interval");
1064a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1065a1425019SValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(aggName);
1066a1425019SValentin Clement   if (global && globalIsInitialized(global))
1067a1425019SValentin Clement     return global;
1068a1425019SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
1069a1425019SValentin Clement   mlir::Type aggTy = getAggregateType(converter, aggregate);
1070a1425019SValentin Clement   if (!global)
1071a1425019SValentin Clement     global = builder.createGlobal(loc, aggTy, aggName, linkage);
1072a1425019SValentin Clement 
1073a1425019SValentin Clement   if (const Fortran::semantics::Symbol *initSym =
1074a1425019SValentin Clement           aggregate.getInitialValueSymbol())
1075a1425019SValentin Clement     if (const auto *objectDetails =
1076a1425019SValentin Clement             initSym->detailsIf<Fortran::semantics::ObjectEntityDetails>())
1077a1425019SValentin Clement       if (objectDetails->init()) {
10788f119da5SPeixin Qiao         Fortran::lower::createGlobalInitialization(
1079a1425019SValentin Clement             builder, global, [&](fir::FirOpBuilder &builder) {
1080a1425019SValentin Clement               Fortran::lower::StatementContext stmtCtx;
1081a1425019SValentin Clement               mlir::Value initVal = fir::getBase(genInitializerExprValue(
1082a1425019SValentin Clement                   converter, loc, objectDetails->init().value(), stmtCtx));
1083a1425019SValentin Clement               builder.create<fir::HasValueOp>(loc, initVal);
1084a1425019SValentin Clement             });
1085a1425019SValentin Clement         return global;
1086a1425019SValentin Clement       }
1087a1425019SValentin Clement   // Equivalence has no Fortran initial value. Create an undefined FIR initial
1088a1425019SValentin Clement   // value to ensure this is consider an object definition in the IR regardless
1089a1425019SValentin Clement   // of the linkage.
10908f119da5SPeixin Qiao   Fortran::lower::createGlobalInitialization(
10918f119da5SPeixin Qiao       builder, global, [&](fir::FirOpBuilder &builder) {
1092a1425019SValentin Clement         Fortran::lower::StatementContext stmtCtx;
109387e25210SjeanPerier         mlir::Value initVal = builder.create<fir::ZeroOp>(loc, aggTy);
1094a1425019SValentin Clement         builder.create<fir::HasValueOp>(loc, initVal);
1095a1425019SValentin Clement       });
1096a1425019SValentin Clement   return global;
1097a1425019SValentin Clement }
1098a1425019SValentin Clement 
1099a1425019SValentin Clement /// Declare a GlobalOp for the storage of a global equivalence described
1100a1425019SValentin Clement /// by \p aggregate. The global is named \p aggName and is created with
1101a1425019SValentin Clement /// the provided \p linkage.
1102a1425019SValentin Clement /// No initializer is built for the created GlobalOp.
1103a1425019SValentin Clement /// This is to be used when lowering the scope that uses members of an
1104a1425019SValentin Clement /// equivalence it through host or use association.
1105a1425019SValentin Clement /// This is not to be used for equivalence of common block members (they
1106a1425019SValentin Clement /// already have the common block GlobalOp for them, see defineCommonBlock).
1107a1425019SValentin Clement static fir::GlobalOp declareGlobalAggregateStore(
1108a1425019SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
1109a1425019SValentin Clement     const Fortran::lower::pft::Variable::AggregateStore &aggregate,
1110a1425019SValentin Clement     llvm::StringRef aggName, mlir::StringAttr linkage) {
1111a1425019SValentin Clement   assert(aggregate.isGlobal() && "not a global interval");
1112a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1113a1425019SValentin Clement   if (fir::GlobalOp global = builder.getNamedGlobal(aggName))
1114a1425019SValentin Clement     return global;
1115a1425019SValentin Clement   mlir::Type aggTy = getAggregateType(converter, aggregate);
1116a1425019SValentin Clement   return builder.createGlobal(loc, aggTy, aggName, linkage);
1117a1425019SValentin Clement }
1118a1425019SValentin Clement 
1119a1425019SValentin Clement /// This is an aggregate store for a set of EQUIVALENCED variables. Create the
1120a1425019SValentin Clement /// storage on the stack or global memory and add it to the map.
1121a1425019SValentin Clement static void
1122a1425019SValentin Clement instantiateAggregateStore(Fortran::lower::AbstractConverter &converter,
1123a1425019SValentin Clement                           const Fortran::lower::pft::Variable &var,
1124a1425019SValentin Clement                           Fortran::lower::AggregateStoreMap &storeMap) {
1125a1425019SValentin Clement   assert(var.isAggregateStore() && "not an interval");
1126a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1127a1425019SValentin Clement   mlir::IntegerType i8Ty = builder.getIntegerType(8);
1128a1425019SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
11292c143345SV Donaldson   std::string aggName =
11302c143345SV Donaldson       mangleGlobalAggregateStore(converter, var.getAggregateStore());
1131a1425019SValentin Clement   if (var.isGlobal()) {
1132a1425019SValentin Clement     fir::GlobalOp global;
1133a1425019SValentin Clement     auto &aggregate = var.getAggregateStore();
1134a1425019SValentin Clement     mlir::StringAttr linkage = getLinkageAttribute(builder, var);
1135518e6f12SV Donaldson     if (var.isModuleOrSubmoduleVariable()) {
1136a1425019SValentin Clement       // A module global was or will be defined when lowering the module. Emit
1137a1425019SValentin Clement       // only a declaration if the global does not exist at that point.
1138a1425019SValentin Clement       global = declareGlobalAggregateStore(converter, loc, aggregate, aggName,
1139a1425019SValentin Clement                                            linkage);
1140a1425019SValentin Clement     } else {
1141a1425019SValentin Clement       global =
1142a1425019SValentin Clement           defineGlobalAggregateStore(converter, aggregate, aggName, linkage);
1143a1425019SValentin Clement     }
1144a1425019SValentin Clement     auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(),
1145a1425019SValentin Clement                                               global.getSymbol());
1146a1425019SValentin Clement     auto size = std::get<1>(var.getInterval());
1147a1425019SValentin Clement     fir::SequenceType::Shape shape(1, size);
1148a1425019SValentin Clement     auto seqTy = fir::SequenceType::get(shape, i8Ty);
1149a1425019SValentin Clement     mlir::Type refTy = builder.getRefType(seqTy);
1150a1425019SValentin Clement     mlir::Value aggregateStore = builder.createConvert(loc, refTy, addr);
1151a1425019SValentin Clement     insertAggregateStore(storeMap, var, aggregateStore);
1152a1425019SValentin Clement     return;
1153a1425019SValentin Clement   }
1154a1425019SValentin Clement   // This is a local aggregate, allocate an anonymous block of memory.
1155a1425019SValentin Clement   auto size = std::get<1>(var.getInterval());
1156a1425019SValentin Clement   fir::SequenceType::Shape shape(1, size);
1157a1425019SValentin Clement   auto seqTy = fir::SequenceType::get(shape, i8Ty);
1158a1425019SValentin Clement   mlir::Value local =
11599a417395SKazu Hirata       builder.allocateLocal(loc, seqTy, aggName, "", std::nullopt, std::nullopt,
1160a1425019SValentin Clement                             /*target=*/false);
1161a1425019SValentin Clement   insertAggregateStore(storeMap, var, local);
11622a59ead1SValentin Clement }
11632a59ead1SValentin Clement 
11645d25267dSValentin Clement /// Cast an alias address (variable part of an equivalence) to fir.ptr so that
11655d25267dSValentin Clement /// the optimizer is conservative and avoids doing copy elision in assignment
11665d25267dSValentin Clement /// involving equivalenced variables.
11675d25267dSValentin Clement /// TODO: Represent the equivalence aliasing constraint in another way to avoid
11685d25267dSValentin Clement /// pessimizing array assignments involving equivalenced variables.
11695d25267dSValentin Clement static mlir::Value castAliasToPointer(fir::FirOpBuilder &builder,
11705d25267dSValentin Clement                                       mlir::Location loc, mlir::Type aliasType,
11715d25267dSValentin Clement                                       mlir::Value aliasAddr) {
11725d25267dSValentin Clement   return builder.createConvert(loc, fir::PointerType::get(aliasType),
11735d25267dSValentin Clement                                aliasAddr);
11745d25267dSValentin Clement }
11755d25267dSValentin Clement 
1176a1425019SValentin Clement /// Instantiate a member of an equivalence. Compute its address in its
1177a1425019SValentin Clement /// aggregate storage and lower its attributes.
1178a1425019SValentin Clement static void instantiateAlias(Fortran::lower::AbstractConverter &converter,
1179a1425019SValentin Clement                              const Fortran::lower::pft::Variable &var,
1180a1425019SValentin Clement                              Fortran::lower::SymMap &symMap,
1181a1425019SValentin Clement                              Fortran::lower::AggregateStoreMap &storeMap) {
1182a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1183a1425019SValentin Clement   assert(var.isAlias());
1184a1425019SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
118553804e42SValentin Clement   const mlir::Location loc = genLocation(converter, sym);
1186a1425019SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
1187a1425019SValentin Clement   mlir::IntegerType i8Ty = builder.getIntegerType(8);
1188a1425019SValentin Clement   mlir::Type i8Ptr = builder.getRefType(i8Ty);
1189518e6f12SV Donaldson   mlir::Type symType = converter.genType(sym);
1190518e6f12SV Donaldson   std::size_t off = sym.GetUltimate().offset() - var.getAliasOffset();
1191518e6f12SV Donaldson   mlir::Value storeAddr = getAggregateStore(storeMap, var);
1192518e6f12SV Donaldson   mlir::Value offset = builder.createIntegerConstant(loc, idxTy, off);
1193518e6f12SV Donaldson   mlir::Value bytePtr = builder.create<fir::CoordinateOp>(
1194518e6f12SV Donaldson       loc, i8Ptr, storeAddr, mlir::ValueRange{offset});
1195518e6f12SV Donaldson   mlir::Value typedPtr = castAliasToPointer(builder, loc, symType, bytePtr);
1196a1425019SValentin Clement   Fortran::lower::StatementContext stmtCtx;
1197518e6f12SV Donaldson   mapSymbolAttributes(converter, var, symMap, stmtCtx, typedPtr);
1198a1425019SValentin Clement   // Default initialization is possible for equivalence members: see
1199a1425019SValentin Clement   // F2018 19.5.3.4. Note that if several equivalenced entities have
1200a1425019SValentin Clement   // default initialization, they must have the same type, and the standard
1201a1425019SValentin Clement   // allows the storage to be default initialized several times (this has
1202a1425019SValentin Clement   // no consequences other than wasting some execution time). For now,
1203a1425019SValentin Clement   // do not try optimizing this to single default initializations of
1204a1425019SValentin Clement   // the equivalenced storages. Keep lowering simple.
1205a1425019SValentin Clement   if (mustBeDefaultInitializedAtRuntime(var))
120698e733eaSTom Eccles     Fortran::lower::defaultInitializeAtRuntime(converter, var.getSymbol(),
120798e733eaSTom Eccles                                                symMap);
1208a1425019SValentin Clement }
1209a1425019SValentin Clement 
12105d25267dSValentin Clement //===--------------------------------------------------------------===//
12115d25267dSValentin Clement // COMMON blocks instantiation
12125d25267dSValentin Clement //===--------------------------------------------------------------===//
12135d25267dSValentin Clement 
12145d25267dSValentin Clement /// Does any member of the common block has an initializer ?
12155d25267dSValentin Clement static bool
12165d25267dSValentin Clement commonBlockHasInit(const Fortran::semantics::MutableSymbolVector &cmnBlkMems) {
12175d25267dSValentin Clement   for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
12185d25267dSValentin Clement     if (const auto *memDet =
12195d25267dSValentin Clement             mem->detailsIf<Fortran::semantics::ObjectEntityDetails>())
12205d25267dSValentin Clement       if (memDet->init())
12215d25267dSValentin Clement         return true;
12225d25267dSValentin Clement   }
12235d25267dSValentin Clement   return false;
12245d25267dSValentin Clement }
12255d25267dSValentin Clement 
12265d25267dSValentin Clement /// Build a tuple type for a common block based on the common block
12275d25267dSValentin Clement /// members and the common block size.
12285d25267dSValentin Clement /// This type is only needed to build common block initializers where
12295d25267dSValentin Clement /// the initial value is the collection of the member initial values.
12305d25267dSValentin Clement static mlir::TupleType getTypeOfCommonWithInit(
12315d25267dSValentin Clement     Fortran::lower::AbstractConverter &converter,
12325d25267dSValentin Clement     const Fortran::semantics::MutableSymbolVector &cmnBlkMems,
12335d25267dSValentin Clement     std::size_t commonSize) {
12345d25267dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
12355d25267dSValentin Clement   llvm::SmallVector<mlir::Type> members;
12365d25267dSValentin Clement   std::size_t counter = 0;
12375d25267dSValentin Clement   for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
12385d25267dSValentin Clement     if (const auto *memDet =
12395d25267dSValentin Clement             mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
12405d25267dSValentin Clement       if (mem->offset() > counter) {
12415d25267dSValentin Clement         fir::SequenceType::Shape len = {
12425d25267dSValentin Clement             static_cast<fir::SequenceType::Extent>(mem->offset() - counter)};
12435d25267dSValentin Clement         mlir::IntegerType byteTy = builder.getIntegerType(8);
12445d25267dSValentin Clement         auto memTy = fir::SequenceType::get(len, byteTy);
12455d25267dSValentin Clement         members.push_back(memTy);
12465d25267dSValentin Clement         counter = mem->offset();
12475d25267dSValentin Clement       }
12485d25267dSValentin Clement       if (memDet->init()) {
12495d25267dSValentin Clement         mlir::Type memTy = converter.genType(*mem);
12505d25267dSValentin Clement         members.push_back(memTy);
12515d25267dSValentin Clement         counter = mem->offset() + mem->size();
12525d25267dSValentin Clement       }
12535d25267dSValentin Clement     }
12545d25267dSValentin Clement   }
12555d25267dSValentin Clement   if (counter < commonSize) {
12565d25267dSValentin Clement     fir::SequenceType::Shape len = {
12575d25267dSValentin Clement         static_cast<fir::SequenceType::Extent>(commonSize - counter)};
12585d25267dSValentin Clement     mlir::IntegerType byteTy = builder.getIntegerType(8);
12595d25267dSValentin Clement     auto memTy = fir::SequenceType::get(len, byteTy);
12605d25267dSValentin Clement     members.push_back(memTy);
12615d25267dSValentin Clement   }
12625d25267dSValentin Clement   return mlir::TupleType::get(builder.getContext(), members);
12635d25267dSValentin Clement }
12645d25267dSValentin Clement 
12655d25267dSValentin Clement /// Common block members may have aliases. They are not in the common block
12665d25267dSValentin Clement /// member list from the symbol. We need to know about these aliases if they
12675d25267dSValentin Clement /// have initializer to generate the common initializer.
12685d25267dSValentin Clement /// This function takes care of adding aliases with initializer to the member
12695d25267dSValentin Clement /// list.
12705d25267dSValentin Clement static Fortran::semantics::MutableSymbolVector
12715d25267dSValentin Clement getCommonMembersWithInitAliases(const Fortran::semantics::Symbol &common) {
12725d25267dSValentin Clement   const auto &commonDetails =
12735d25267dSValentin Clement       common.get<Fortran::semantics::CommonBlockDetails>();
12745d25267dSValentin Clement   auto members = commonDetails.objects();
12755d25267dSValentin Clement 
12765d25267dSValentin Clement   // The number and size of equivalence and common is expected to be small, so
12775d25267dSValentin Clement   // no effort is given to optimize this loop of complexity equivalenced
12785d25267dSValentin Clement   // common members * common members
12795d25267dSValentin Clement   for (const Fortran::semantics::EquivalenceSet &set :
12805d25267dSValentin Clement        common.owner().equivalenceSets())
12815d25267dSValentin Clement     for (const Fortran::semantics::EquivalenceObject &obj : set) {
12825d25267dSValentin Clement       if (!obj.symbol.test(Fortran::semantics::Symbol::Flag::CompilerCreated)) {
12835d25267dSValentin Clement         if (const auto &details =
12845d25267dSValentin Clement                 obj.symbol
12855d25267dSValentin Clement                     .detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
12865d25267dSValentin Clement           const Fortran::semantics::Symbol *com =
12875d25267dSValentin Clement               FindCommonBlockContaining(obj.symbol);
12885d25267dSValentin Clement           if (!details->init() || com != &common)
12895d25267dSValentin Clement             continue;
12905d25267dSValentin Clement           // This is an alias with an init that belongs to the list
129106b551c9SKazu Hirata           if (!llvm::is_contained(members, obj.symbol))
12925d25267dSValentin Clement             members.emplace_back(obj.symbol);
12935d25267dSValentin Clement         }
12945d25267dSValentin Clement       }
12955d25267dSValentin Clement     }
12965d25267dSValentin Clement   return members;
12975d25267dSValentin Clement }
12985d25267dSValentin Clement 
12992c8cb9acSJean Perier /// Return the fir::GlobalOp that was created of COMMON block \p common.
13002c8cb9acSJean Perier /// It is an error if the fir::GlobalOp was not created before this is
13012c8cb9acSJean Perier /// called (it cannot be created on the flight because it is not known here
13022c8cb9acSJean Perier /// what mlir type the GlobalOp should have to satisfy all the
13032c8cb9acSJean Perier /// appearances in the program).
13045d25267dSValentin Clement static fir::GlobalOp
13052c8cb9acSJean Perier getCommonBlockGlobal(Fortran::lower::AbstractConverter &converter,
13065d25267dSValentin Clement                      const Fortran::semantics::Symbol &common) {
13075d25267dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
13082c143345SV Donaldson   std::string commonName = converter.mangleName(common);
13095d25267dSValentin Clement   fir::GlobalOp global = builder.getNamedGlobal(commonName);
13102c8cb9acSJean Perier   // Common blocks are lowered before any subprograms to deal with common
13112c8cb9acSJean Perier   // whose size may not be the same in every subprograms.
13122c8cb9acSJean Perier   if (!global)
13132c8cb9acSJean Perier     fir::emitFatalError(converter.genLocation(common.name()),
13142c8cb9acSJean Perier                         "COMMON block was not lowered before its usage");
13155d25267dSValentin Clement   return global;
13162c8cb9acSJean Perier }
13172c8cb9acSJean Perier 
13182c8cb9acSJean Perier /// Create the fir::GlobalOp for COMMON block \p common. If \p common has an
13192c8cb9acSJean Perier /// initial value, it is not created yet. Instead, the common block list
13202c8cb9acSJean Perier /// members is returned to later create the initial value in
13212c8cb9acSJean Perier /// finalizeCommonBlockDefinition.
13222c8cb9acSJean Perier static std::optional<std::tuple<
13232c8cb9acSJean Perier     fir::GlobalOp, Fortran::semantics::MutableSymbolVector, mlir::Location>>
13242c8cb9acSJean Perier declareCommonBlock(Fortran::lower::AbstractConverter &converter,
13252c8cb9acSJean Perier                    const Fortran::semantics::Symbol &common,
13262c8cb9acSJean Perier                    std::size_t commonSize) {
13272c8cb9acSJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
13282c143345SV Donaldson   std::string commonName = converter.mangleName(common);
13292c8cb9acSJean Perier   fir::GlobalOp global = builder.getNamedGlobal(commonName);
13302c8cb9acSJean Perier   if (global)
13312c8cb9acSJean Perier     return std::nullopt;
13325d25267dSValentin Clement   Fortran::semantics::MutableSymbolVector cmnBlkMems =
13335d25267dSValentin Clement       getCommonMembersWithInitAliases(common);
13345d25267dSValentin Clement   mlir::Location loc = converter.genLocation(common.name());
13355d25267dSValentin Clement   mlir::StringAttr linkage = builder.createCommonLinkage();
1336c1654c38SValentin Clement (バレンタイン クレメン)   const auto *details =
1337c1654c38SValentin Clement (バレンタイン クレメン)       common.detailsIf<Fortran::semantics::CommonBlockDetails>();
1338c1654c38SValentin Clement (バレンタイン クレメン)   assert(details && "Expect CommonBlockDetails on the common symbol");
13392c8cb9acSJean Perier   if (!commonBlockHasInit(cmnBlkMems)) {
13402c8cb9acSJean Perier     // A COMMON block sans initializers is initialized to zero.
13415d25267dSValentin Clement     // mlir::Vector types must have a strictly positive size, so at least
13425d25267dSValentin Clement     // temporarily, force a zero size COMMON block to have one byte.
13432c8cb9acSJean Perier     const auto sz =
13442c8cb9acSJean Perier         static_cast<fir::SequenceType::Extent>(commonSize > 0 ? commonSize : 1);
13455d25267dSValentin Clement     fir::SequenceType::Shape shape = {sz};
13465d25267dSValentin Clement     mlir::IntegerType i8Ty = builder.getIntegerType(8);
13475d25267dSValentin Clement     auto commonTy = fir::SequenceType::get(shape, i8Ty);
13485d25267dSValentin Clement     auto vecTy = mlir::VectorType::get(sz, i8Ty);
13495d25267dSValentin Clement     mlir::Attribute zero = builder.getIntegerAttr(i8Ty, 0);
1350984b800aSserge-sans-paille     auto init = mlir::DenseElementsAttr::get(vecTy, llvm::ArrayRef(zero));
1351c1654c38SValentin Clement (バレンタイン クレメン)     global = builder.createGlobal(loc, commonTy, commonName, linkage, init);
1352c1654c38SValentin Clement (バレンタイン クレメン)     global.setAlignment(details->alignment());
13532c8cb9acSJean Perier     // No need to add any initial value later.
13542c8cb9acSJean Perier     return std::nullopt;
13555d25267dSValentin Clement   }
13562c8cb9acSJean Perier   // COMMON block with initializer (note that initialized blank common are
13572c8cb9acSJean Perier   // accepted as an extension by semantics). Sort members by offset before
13582c8cb9acSJean Perier   // generating the type and initializer.
13595d25267dSValentin Clement   std::sort(cmnBlkMems.begin(), cmnBlkMems.end(),
13605d25267dSValentin Clement             [](auto &s1, auto &s2) { return s1->offset() < s2->offset(); });
13615d25267dSValentin Clement   mlir::TupleType commonTy =
13622c8cb9acSJean Perier       getTypeOfCommonWithInit(converter, cmnBlkMems, commonSize);
13632c8cb9acSJean Perier   // Create the global object, the initial value will be added later.
13642c8cb9acSJean Perier   global = builder.createGlobal(loc, commonTy, commonName);
1365c1654c38SValentin Clement (バレンタイン クレメン)   global.setAlignment(details->alignment());
13662c8cb9acSJean Perier   return std::make_tuple(global, std::move(cmnBlkMems), loc);
13672c8cb9acSJean Perier }
13682c8cb9acSJean Perier 
13692c8cb9acSJean Perier /// Add initial value to a COMMON block fir::GlobalOp \p global given the list
13702c8cb9acSJean Perier /// \p cmnBlkMems of the common block member symbols that contains symbols with
13712c8cb9acSJean Perier /// an initial value.
13722c8cb9acSJean Perier static void finalizeCommonBlockDefinition(
13732c8cb9acSJean Perier     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
13742c8cb9acSJean Perier     fir::GlobalOp global,
13752c8cb9acSJean Perier     const Fortran::semantics::MutableSymbolVector &cmnBlkMems) {
13762c8cb9acSJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1377fac349a1SChristian Sigg   mlir::TupleType commonTy = mlir::cast<mlir::TupleType>(global.getType());
13785d25267dSValentin Clement   auto initFunc = [&](fir::FirOpBuilder &builder) {
13792c8cb9acSJean Perier     mlir::IndexType idxTy = builder.getIndexType();
138087e25210SjeanPerier     mlir::Value cb = builder.create<fir::ZeroOp>(loc, commonTy);
13815d25267dSValentin Clement     unsigned tupIdx = 0;
13825d25267dSValentin Clement     std::size_t offset = 0;
13835d25267dSValentin Clement     LLVM_DEBUG(llvm::dbgs() << "block {\n");
13845d25267dSValentin Clement     for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
13855d25267dSValentin Clement       if (const auto *memDet =
13865d25267dSValentin Clement               mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
13875d25267dSValentin Clement         if (mem->offset() > offset) {
13885d25267dSValentin Clement           ++tupIdx;
13895d25267dSValentin Clement           offset = mem->offset();
13905d25267dSValentin Clement         }
13915d25267dSValentin Clement         if (memDet->init()) {
13925d25267dSValentin Clement           LLVM_DEBUG(llvm::dbgs()
13935d25267dSValentin Clement                      << "offset: " << mem->offset() << " is " << *mem << '\n');
13945d25267dSValentin Clement           Fortran::lower::StatementContext stmtCtx;
13955d25267dSValentin Clement           auto initExpr = memDet->init().value();
13965d25267dSValentin Clement           fir::ExtendedValue initVal =
13975d25267dSValentin Clement               Fortran::semantics::IsPointer(*mem)
13985d25267dSValentin Clement                   ? Fortran::lower::genInitialDataTarget(
13995d25267dSValentin Clement                         converter, loc, converter.genType(*mem), initExpr)
14005d25267dSValentin Clement                   : genInitializerExprValue(converter, loc, initExpr, stmtCtx);
14015d25267dSValentin Clement           mlir::IntegerAttr offVal = builder.getIntegerAttr(idxTy, tupIdx);
14025d25267dSValentin Clement           mlir::Value castVal = builder.createConvert(
14035d25267dSValentin Clement               loc, commonTy.getType(tupIdx), fir::getBase(initVal));
14045d25267dSValentin Clement           cb = builder.create<fir::InsertValueOp>(loc, commonTy, cb, castVal,
14055d25267dSValentin Clement                                                   builder.getArrayAttr(offVal));
14065d25267dSValentin Clement           ++tupIdx;
14075d25267dSValentin Clement           offset = mem->offset() + mem->size();
14085d25267dSValentin Clement         }
14095d25267dSValentin Clement       }
14105d25267dSValentin Clement     }
14115d25267dSValentin Clement     LLVM_DEBUG(llvm::dbgs() << "}\n");
14125d25267dSValentin Clement     builder.create<fir::HasValueOp>(loc, cb);
14135d25267dSValentin Clement   };
14148f119da5SPeixin Qiao   Fortran::lower::createGlobalInitialization(builder, global, initFunc);
14155d25267dSValentin Clement }
14162c8cb9acSJean Perier 
14172c8cb9acSJean Perier void Fortran::lower::defineCommonBlocks(
14182c8cb9acSJean Perier     Fortran::lower::AbstractConverter &converter,
14192c8cb9acSJean Perier     const Fortran::semantics::CommonBlockList &commonBlocks) {
14202c8cb9acSJean Perier   // Common blocks may depend on another common block address (if they contain
14212c8cb9acSJean Perier   // pointers with initial targets). To cover this case, create all common block
14222c8cb9acSJean Perier   // fir::Global before creating the initial values (if any).
14232c8cb9acSJean Perier   std::vector<std::tuple<fir::GlobalOp, Fortran::semantics::MutableSymbolVector,
14242c8cb9acSJean Perier                          mlir::Location>>
14252c8cb9acSJean Perier       delayedInitializations;
14265a793640SPeter Klausler   for (const auto &[common, size] : commonBlocks)
14272c8cb9acSJean Perier     if (auto delayedInit = declareCommonBlock(converter, common, size))
14282c8cb9acSJean Perier       delayedInitializations.emplace_back(std::move(*delayedInit));
14292c8cb9acSJean Perier   for (auto &[global, cmnBlkMems, loc] : delayedInitializations)
14302c8cb9acSJean Perier     finalizeCommonBlockDefinition(loc, converter, global, cmnBlkMems);
14312c8cb9acSJean Perier }
14322c8cb9acSJean Perier 
143310f7801cSKrzysztof Parzyszek mlir::Value Fortran::lower::genCommonBlockMember(
143410f7801cSKrzysztof Parzyszek     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
143510f7801cSKrzysztof Parzyszek     const Fortran::semantics::Symbol &sym, mlir::Value commonValue) {
143610f7801cSKrzysztof Parzyszek   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
143710f7801cSKrzysztof Parzyszek 
143810f7801cSKrzysztof Parzyszek   std::size_t byteOffset = sym.GetUltimate().offset();
143910f7801cSKrzysztof Parzyszek   mlir::IntegerType i8Ty = builder.getIntegerType(8);
144010f7801cSKrzysztof Parzyszek   mlir::Type i8Ptr = builder.getRefType(i8Ty);
144110f7801cSKrzysztof Parzyszek   mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(i8Ty));
144210f7801cSKrzysztof Parzyszek   mlir::Value base = builder.createConvert(loc, seqTy, commonValue);
144310f7801cSKrzysztof Parzyszek 
144410f7801cSKrzysztof Parzyszek   mlir::Value offs =
144510f7801cSKrzysztof Parzyszek       builder.createIntegerConstant(loc, builder.getIndexType(), byteOffset);
144610f7801cSKrzysztof Parzyszek   mlir::Value varAddr = builder.create<fir::CoordinateOp>(
144710f7801cSKrzysztof Parzyszek       loc, i8Ptr, base, mlir::ValueRange{offs});
144810f7801cSKrzysztof Parzyszek   mlir::Type symType = converter.genType(sym);
144910f7801cSKrzysztof Parzyszek 
145010f7801cSKrzysztof Parzyszek   return Fortran::semantics::FindEquivalenceSet(sym) != nullptr
145110f7801cSKrzysztof Parzyszek              ? castAliasToPointer(builder, loc, symType, varAddr)
145210f7801cSKrzysztof Parzyszek              : builder.createConvert(loc, builder.getRefType(symType), varAddr);
145310f7801cSKrzysztof Parzyszek }
145410f7801cSKrzysztof Parzyszek 
14555d25267dSValentin Clement /// The COMMON block is a global structure. `var` will be at some offset
14565d25267dSValentin Clement /// within the COMMON block. Adds the address of `var` (COMMON + offset) to
14575d25267dSValentin Clement /// the symbol map.
14585d25267dSValentin Clement static void instantiateCommon(Fortran::lower::AbstractConverter &converter,
14595d25267dSValentin Clement                               const Fortran::semantics::Symbol &common,
14605d25267dSValentin Clement                               const Fortran::lower::pft::Variable &var,
14615d25267dSValentin Clement                               Fortran::lower::SymMap &symMap) {
14625d25267dSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
14635d25267dSValentin Clement   const Fortran::semantics::Symbol &varSym = var.getSymbol();
14645d25267dSValentin Clement   mlir::Location loc = converter.genLocation(varSym.name());
14655d25267dSValentin Clement 
14665d25267dSValentin Clement   mlir::Value commonAddr;
14675d25267dSValentin Clement   if (Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(common))
14685d25267dSValentin Clement     commonAddr = symBox.getAddr();
14695d25267dSValentin Clement   if (!commonAddr) {
14705d25267dSValentin Clement     // introduce a local AddrOf and add it to the map
14712c8cb9acSJean Perier     fir::GlobalOp global = getCommonBlockGlobal(converter, common);
14725d25267dSValentin Clement     commonAddr = builder.create<fir::AddrOfOp>(loc, global.resultType(),
14735d25267dSValentin Clement                                                global.getSymbol());
14745d25267dSValentin Clement 
14755d25267dSValentin Clement     symMap.addSymbol(common, commonAddr);
14765d25267dSValentin Clement   }
147710f7801cSKrzysztof Parzyszek 
147810f7801cSKrzysztof Parzyszek   mlir::Value local = genCommonBlockMember(converter, loc, varSym, commonAddr);
14795d25267dSValentin Clement   Fortran::lower::StatementContext stmtCtx;
14805d25267dSValentin Clement   mapSymbolAttributes(converter, var, symMap, stmtCtx, local);
14815d25267dSValentin Clement }
14825d25267dSValentin Clement 
14835d25267dSValentin Clement //===--------------------------------------------------------------===//
14845d25267dSValentin Clement // Lower Variables specification expressions and attributes
14855d25267dSValentin Clement //===--------------------------------------------------------------===//
14865d25267dSValentin Clement 
14872a59ead1SValentin Clement /// Helper to decide if a dummy argument must be tracked in an BoxValue.
14882a59ead1SValentin Clement static bool lowerToBoxValue(const Fortran::semantics::Symbol &sym,
14895b6f3fcbSjeanPerier                             mlir::Value dummyArg,
14905b6f3fcbSjeanPerier                             Fortran::lower::AbstractConverter &converter) {
14912a59ead1SValentin Clement   // Only dummy arguments coming as fir.box can be tracked in an BoxValue.
1492fac349a1SChristian Sigg   if (!dummyArg || !mlir::isa<fir::BaseBoxType>(dummyArg.getType()))
14932a59ead1SValentin Clement     return false;
14942a59ead1SValentin Clement   // Non contiguous arrays must be tracked in an BoxValue.
14955b6f3fcbSjeanPerier   if (sym.Rank() > 0 && !Fortran::evaluate::IsSimplyContiguous(
14965b6f3fcbSjeanPerier                             sym, converter.getFoldingContext()))
14972a59ead1SValentin Clement     return true;
14982a59ead1SValentin Clement   // Assumed rank and optional fir.box cannot yet be read while lowering the
14992a59ead1SValentin Clement   // specifications.
15002a59ead1SValentin Clement   if (Fortran::evaluate::IsAssumedRank(sym) ||
15012a59ead1SValentin Clement       Fortran::semantics::IsOptional(sym))
15022a59ead1SValentin Clement     return true;
15032a59ead1SValentin Clement   // Polymorphic entity should be tracked through a fir.box that has the
15042a59ead1SValentin Clement   // dynamic type info.
15052a59ead1SValentin Clement   if (const Fortran::semantics::DeclTypeSpec *type = sym.GetType())
15062a59ead1SValentin Clement     if (type->IsPolymorphic())
15072a59ead1SValentin Clement       return true;
15082a59ead1SValentin Clement   return false;
15092a59ead1SValentin Clement }
15102a59ead1SValentin Clement 
15112a59ead1SValentin Clement /// Compute extent from lower and upper bound.
15122a59ead1SValentin Clement static mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc,
15132a59ead1SValentin Clement                                  mlir::Value lb, mlir::Value ub) {
15142a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
15152a59ead1SValentin Clement   // Let the folder deal with the common `ub - <const> + 1` case.
15162a59ead1SValentin Clement   auto diff = builder.create<mlir::arith::SubIOp>(loc, idxTy, ub, lb);
15172a59ead1SValentin Clement   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
15185bc9ee1bSJean Perier   auto rawExtent = builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one);
1519d91735b5SjeanPerier   return fir::factory::genMaxWithZero(builder, loc, rawExtent);
15202a59ead1SValentin Clement }
15212a59ead1SValentin Clement 
15222a59ead1SValentin Clement /// Lower explicit lower bounds into \p result. Does nothing if this is not an
15232a59ead1SValentin Clement /// array, or if the lower bounds are deferred, or all implicit or one.
15242a59ead1SValentin Clement static void lowerExplicitLowerBounds(
15252a59ead1SValentin Clement     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
15262a59ead1SValentin Clement     const Fortran::lower::BoxAnalyzer &box,
15272a59ead1SValentin Clement     llvm::SmallVectorImpl<mlir::Value> &result, Fortran::lower::SymMap &symMap,
15282a59ead1SValentin Clement     Fortran::lower::StatementContext &stmtCtx) {
15292a59ead1SValentin Clement   if (!box.isArray() || box.lboundIsAllOnes())
15302a59ead1SValentin Clement     return;
15312a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
15322a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
15332a59ead1SValentin Clement   if (box.isStaticArray()) {
15342a59ead1SValentin Clement     for (int64_t lb : box.staticLBound())
15352a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, lb));
15362a59ead1SValentin Clement     return;
15372a59ead1SValentin Clement   }
15382a59ead1SValentin Clement   for (const Fortran::semantics::ShapeSpec *spec : box.dynamicBound()) {
15392a59ead1SValentin Clement     if (auto low = spec->lbound().GetExplicit()) {
15402a59ead1SValentin Clement       auto expr = Fortran::lower::SomeExpr{*low};
15412a59ead1SValentin Clement       mlir::Value lb = builder.createConvert(
15422a59ead1SValentin Clement           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
15432a59ead1SValentin Clement       result.emplace_back(lb);
15442a59ead1SValentin Clement     }
15452a59ead1SValentin Clement   }
15462a59ead1SValentin Clement   assert(result.empty() || result.size() == box.dynamicBound().size());
15472a59ead1SValentin Clement }
15482a59ead1SValentin Clement 
154927cfe7a0SjeanPerier /// Return -1 for the last dimension extent/upper bound of assumed-size arrays.
155027cfe7a0SjeanPerier /// This value is required to fulfill the requirements for assumed-rank
155127cfe7a0SjeanPerier /// associated with assumed-size (see for instance UBOUND in 16.9.196, and
155227cfe7a0SjeanPerier /// CFI_desc_t requirements in 18.5.3 point 5.).
155327cfe7a0SjeanPerier static mlir::Value getAssumedSizeExtent(mlir::Location loc,
155427cfe7a0SjeanPerier                                         fir::FirOpBuilder &builder) {
15558ddfb669SjeanPerier   return builder.createMinusOneInteger(loc, builder.getIndexType());
155627cfe7a0SjeanPerier }
155727cfe7a0SjeanPerier 
15582a59ead1SValentin Clement /// Lower explicit extents into \p result if this is an explicit-shape or
15592a59ead1SValentin Clement /// assumed-size array. Does nothing if this is not an explicit-shape or
15602a59ead1SValentin Clement /// assumed-size array.
15615bc9ee1bSJean Perier static void
15625bc9ee1bSJean Perier lowerExplicitExtents(Fortran::lower::AbstractConverter &converter,
15635bc9ee1bSJean Perier                      mlir::Location loc, const Fortran::lower::BoxAnalyzer &box,
15645bc9ee1bSJean Perier                      llvm::SmallVectorImpl<mlir::Value> &lowerBounds,
15652a59ead1SValentin Clement                      llvm::SmallVectorImpl<mlir::Value> &result,
15662a59ead1SValentin Clement                      Fortran::lower::SymMap &symMap,
15672a59ead1SValentin Clement                      Fortran::lower::StatementContext &stmtCtx) {
15682a59ead1SValentin Clement   if (!box.isArray())
15692a59ead1SValentin Clement     return;
15702a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
15712a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
15722a59ead1SValentin Clement   if (box.isStaticArray()) {
15732a59ead1SValentin Clement     for (int64_t extent : box.staticShape())
15742a59ead1SValentin Clement       result.emplace_back(builder.createIntegerConstant(loc, idxTy, extent));
15752a59ead1SValentin Clement     return;
15762a59ead1SValentin Clement   }
15772a59ead1SValentin Clement   for (const auto &spec : llvm::enumerate(box.dynamicBound())) {
15782a59ead1SValentin Clement     if (auto up = spec.value()->ubound().GetExplicit()) {
15792a59ead1SValentin Clement       auto expr = Fortran::lower::SomeExpr{*up};
15802a59ead1SValentin Clement       mlir::Value ub = builder.createConvert(
15812a59ead1SValentin Clement           loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx));
15822a59ead1SValentin Clement       if (lowerBounds.empty())
1583d91735b5SjeanPerier         result.emplace_back(fir::factory::genMaxWithZero(builder, loc, ub));
15842a59ead1SValentin Clement       else
15852a59ead1SValentin Clement         result.emplace_back(
15862a59ead1SValentin Clement             computeExtent(builder, loc, lowerBounds[spec.index()], ub));
15872a59ead1SValentin Clement     } else if (spec.value()->ubound().isStar()) {
158827cfe7a0SjeanPerier       result.emplace_back(getAssumedSizeExtent(loc, builder));
15892a59ead1SValentin Clement     }
15902a59ead1SValentin Clement   }
15912a59ead1SValentin Clement   assert(result.empty() || result.size() == box.dynamicBound().size());
15922a59ead1SValentin Clement }
15932a59ead1SValentin Clement 
159496d9df41SValentin Clement /// Lower explicit character length if any. Return empty mlir::Value if no
159596d9df41SValentin Clement /// explicit length.
159696d9df41SValentin Clement static mlir::Value
159796d9df41SValentin Clement lowerExplicitCharLen(Fortran::lower::AbstractConverter &converter,
159896d9df41SValentin Clement                      mlir::Location loc, const Fortran::lower::BoxAnalyzer &box,
159996d9df41SValentin Clement                      Fortran::lower::SymMap &symMap,
160096d9df41SValentin Clement                      Fortran::lower::StatementContext &stmtCtx) {
160196d9df41SValentin Clement   if (!box.isChar())
160296d9df41SValentin Clement     return mlir::Value{};
160396d9df41SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
160496d9df41SValentin Clement   mlir::Type lenTy = builder.getCharacterLengthType();
1605c0921586SKazu Hirata   if (std::optional<int64_t> len = box.getCharLenConst())
160696d9df41SValentin Clement     return builder.createIntegerConstant(loc, lenTy, *len);
1607c0921586SKazu Hirata   if (std::optional<Fortran::lower::SomeExpr> lenExpr = box.getCharLenExpr())
1608fe252f8eSValentin Clement     // If the length expression is negative, the length is zero. See F2018
1609fe252f8eSValentin Clement     // 7.4.4.2 point 5.
1610d91735b5SjeanPerier     return fir::factory::genMaxWithZero(
1611fe252f8eSValentin Clement         builder, loc,
1612fe252f8eSValentin Clement         genScalarValue(converter, loc, *lenExpr, symMap, stmtCtx));
161396d9df41SValentin Clement   return mlir::Value{};
161496d9df41SValentin Clement }
161596d9df41SValentin Clement 
161627cfe7a0SjeanPerier /// Assumed size arrays last extent is -1 in the front end.
16172a59ead1SValentin Clement static mlir::Value genExtentValue(fir::FirOpBuilder &builder,
16182a59ead1SValentin Clement                                   mlir::Location loc, mlir::Type idxTy,
16192a59ead1SValentin Clement                                   long frontEndExtent) {
16202a59ead1SValentin Clement   if (frontEndExtent >= 0)
16212a59ead1SValentin Clement     return builder.createIntegerConstant(loc, idxTy, frontEndExtent);
162227cfe7a0SjeanPerier   return getAssumedSizeExtent(loc, builder);
16232a59ead1SValentin Clement }
16242a59ead1SValentin Clement 
1625411f839aSValentin Clement /// If a symbol is an array, it may have been declared with unknown extent
1626411f839aSValentin Clement /// parameters (e.g., `*`), but if it has an initial value then the actual size
1627411f839aSValentin Clement /// may be available from the initial array value's type.
1628411f839aSValentin Clement inline static llvm::SmallVector<std::int64_t>
1629411f839aSValentin Clement recoverShapeVector(llvm::ArrayRef<std::int64_t> shapeVec, mlir::Value initVal) {
1630411f839aSValentin Clement   llvm::SmallVector<std::int64_t> result;
1631411f839aSValentin Clement   if (initVal) {
1632411f839aSValentin Clement     if (auto seqTy = fir::unwrapUntilSeqType(initVal.getType())) {
1633411f839aSValentin Clement       for (auto [fst, snd] : llvm::zip(shapeVec, seqTy.getShape()))
1634411f839aSValentin Clement         result.push_back(fst == fir::SequenceType::getUnknownExtent() ? snd
1635411f839aSValentin Clement                                                                       : fst);
1636411f839aSValentin Clement       return result;
1637411f839aSValentin Clement     }
1638411f839aSValentin Clement   }
1639411f839aSValentin Clement   result.assign(shapeVec.begin(), shapeVec.end());
1640411f839aSValentin Clement   return result;
1641411f839aSValentin Clement }
1642411f839aSValentin Clement 
16433508f691SJean Perier fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
164447025af6SSlava Zakharin     mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym,
164547025af6SSlava Zakharin     fir::FortranVariableFlagsEnum extraFlags) {
164647025af6SSlava Zakharin   fir::FortranVariableFlagsEnum flags = extraFlags;
1647de7a50fbSjeanPerier   if (sym.test(Fortran::semantics::Symbol::Flag::CrayPointee)) {
1648de7a50fbSjeanPerier     // CrayPointee are represented as pointers.
1649de7a50fbSjeanPerier     flags = flags | fir::FortranVariableFlagsEnum::pointer;
1650de7a50fbSjeanPerier     return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
1651de7a50fbSjeanPerier   }
1652ca0a0bf9SJean Perier   const auto &attrs = sym.attrs();
1653ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::ALLOCATABLE))
1654ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::allocatable;
1655ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::ASYNCHRONOUS))
1656ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::asynchronous;
1657ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::BIND_C))
1658ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::bind_c;
1659ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::CONTIGUOUS))
1660ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::contiguous;
1661ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::INTENT_IN))
1662ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::intent_in;
1663ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::INTENT_INOUT))
1664ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::intent_inout;
1665ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::INTENT_OUT))
1666ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::intent_out;
1667ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::OPTIONAL))
1668ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::optional;
1669ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::PARAMETER))
1670ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::parameter;
1671ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::POINTER))
1672ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::pointer;
1673ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::TARGET))
1674ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::target;
1675ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::VALUE))
1676ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::value;
1677ca0a0bf9SJean Perier   if (attrs.test(Fortran::semantics::Attr::VOLATILE))
1678ca0a0bf9SJean Perier     flags = flags | fir::FortranVariableFlagsEnum::fortran_volatile;
1679ca0a0bf9SJean Perier   if (flags == fir::FortranVariableFlagsEnum::None)
1680ca0a0bf9SJean Perier     return {};
1681ca0a0bf9SJean Perier   return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
1682ca0a0bf9SJean Perier }
1683ca0a0bf9SJean Perier 
168445daa4fdSValentin Clement (バレンタイン クレメン) cuf::DataAttributeAttr Fortran::lower::translateSymbolCUFDataAttribute(
1685abc4f74dSValentin Clement (バレンタイン クレメン)     mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym) {
1686abc4f74dSValentin Clement (バレンタイン クレメン)   std::optional<Fortran::common::CUDADataAttr> cudaAttr =
1687e2d80a3dSValentin Clement (バレンタイン クレメン)       Fortran::semantics::GetCUDADataAttr(&sym.GetUltimate());
168845daa4fdSValentin Clement (バレンタイン クレメン)   return cuf::getDataAttribute(mlirContext, cudaAttr);
1689abc4f74dSValentin Clement (バレンタイン クレメン) }
1690abc4f74dSValentin Clement (バレンタイン クレメン) 
1691bb8bf858SjeanPerier static bool
1692bb8bf858SjeanPerier isCapturedInInternalProcedure(Fortran::lower::AbstractConverter &converter,
1693bb8bf858SjeanPerier                               const Fortran::semantics::Symbol &sym) {
1694bb8bf858SjeanPerier   const Fortran::lower::pft::FunctionLikeUnit *funit =
1695bb8bf858SjeanPerier       converter.getCurrentFunctionUnit();
1696bb8bf858SjeanPerier   if (!funit || funit->getHostAssoc().empty())
1697bb8bf858SjeanPerier     return false;
1698bb8bf858SjeanPerier   if (funit->getHostAssoc().isAssociated(sym))
1699bb8bf858SjeanPerier     return true;
1700bb8bf858SjeanPerier   // Consider that any capture of a variable that is in an equivalence with the
1701cf602b95SjeanPerier   // symbol imply that the storage of the symbol may also be accessed inside
1702bb8bf858SjeanPerier   // symbol implies that the storage of the symbol may also be accessed inside
1703cf602b95SjeanPerier 
1704bb8bf858SjeanPerier   // the internal procedure and flag it as captured.
1705bb8bf858SjeanPerier   if (const auto *equivSet = Fortran::semantics::FindEquivalenceSet(sym))
1706bb8bf858SjeanPerier     for (const Fortran::semantics::EquivalenceObject &eqObj : *equivSet)
1707bb8bf858SjeanPerier       if (funit->getHostAssoc().isAssociated(eqObj.symbol))
1708bb8bf858SjeanPerier         return true;
1709bb8bf858SjeanPerier   return false;
1710bb8bf858SjeanPerier }
1711bb8bf858SjeanPerier 
17129e37301cSJean Perier /// Map a symbol to its FIR address and evaluated specification expressions.
17139e37301cSJean Perier /// Not for symbols lowered to fir.box.
17149e37301cSJean Perier /// Will optionally create fir.declare.
17159e37301cSJean Perier static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
17169e37301cSJean Perier                              Fortran::lower::SymMap &symMap,
17179e37301cSJean Perier                              const Fortran::semantics::Symbol &sym,
17189e37301cSJean Perier                              mlir::Value base, mlir::Value len = {},
17199a417395SKazu Hirata                              llvm::ArrayRef<mlir::Value> shape = std::nullopt,
17209a417395SKazu Hirata                              llvm::ArrayRef<mlir::Value> lbounds = std::nullopt,
17219e37301cSJean Perier                              bool force = false) {
1722cedfd272SJean Perier   // In HLFIR, procedure dummy symbols are not added with an hlfir.declare
1723cedfd272SJean Perier   // because they are "values", and hlfir.declare is intended for variables. It
1724cedfd272SJean Perier   // would add too much complexity to hlfir.declare to support this case, and
1725cedfd272SJean Perier   // this would bring very little (the only point being debug info, that are not
1726cedfd272SJean Perier   // yet emitted) since alias analysis is meaningless for those.
17278b834caaSKiran Chandramohan   // Commonblock names are not variables, but in some lowerings (like OpenMP) it
17288b834caaSKiran Chandramohan   // is useful to maintain the address of the commonblock in an MLIR value and
17298b834caaSKiran Chandramohan   // query it. hlfir.declare need not be created for these.
1730cedfd272SJean Perier   if (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
1731af09219eSDaniel Chen       (!Fortran::semantics::IsProcedure(sym) ||
1732af09219eSDaniel Chen        Fortran::semantics::IsPointer(sym)) &&
17338b834caaSKiran Chandramohan       !sym.detailsIf<Fortran::semantics::CommonBlockDetails>()) {
1734ca0a0bf9SJean Perier     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1735ca0a0bf9SJean Perier     const mlir::Location loc = genLocation(converter, sym);
1736ca0a0bf9SJean Perier     mlir::Value shapeOrShift;
1737ca0a0bf9SJean Perier     if (!shape.empty() && !lbounds.empty())
173834d3f3fbSJean Perier       shapeOrShift = builder.genShape(loc, lbounds, shape);
1739ca0a0bf9SJean Perier     else if (!shape.empty())
1740ca0a0bf9SJean Perier       shapeOrShift = builder.genShape(loc, shape);
1741ca0a0bf9SJean Perier     else if (!lbounds.empty())
1742ca0a0bf9SJean Perier       shapeOrShift = builder.genShift(loc, lbounds);
1743ca0a0bf9SJean Perier     llvm::SmallVector<mlir::Value> lenParams;
1744ca0a0bf9SJean Perier     if (len)
1745ca0a0bf9SJean Perier       lenParams.emplace_back(len);
17462c143345SV Donaldson     auto name = converter.mangleName(sym);
1747bb8bf858SjeanPerier     fir::FortranVariableFlagsEnum extraFlags = {};
1748bb8bf858SjeanPerier     if (isCapturedInInternalProcedure(converter, sym))
1749bb8bf858SjeanPerier       extraFlags = extraFlags | fir::FortranVariableFlagsEnum::internal_assoc;
1750ca0a0bf9SJean Perier     fir::FortranVariableFlagsAttr attributes =
1751bb8bf858SjeanPerier         Fortran::lower::translateSymbolAttributes(builder.getContext(), sym,
1752bb8bf858SjeanPerier                                                   extraFlags);
175345daa4fdSValentin Clement (バレンタイン クレメン)     cuf::DataAttributeAttr dataAttr =
175445daa4fdSValentin Clement (バレンタイン クレメン)         Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
17557ff48870SValentin Clement (バレンタイン クレメン)                                                         sym);
1756f8843efbSSlava Zakharin 
1757de7a50fbSjeanPerier     if (sym.test(Fortran::semantics::Symbol::Flag::CrayPointee)) {
1758de7a50fbSjeanPerier       mlir::Type ptrBoxType =
1759de7a50fbSjeanPerier           Fortran::lower::getCrayPointeeBoxType(base.getType());
17605bb379f6SValentin Clement (バレンタイン クレメン)       mlir::Value boxAlloc = builder.createTemporary(
17615bb379f6SValentin Clement (バレンタイン クレメン)           loc, ptrBoxType,
17625bb379f6SValentin Clement (バレンタイン クレメン)           /*name=*/{}, /*shape=*/{}, /*lenParams=*/{}, /*attrs=*/{},
17635bb379f6SValentin Clement (バレンタイン クレメン)           Fortran::semantics::GetCUDADataAttr(&sym.GetUltimate()));
1764f8843efbSSlava Zakharin 
1765f8843efbSSlava Zakharin       // Declare a local pointer variable.
1766f8843efbSSlava Zakharin       auto newBase = builder.create<hlfir::DeclareOp>(
17671710c8cfSSlava Zakharin           loc, boxAlloc, name, /*shape=*/nullptr, lenParams,
17681710c8cfSSlava Zakharin           /*dummy_scope=*/nullptr, attributes);
1769de7a50fbSjeanPerier       mlir::Value nullAddr = builder.createNullConstant(
1770de7a50fbSjeanPerier           loc, llvm::cast<fir::BaseBoxType>(ptrBoxType).getEleTy());
1771f8843efbSSlava Zakharin 
1772f8843efbSSlava Zakharin       // If the element type is known-length character, then
1773f8843efbSSlava Zakharin       // EmboxOp does not need the length parameters.
1774f8843efbSSlava Zakharin       if (auto charType = mlir::dyn_cast<fir::CharacterType>(
1775de7a50fbSjeanPerier               hlfir::getFortranElementType(base.getType())))
1776f8843efbSSlava Zakharin         if (!charType.hasDynamicLen())
1777f8843efbSSlava Zakharin           lenParams.clear();
1778f8843efbSSlava Zakharin 
1779f8843efbSSlava Zakharin       // Inherit the shape (and maybe length parameters) from the pointee
1780f8843efbSSlava Zakharin       // declaration.
1781f8843efbSSlava Zakharin       mlir::Value initVal =
1782f8843efbSSlava Zakharin           builder.create<fir::EmboxOp>(loc, ptrBoxType, nullAddr, shapeOrShift,
1783f8843efbSSlava Zakharin                                        /*slice=*/nullptr, lenParams);
1784f8843efbSSlava Zakharin       builder.create<fir::StoreOp>(loc, initVal, newBase.getBase());
1785f8843efbSSlava Zakharin 
1786f8843efbSSlava Zakharin       // Any reference to the pointee is going to be using the pointer
1787f8843efbSSlava Zakharin       // box from now on. The base_addr of the descriptor must be updated
1788f8843efbSSlava Zakharin       // to hold the value of the Cray pointer at the point of the pointee
1789f8843efbSSlava Zakharin       // access.
1790f8843efbSSlava Zakharin       // Note that the same Cray pointer may be associated with
1791f8843efbSSlava Zakharin       // multiple pointees and each of them has its own descriptor.
1792f8843efbSSlava Zakharin       symMap.addVariableDefinition(sym, newBase, force);
1793f8843efbSSlava Zakharin       return;
1794f8843efbSSlava Zakharin     }
17951710c8cfSSlava Zakharin     mlir::Value dummyScope;
17961710c8cfSSlava Zakharin     if (converter.isRegisteredDummySymbol(sym))
17971710c8cfSSlava Zakharin       dummyScope = converter.dummyArgsScopeValue();
179834d3f3fbSJean Perier     auto newBase = builder.create<hlfir::DeclareOp>(
17991710c8cfSSlava Zakharin         loc, base, name, shapeOrShift, lenParams, dummyScope, attributes,
180045daa4fdSValentin Clement (バレンタイン クレメン)         dataAttr);
1801c14ef2d7SJean Perier     symMap.addVariableDefinition(sym, newBase, force);
1802ca0a0bf9SJean Perier     return;
1803ca0a0bf9SJean Perier   }
18049e37301cSJean Perier 
18059e37301cSJean Perier   if (len) {
18069e37301cSJean Perier     if (!shape.empty()) {
18079e37301cSJean Perier       if (!lbounds.empty())
18089e37301cSJean Perier         symMap.addCharSymbolWithBounds(sym, base, len, shape, lbounds, force);
18099e37301cSJean Perier       else
18109e37301cSJean Perier         symMap.addCharSymbolWithShape(sym, base, len, shape, force);
18119e37301cSJean Perier     } else {
18129e37301cSJean Perier       symMap.addCharSymbol(sym, base, len, force);
18139e37301cSJean Perier     }
18149e37301cSJean Perier   } else {
18159e37301cSJean Perier     if (!shape.empty()) {
18169e37301cSJean Perier       if (!lbounds.empty())
18179e37301cSJean Perier         symMap.addSymbolWithBounds(sym, base, shape, lbounds, force);
18189e37301cSJean Perier       else
18199e37301cSJean Perier         symMap.addSymbolWithShape(sym, base, shape, force);
18209e37301cSJean Perier     } else {
18219e37301cSJean Perier       symMap.addSymbol(sym, base, force);
18229e37301cSJean Perier     }
18239e37301cSJean Perier   }
18249e37301cSJean Perier }
18259e37301cSJean Perier 
18269e37301cSJean Perier /// Map a symbol to its FIR address and evaluated specification expressions
18279e37301cSJean Perier /// provided as a fir::ExtendedValue. Will optionally create fir.declare.
1828ab9c4e9fSJean Perier void Fortran::lower::genDeclareSymbol(
1829ab9c4e9fSJean Perier     Fortran::lower::AbstractConverter &converter,
1830ab9c4e9fSJean Perier     Fortran::lower::SymMap &symMap, const Fortran::semantics::Symbol &sym,
183147025af6SSlava Zakharin     const fir::ExtendedValue &exv, fir::FortranVariableFlagsEnum extraFlags,
183247025af6SSlava Zakharin     bool force) {
1833cedfd272SJean Perier   if (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
1834008b7f1dSjeanPerier       (!Fortran::semantics::IsProcedure(sym) ||
1835008b7f1dSjeanPerier        Fortran::semantics::IsPointer(sym)) &&
18368b834caaSKiran Chandramohan       !sym.detailsIf<Fortran::semantics::CommonBlockDetails>()) {
183734d3f3fbSJean Perier     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
183834d3f3fbSJean Perier     const mlir::Location loc = genLocation(converter, sym);
1839bb8bf858SjeanPerier     if (isCapturedInInternalProcedure(converter, sym))
1840bb8bf858SjeanPerier       extraFlags = extraFlags | fir::FortranVariableFlagsEnum::internal_assoc;
18418a3a0821SKiran Chandramohan     // FIXME: Using the ultimate symbol for translating symbol attributes will
18428a3a0821SKiran Chandramohan     // lead to situations where the VOLATILE/ASYNCHRONOUS attributes are not
18438a3a0821SKiran Chandramohan     // propagated to the hlfir.declare (these attributes can be added when
18448a3a0821SKiran Chandramohan     // using module variables).
184534d3f3fbSJean Perier     fir::FortranVariableFlagsAttr attributes =
18468a3a0821SKiran Chandramohan         Fortran::lower::translateSymbolAttributes(
18478a3a0821SKiran Chandramohan             builder.getContext(), sym.GetUltimate(), extraFlags);
184845daa4fdSValentin Clement (バレンタイン クレメン)     cuf::DataAttributeAttr dataAttr =
184945daa4fdSValentin Clement (バレンタイン クレメン)         Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
1850abc4f74dSValentin Clement (バレンタイン クレメン)                                                         sym.GetUltimate());
18512c143345SV Donaldson     auto name = converter.mangleName(sym);
18521710c8cfSSlava Zakharin     mlir::Value dummyScope;
18531710c8cfSSlava Zakharin     if (converter.isRegisteredDummySymbol(sym))
18541710c8cfSSlava Zakharin       dummyScope = converter.dummyArgsScopeValue();
18551710c8cfSSlava Zakharin     hlfir::EntityWithAttributes declare = hlfir::genDeclare(
185645daa4fdSValentin Clement (バレンタイン クレメン)         loc, builder, exv, name, attributes, dummyScope, dataAttr);
185734d3f3fbSJean Perier     symMap.addVariableDefinition(sym, declare.getIfVariableInterface(), force);
185834d3f3fbSJean Perier     return;
185934d3f3fbSJean Perier   }
186034d3f3fbSJean Perier   symMap.addSymbol(sym, exv, force);
18619e37301cSJean Perier }
18629e37301cSJean Perier 
18639e37301cSJean Perier /// Map an allocatable or pointer symbol to its FIR address and evaluated
18649e37301cSJean Perier /// specification expressions. Will optionally create fir.declare.
18659e37301cSJean Perier static void
18669e37301cSJean Perier genAllocatableOrPointerDeclare(Fortran::lower::AbstractConverter &converter,
18679e37301cSJean Perier                                Fortran::lower::SymMap &symMap,
18689e37301cSJean Perier                                const Fortran::semantics::Symbol &sym,
18699e37301cSJean Perier                                fir::MutableBoxValue box, bool force = false) {
18701119c15eSJean Perier   if (!converter.getLoweringOptions().getLowerToHighLevelFIR()) {
18719e37301cSJean Perier     symMap.addAllocatableOrPointer(sym, box, force);
18721119c15eSJean Perier     return;
18731119c15eSJean Perier   }
18741119c15eSJean Perier   assert(!box.isDescribedByVariables() &&
18751119c15eSJean Perier          "HLFIR alloctables/pointers must be fir.ref<fir.box>");
18761119c15eSJean Perier   mlir::Value base = box.getAddr();
18771119c15eSJean Perier   mlir::Value explictLength;
18781119c15eSJean Perier   if (box.hasNonDeferredLenParams()) {
18791119c15eSJean Perier     if (!box.isCharacter())
18801119c15eSJean Perier       TODO(genLocation(converter, sym),
18811119c15eSJean Perier            "Pointer or Allocatable parametrized derived type");
18821119c15eSJean Perier     explictLength = box.nonDeferredLenParams()[0];
18831119c15eSJean Perier   }
18841119c15eSJean Perier   genDeclareSymbol(converter, symMap, sym, base, explictLength,
18851119c15eSJean Perier                    /*shape=*/std::nullopt,
18861119c15eSJean Perier                    /*lbounds=*/std::nullopt, force);
18879e37301cSJean Perier }
18889e37301cSJean Perier 
1889af09219eSDaniel Chen /// Map a procedure pointer
1890af09219eSDaniel Chen static void genProcPointer(Fortran::lower::AbstractConverter &converter,
1891af09219eSDaniel Chen                            Fortran::lower::SymMap &symMap,
1892af09219eSDaniel Chen                            const Fortran::semantics::Symbol &sym,
1893af09219eSDaniel Chen                            mlir::Value addr, bool force = false) {
1894af09219eSDaniel Chen   genDeclareSymbol(converter, symMap, sym, addr, mlir::Value{},
1895af09219eSDaniel Chen                    /*shape=*/std::nullopt,
1896af09219eSDaniel Chen                    /*lbounds=*/std::nullopt, force);
1897af09219eSDaniel Chen }
1898af09219eSDaniel Chen 
18999e37301cSJean Perier /// Map a symbol represented with a runtime descriptor to its FIR fir.box and
19009e37301cSJean Perier /// evaluated specification expressions. Will optionally create fir.declare.
19019e37301cSJean Perier static void genBoxDeclare(Fortran::lower::AbstractConverter &converter,
19029e37301cSJean Perier                           Fortran::lower::SymMap &symMap,
19039e37301cSJean Perier                           const Fortran::semantics::Symbol &sym,
19049e37301cSJean Perier                           mlir::Value box, llvm::ArrayRef<mlir::Value> lbounds,
19059e37301cSJean Perier                           llvm::ArrayRef<mlir::Value> explicitParams,
19069e37301cSJean Perier                           llvm::ArrayRef<mlir::Value> explicitExtents,
19079e37301cSJean Perier                           bool replace = false) {
190834d3f3fbSJean Perier   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
190934d3f3fbSJean Perier     fir::BoxValue boxValue{box, lbounds, explicitParams, explicitExtents};
191047025af6SSlava Zakharin     Fortran::lower::genDeclareSymbol(
191147025af6SSlava Zakharin         converter, symMap, sym, std::move(boxValue),
191247025af6SSlava Zakharin         fir::FortranVariableFlagsEnum::None, replace);
191334d3f3fbSJean Perier     return;
191434d3f3fbSJean Perier   }
19159e37301cSJean Perier   symMap.addBoxSymbol(sym, box, lbounds, explicitParams, explicitExtents,
19169e37301cSJean Perier                       replace);
19179e37301cSJean Perier }
19189e37301cSJean Perier 
1919bbdb1e40SValentin Clement (バレンタイン クレメン) static unsigned getAllocatorIdx(const Fortran::semantics::Symbol &sym) {
1920bbdb1e40SValentin Clement (バレンタイン クレメン)   std::optional<Fortran::common::CUDADataAttr> cudaAttr =
1921bbdb1e40SValentin Clement (バレンタイン クレメン)       Fortran::semantics::GetCUDADataAttr(&sym.GetUltimate());
1922bbdb1e40SValentin Clement (バレンタイン クレメン)   if (cudaAttr) {
1923bbdb1e40SValentin Clement (バレンタイン クレメン)     if (*cudaAttr == Fortran::common::CUDADataAttr::Pinned)
1924bbdb1e40SValentin Clement (バレンタイン クレメン)       return kPinnedAllocatorPos;
1925bbdb1e40SValentin Clement (バレンタイン クレメン)     if (*cudaAttr == Fortran::common::CUDADataAttr::Device)
1926bbdb1e40SValentin Clement (バレンタイン クレメン)       return kDeviceAllocatorPos;
1927388b6324SValentin Clement (バレンタイン クレメン)     if (*cudaAttr == Fortran::common::CUDADataAttr::Managed)
1928bbdb1e40SValentin Clement (バレンタイン クレメン)       return kManagedAllocatorPos;
1929388b6324SValentin Clement (バレンタイン クレメン)     if (*cudaAttr == Fortran::common::CUDADataAttr::Unified)
1930388b6324SValentin Clement (バレンタイン クレメン)       return kUnifiedAllocatorPos;
1931bbdb1e40SValentin Clement (バレンタイン クレメン)   }
1932bbdb1e40SValentin Clement (バレンタイン クレメン)   return kDefaultAllocator;
1933bbdb1e40SValentin Clement (バレンタイン クレメン) }
1934bbdb1e40SValentin Clement (バレンタイン クレメン) 
19352a59ead1SValentin Clement /// Lower specification expressions and attributes of variable \p var and
19361e1f60c6SV Donaldson /// add it to the symbol map. For a global or an alias, the address must be
19371e1f60c6SV Donaldson /// pre-computed and provided in \p preAlloc. A dummy argument for the current
19381e1f60c6SV Donaldson /// entry point has already been mapped to an mlir block argument in
19391e1f60c6SV Donaldson /// mapDummiesAndResults. Its mapping may be updated here.
19402a59ead1SValentin Clement void Fortran::lower::mapSymbolAttributes(
19412a59ead1SValentin Clement     AbstractConverter &converter, const Fortran::lower::pft::Variable &var,
19422a59ead1SValentin Clement     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
19432a59ead1SValentin Clement     mlir::Value preAlloc) {
19442a59ead1SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
19452c2e5a5dSValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
194653804e42SValentin Clement   const mlir::Location loc = genLocation(converter, sym);
19472a59ead1SValentin Clement   mlir::IndexType idxTy = builder.getIndexType();
19481e1f60c6SV Donaldson   const bool isDeclaredDummy = Fortran::semantics::IsDummy(sym);
19491e1f60c6SV Donaldson   // An active dummy from the current entry point.
19501e1f60c6SV Donaldson   const bool isDummy = isDeclaredDummy && symMap.lookupSymbol(sym).getAddr();
19511e1f60c6SV Donaldson   // An unused dummy from another entry point.
19521e1f60c6SV Donaldson   const bool isUnusedEntryDummy = isDeclaredDummy && !isDummy;
1953da7c77b8SValentin Clement   const bool isResult = Fortran::semantics::IsFunctionResult(sym);
19542a59ead1SValentin Clement   const bool replace = isDummy || isResult;
19552a59ead1SValentin Clement   fir::factory::CharacterExprHelper charHelp{builder, loc};
19561e1f60c6SV Donaldson 
19571e1f60c6SV Donaldson   if (Fortran::semantics::IsProcedure(sym)) {
19581e1f60c6SV Donaldson     if (isUnusedEntryDummy) {
19591e1f60c6SV Donaldson       // Additional discussion below.
19601e1f60c6SV Donaldson       mlir::Type dummyProcType =
19611e1f60c6SV Donaldson           Fortran::lower::getDummyProcedureType(sym, converter);
19621e1f60c6SV Donaldson       mlir::Value undefOp = builder.create<fir::UndefOp>(loc, dummyProcType);
19639e37301cSJean Perier 
1964ab9c4e9fSJean Perier       Fortran::lower::genDeclareSymbol(converter, symMap, sym, undefOp);
19651e1f60c6SV Donaldson     }
1966af09219eSDaniel Chen 
1967af09219eSDaniel Chen     // Procedure pointer.
1968af09219eSDaniel Chen     if (Fortran::semantics::IsPointer(sym)) {
1969af09219eSDaniel Chen       // global
1970af09219eSDaniel Chen       mlir::Value boxAlloc = preAlloc;
1971af09219eSDaniel Chen       // dummy or passed result
1972af09219eSDaniel Chen       if (!boxAlloc)
1973af09219eSDaniel Chen         if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
1974af09219eSDaniel Chen           boxAlloc = symbox.getAddr();
1975af09219eSDaniel Chen       // local
1976af09219eSDaniel Chen       if (!boxAlloc)
1977af09219eSDaniel Chen         boxAlloc = createNewLocal(converter, loc, var, preAlloc);
1978af09219eSDaniel Chen       genProcPointer(converter, symMap, sym, boxAlloc, replace);
1979af09219eSDaniel Chen     }
19801e1f60c6SV Donaldson     return;
19811e1f60c6SV Donaldson   }
19821e1f60c6SV Donaldson 
19835aba0dedSjeanPerier   const bool isAssumedRank = Fortran::evaluate::IsAssumedRank(sym);
19845aba0dedSjeanPerier   if (isAssumedRank && !allowAssumedRank)
1985a49f630cSjeanPerier     TODO(loc, "assumed-rank variable in procedure implemented in Fortran");
1986a49f630cSjeanPerier 
19872a59ead1SValentin Clement   Fortran::lower::BoxAnalyzer ba;
19882a59ead1SValentin Clement   ba.analyze(sym);
1989da7c77b8SValentin Clement 
19901e1f60c6SV Donaldson   // First deal with pointers and allocatables, because their handling here
19912a59ead1SValentin Clement   // is the same regardless of their rank.
19922a59ead1SValentin Clement   if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
19932a59ead1SValentin Clement     // Get address of fir.box describing the entity.
19942a59ead1SValentin Clement     // global
19952a59ead1SValentin Clement     mlir::Value boxAlloc = preAlloc;
19962a59ead1SValentin Clement     // dummy or passed result
19972a59ead1SValentin Clement     if (!boxAlloc)
19982a59ead1SValentin Clement       if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
19992a59ead1SValentin Clement         boxAlloc = symbox.getAddr();
200074faa402SjeanPerier     assert((boxAlloc || !isAssumedRank) && "assumed-ranks cannot be local");
20012a59ead1SValentin Clement     // local
20022a59ead1SValentin Clement     if (!boxAlloc)
20032a59ead1SValentin Clement       boxAlloc = createNewLocal(converter, loc, var, preAlloc);
20042a59ead1SValentin Clement     // Lower non deferred parameters.
20052a59ead1SValentin Clement     llvm::SmallVector<mlir::Value> nonDeferredLenParams;
20062a59ead1SValentin Clement     if (ba.isChar()) {
200796d9df41SValentin Clement       if (mlir::Value len =
200896d9df41SValentin Clement               lowerExplicitCharLen(converter, loc, ba, symMap, stmtCtx))
200996d9df41SValentin Clement         nonDeferredLenParams.push_back(len);
201096d9df41SValentin Clement       else if (Fortran::semantics::IsAssumedLengthCharacter(sym))
20114d95f74bSJonathon Penix         nonDeferredLenParams.push_back(
20124d95f74bSJonathon Penix             Fortran::lower::getAssumedCharAllocatableOrPointerLen(
20134d95f74bSJonathon Penix                 builder, loc, sym, boxAlloc));
20142a59ead1SValentin Clement     } else if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) {
20152a59ead1SValentin Clement       if (const Fortran::semantics::DerivedTypeSpec *derived =
20162a59ead1SValentin Clement               declTy->AsDerived())
20172a59ead1SValentin Clement         if (Fortran::semantics::CountLenParameters(*derived) != 0)
20182a59ead1SValentin Clement           TODO(loc,
20192a59ead1SValentin Clement                "derived type allocatable or pointer with length parameters");
20202a59ead1SValentin Clement     }
20212a59ead1SValentin Clement     fir::MutableBoxValue box = Fortran::lower::createMutableBox(
20221119c15eSJean Perier         converter, loc, var, boxAlloc, nonDeferredLenParams,
20231119c15eSJean Perier         /*alwaysUseBox=*/
2024bbdb1e40SValentin Clement (バレンタイン クレメン)         converter.getLoweringOptions().getLowerToHighLevelFIR(),
2025bbdb1e40SValentin Clement (バレンタイン クレメン)         getAllocatorIdx(var.getSymbol()));
20269e37301cSJean Perier     genAllocatableOrPointerDeclare(converter, symMap, var.getSymbol(), box,
20279e37301cSJean Perier                                    replace);
20282a59ead1SValentin Clement     return;
20292a59ead1SValentin Clement   }
20302a59ead1SValentin Clement 
20312a59ead1SValentin Clement   if (isDummy) {
20322a59ead1SValentin Clement     mlir::Value dummyArg = symMap.lookupSymbol(sym).getAddr();
20335b6f3fcbSjeanPerier     if (lowerToBoxValue(sym, dummyArg, converter)) {
20342a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> lbounds;
20355bc9ee1bSJean Perier       llvm::SmallVector<mlir::Value> explicitExtents;
20362a59ead1SValentin Clement       llvm::SmallVector<mlir::Value> explicitParams;
20372a59ead1SValentin Clement       // Lower lower bounds, explicit type parameters and explicit
20382a59ead1SValentin Clement       // extents if any.
20395b6f3fcbSjeanPerier       if (ba.isChar()) {
204080f8c6ddSValentin Clement         if (mlir::Value len =
204180f8c6ddSValentin Clement                 lowerExplicitCharLen(converter, loc, ba, symMap, stmtCtx))
204280f8c6ddSValentin Clement           explicitParams.push_back(len);
20435aba0dedSjeanPerier         if (!isAssumedRank && sym.Rank() == 0) {
20445b6f3fcbSjeanPerier           // Do not keep scalar characters as fir.box (even when optional).
20455b6f3fcbSjeanPerier           // Lowering and FIR is not meant to deal with scalar characters as
20465b6f3fcbSjeanPerier           // fir.box outside of calls.
2047fac349a1SChristian Sigg           auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(dummyArg.getType());
20485b6f3fcbSjeanPerier           mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
20495b6f3fcbSjeanPerier           mlir::Type lenType = builder.getCharacterLengthType();
20505b6f3fcbSjeanPerier           mlir::Value addr, len;
20515b6f3fcbSjeanPerier           if (Fortran::semantics::IsOptional(sym)) {
20525b6f3fcbSjeanPerier             auto isPresent = builder.create<fir::IsPresentOp>(
20535b6f3fcbSjeanPerier                 loc, builder.getI1Type(), dummyArg);
20545b6f3fcbSjeanPerier             auto addrAndLen =
20555b6f3fcbSjeanPerier                 builder
20565b6f3fcbSjeanPerier                     .genIfOp(loc, {refTy, lenType}, isPresent,
20575b6f3fcbSjeanPerier                              /*withElseRegion=*/true)
20585b6f3fcbSjeanPerier                     .genThen([&]() {
20595b6f3fcbSjeanPerier                       mlir::Value readAddr =
20605b6f3fcbSjeanPerier                           builder.create<fir::BoxAddrOp>(loc, refTy, dummyArg);
20615b6f3fcbSjeanPerier                       mlir::Value readLength =
20625b6f3fcbSjeanPerier                           charHelp.readLengthFromBox(dummyArg);
20635b6f3fcbSjeanPerier                       builder.create<fir::ResultOp>(
20645b6f3fcbSjeanPerier                           loc, mlir::ValueRange{readAddr, readLength});
20655b6f3fcbSjeanPerier                     })
20665b6f3fcbSjeanPerier                     .genElse([&] {
20675b6f3fcbSjeanPerier                       mlir::Value readAddr = builder.genAbsentOp(loc, refTy);
20685b6f3fcbSjeanPerier                       mlir::Value readLength =
20695b6f3fcbSjeanPerier                           fir::factory::createZeroValue(builder, loc, lenType);
20705b6f3fcbSjeanPerier                       builder.create<fir::ResultOp>(
20715b6f3fcbSjeanPerier                           loc, mlir::ValueRange{readAddr, readLength});
20725b6f3fcbSjeanPerier                     })
20735b6f3fcbSjeanPerier                     .getResults();
20745b6f3fcbSjeanPerier             addr = addrAndLen[0];
20755b6f3fcbSjeanPerier             len = addrAndLen[1];
20765b6f3fcbSjeanPerier           } else {
20775b6f3fcbSjeanPerier             addr = builder.create<fir::BoxAddrOp>(loc, refTy, dummyArg);
20785b6f3fcbSjeanPerier             len = charHelp.readLengthFromBox(dummyArg);
20795b6f3fcbSjeanPerier           }
20805b6f3fcbSjeanPerier           if (!explicitParams.empty())
20815b6f3fcbSjeanPerier             len = explicitParams[0];
20825b6f3fcbSjeanPerier           ::genDeclareSymbol(converter, symMap, sym, addr, len, /*extents=*/{},
20835b6f3fcbSjeanPerier                              /*lbounds=*/{}, replace);
20845b6f3fcbSjeanPerier           return;
20855b6f3fcbSjeanPerier         }
20865b6f3fcbSjeanPerier       }
20872a59ead1SValentin Clement       // TODO: derived type length parameters.
20885aba0dedSjeanPerier       if (!isAssumedRank) {
20892a59ead1SValentin Clement         lowerExplicitLowerBounds(converter, loc, ba, lbounds, symMap, stmtCtx);
20905aba0dedSjeanPerier         lowerExplicitExtents(converter, loc, ba, lbounds, explicitExtents,
20915aba0dedSjeanPerier                              symMap, stmtCtx);
20925aba0dedSjeanPerier       }
20939e37301cSJean Perier       genBoxDeclare(converter, symMap, sym, dummyArg, lbounds, explicitParams,
20945bc9ee1bSJean Perier                     explicitExtents, replace);
20952a59ead1SValentin Clement       return;
20962a59ead1SValentin Clement     }
20972a59ead1SValentin Clement   }
20982a59ead1SValentin Clement 
20991e1f60c6SV Donaldson   // A dummy from another entry point that is not declared in the current
21001e1f60c6SV Donaldson   // entry point requires a skeleton definition. Most such "unused" dummies
21011e1f60c6SV Donaldson   // will not survive into final generated code, but some will. It is illegal
21021e1f60c6SV Donaldson   // to reference one at run time if it does. Such a dummy is mapped to a
21031e1f60c6SV Donaldson   // value in one of three ways:
21041e1f60c6SV Donaldson   //
21051e1f60c6SV Donaldson   //  - Generate a fir::UndefOp value. This is lightweight, easy to clean up,
21061e1f60c6SV Donaldson   //    and often valid, but it may fail for a dummy with dynamic bounds,
21071e1f60c6SV Donaldson   //    or a dummy used to define another dummy. Information to distinguish
21081e1f60c6SV Donaldson   //    valid cases is not generally available here, with the exception of
21091e1f60c6SV Donaldson   //    dummy procedures. See the first function exit above.
21101e1f60c6SV Donaldson   //
21111e1f60c6SV Donaldson   //  - Allocate an uninitialized stack slot. This is an intermediate-weight
21121e1f60c6SV Donaldson   //    solution that is harder to clean up. It is often valid, but may fail
21131e1f60c6SV Donaldson   //    for an object with dynamic bounds. This option is "automatically"
21141e1f60c6SV Donaldson   //    used by default for cases that do not use one of the other options.
21151e1f60c6SV Donaldson   //
21161e1f60c6SV Donaldson   //  - Allocate a heap box/descriptor, initialized to zero. This always
21171e1f60c6SV Donaldson   //    works, but is more heavyweight and harder to clean up. It is used
21181e1f60c6SV Donaldson   //    for dynamic objects via calls to genUnusedEntryPointBox.
21191e1f60c6SV Donaldson 
21201e1f60c6SV Donaldson   auto genUnusedEntryPointBox = [&]() {
21211e1f60c6SV Donaldson     if (isUnusedEntryDummy) {
21221e1f60c6SV Donaldson       assert(!Fortran::semantics::IsAllocatableOrPointer(sym) &&
21231e1f60c6SV Donaldson              "handled above");
21241e1f60c6SV Donaldson       // The box is read right away because lowering code does not expect
21251e1f60c6SV Donaldson       // a non pointer/allocatable symbol to be mapped to a MutableBox.
2126658595d0SValentin Clement       mlir::Type ty = converter.genType(var);
2127658595d0SValentin Clement       bool isPolymorphic = false;
2128fac349a1SChristian Sigg       if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) {
2129fac349a1SChristian Sigg         isPolymorphic = mlir::isa<fir::ClassType>(ty);
2130658595d0SValentin Clement         ty = boxTy.getEleTy();
2131658595d0SValentin Clement       }
2132ab9c4e9fSJean Perier       Fortran::lower::genDeclareSymbol(
2133ab9c4e9fSJean Perier           converter, symMap, sym,
21349e37301cSJean Perier           fir::factory::genMutableBoxRead(
21351e1f60c6SV Donaldson               builder, loc,
2136658595d0SValentin Clement               fir::factory::createTempMutableBox(builder, loc, ty, {}, {},
21371710c8cfSSlava Zakharin                                                  isPolymorphic)),
21381710c8cfSSlava Zakharin           fir::FortranVariableFlagsEnum::None,
21391710c8cfSSlava Zakharin           converter.isRegisteredDummySymbol(sym));
21401e1f60c6SV Donaldson       return true;
21411e1f60c6SV Donaldson     }
21421e1f60c6SV Donaldson     return false;
21431e1f60c6SV Donaldson   };
21441e1f60c6SV Donaldson 
21455aba0dedSjeanPerier   if (isAssumedRank) {
21465aba0dedSjeanPerier     assert(isUnusedEntryDummy && "assumed rank must be pointers/allocatables "
21475aba0dedSjeanPerier                                  "or descriptor dummy arguments");
21485aba0dedSjeanPerier     genUnusedEntryPointBox();
21495aba0dedSjeanPerier     return;
21505aba0dedSjeanPerier   }
21515aba0dedSjeanPerier 
2152d88dfd2bSValentin Clement   // Helper to generate scalars for the symbol properties.
2153d88dfd2bSValentin Clement   auto genValue = [&](const Fortran::lower::SomeExpr &expr) {
2154d88dfd2bSValentin Clement     return genScalarValue(converter, loc, expr, symMap, stmtCtx);
2155d88dfd2bSValentin Clement   };
2156d88dfd2bSValentin Clement 
2157d88dfd2bSValentin Clement   // For symbols reaching this point, all properties are constant and can be
2158d88dfd2bSValentin Clement   // read/computed already into ssa values.
2159d88dfd2bSValentin Clement 
2160d88dfd2bSValentin Clement   // The origin must be \vec{1}.
2161d88dfd2bSValentin Clement   auto populateShape = [&](auto &shapes, const auto &bounds, mlir::Value box) {
2162d88dfd2bSValentin Clement     for (auto iter : llvm::enumerate(bounds)) {
2163d88dfd2bSValentin Clement       auto *spec = iter.value();
2164d88dfd2bSValentin Clement       assert(spec->lbound().GetExplicit() &&
2165d88dfd2bSValentin Clement              "lbound must be explicit with constant value 1");
2166d88dfd2bSValentin Clement       if (auto high = spec->ubound().GetExplicit()) {
2167d88dfd2bSValentin Clement         Fortran::lower::SomeExpr highEx{*high};
2168d88dfd2bSValentin Clement         mlir::Value ub = genValue(highEx);
21695bc9ee1bSJean Perier         ub = builder.createConvert(loc, idxTy, ub);
2170d91735b5SjeanPerier         shapes.emplace_back(fir::factory::genMaxWithZero(builder, loc, ub));
2171d88dfd2bSValentin Clement       } else if (spec->ubound().isColon()) {
2172d88dfd2bSValentin Clement         assert(box && "assumed bounds require a descriptor");
2173d88dfd2bSValentin Clement         mlir::Value dim =
2174d88dfd2bSValentin Clement             builder.createIntegerConstant(loc, idxTy, iter.index());
2175d88dfd2bSValentin Clement         auto dimInfo =
2176d88dfd2bSValentin Clement             builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
2177d88dfd2bSValentin Clement         shapes.emplace_back(dimInfo.getResult(1));
2178d88dfd2bSValentin Clement       } else if (spec->ubound().isStar()) {
217927cfe7a0SjeanPerier         shapes.emplace_back(getAssumedSizeExtent(loc, builder));
2180d88dfd2bSValentin Clement       } else {
2181d88dfd2bSValentin Clement         llvm::report_fatal_error("unknown bound category");
2182d88dfd2bSValentin Clement       }
2183d88dfd2bSValentin Clement     }
2184d88dfd2bSValentin Clement   };
2185d88dfd2bSValentin Clement 
2186d88dfd2bSValentin Clement   // The origin is not \vec{1}.
2187d88dfd2bSValentin Clement   auto populateLBoundsExtents = [&](auto &lbounds, auto &extents,
2188d88dfd2bSValentin Clement                                     const auto &bounds, mlir::Value box) {
2189d88dfd2bSValentin Clement     for (auto iter : llvm::enumerate(bounds)) {
2190d88dfd2bSValentin Clement       auto *spec = iter.value();
2191d88dfd2bSValentin Clement       fir::BoxDimsOp dimInfo;
2192d88dfd2bSValentin Clement       mlir::Value ub, lb;
2193d88dfd2bSValentin Clement       if (spec->lbound().isColon() || spec->ubound().isColon()) {
2194d88dfd2bSValentin Clement         // This is an assumed shape because allocatables and pointers extents
2195d88dfd2bSValentin Clement         // are not constant in the scope and are not read here.
2196d88dfd2bSValentin Clement         assert(box && "deferred bounds require a descriptor");
2197d88dfd2bSValentin Clement         mlir::Value dim =
2198d88dfd2bSValentin Clement             builder.createIntegerConstant(loc, idxTy, iter.index());
2199d88dfd2bSValentin Clement         dimInfo =
2200d88dfd2bSValentin Clement             builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim);
2201d88dfd2bSValentin Clement         extents.emplace_back(dimInfo.getResult(1));
2202d88dfd2bSValentin Clement         if (auto low = spec->lbound().GetExplicit()) {
2203d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*low};
2204d88dfd2bSValentin Clement           mlir::Value lb = builder.createConvert(loc, idxTy, genValue(expr));
2205d88dfd2bSValentin Clement           lbounds.emplace_back(lb);
2206d88dfd2bSValentin Clement         } else {
2207d88dfd2bSValentin Clement           // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
2208d88dfd2bSValentin Clement           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, 1));
2209d88dfd2bSValentin Clement         }
2210d88dfd2bSValentin Clement       } else {
2211d88dfd2bSValentin Clement         if (auto low = spec->lbound().GetExplicit()) {
2212d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*low};
2213d88dfd2bSValentin Clement           lb = builder.createConvert(loc, idxTy, genValue(expr));
2214d88dfd2bSValentin Clement         } else {
221539377d52SValentin Clement           TODO(loc, "support for assumed rank entities");
2216d88dfd2bSValentin Clement         }
22175bc9ee1bSJean Perier         lbounds.emplace_back(lb);
2218d88dfd2bSValentin Clement 
2219d88dfd2bSValentin Clement         if (auto high = spec->ubound().GetExplicit()) {
2220d88dfd2bSValentin Clement           auto expr = Fortran::lower::SomeExpr{*high};
2221d88dfd2bSValentin Clement           ub = builder.createConvert(loc, idxTy, genValue(expr));
2222d88dfd2bSValentin Clement           extents.emplace_back(computeExtent(builder, loc, lb, ub));
2223d88dfd2bSValentin Clement         } else {
2224d88dfd2bSValentin Clement           // An assumed size array. The extent is not computed.
2225d88dfd2bSValentin Clement           assert(spec->ubound().isStar() && "expected assumed size");
222627cfe7a0SjeanPerier           extents.emplace_back(getAssumedSizeExtent(loc, builder));
2227d88dfd2bSValentin Clement         }
2228d88dfd2bSValentin Clement       }
2229d88dfd2bSValentin Clement     }
2230d88dfd2bSValentin Clement   };
2231d88dfd2bSValentin Clement 
22329e37301cSJean Perier   //===--------------------------------------------------------------===//
22339e37301cSJean Perier   // Non Pointer non allocatable scalar, explicit shape, and assumed
22349e37301cSJean Perier   // size arrays.
22359e37301cSJean Perier   // Lower the specification expressions.
22369e37301cSJean Perier   //===--------------------------------------------------------------===//
22379e37301cSJean Perier 
22389e37301cSJean Perier   mlir::Value len;
22399e37301cSJean Perier   llvm::SmallVector<mlir::Value> extents;
22409e37301cSJean Perier   llvm::SmallVector<mlir::Value> lbounds;
22419e37301cSJean Perier   auto arg = symMap.lookupSymbol(sym).getAddr();
22429e37301cSJean Perier   mlir::Value addr = preAlloc;
22439e37301cSJean Perier 
22449e37301cSJean Perier   if (arg)
2245fac349a1SChristian Sigg     if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(arg.getType())) {
22469e37301cSJean Perier       // Contiguous assumed shape that can be tracked without a fir.box.
22479e37301cSJean Perier       mlir::Type refTy = builder.getRefType(boxTy.getEleTy());
22489e37301cSJean Perier       addr = builder.create<fir::BoxAddrOp>(loc, refTy, arg);
22499e37301cSJean Perier     }
22509e37301cSJean Perier 
22519e37301cSJean Perier   // Compute/Extract character length.
22529e37301cSJean Perier   if (ba.isChar()) {
22539e37301cSJean Perier     if (arg) {
22549e37301cSJean Perier       assert(!preAlloc && "dummy cannot be pre-allocated");
2255ad4e1abaSjeanPerier       if (mlir::isa<fir::BoxCharType>(arg.getType())) {
22569e37301cSJean Perier         std::tie(addr, len) = charHelp.createUnboxChar(arg);
2257ad4e1abaSjeanPerier       } else if (mlir::isa<fir::CharacterType>(arg.getType())) {
2258ad4e1abaSjeanPerier         // fir.char<1> passed by value (BIND(C) with VALUE attribute).
2259ad4e1abaSjeanPerier         addr = builder.create<fir::AllocaOp>(loc, arg.getType());
2260ad4e1abaSjeanPerier         builder.create<fir::StoreOp>(loc, arg, addr);
2261ad4e1abaSjeanPerier       } else if (!addr) {
226249cb1595SjeanPerier         addr = arg;
2263ad4e1abaSjeanPerier       }
226449cb1595SjeanPerier       // Ensure proper type is given to array/scalar that was transmitted as a
226549cb1595SjeanPerier       // fir.boxchar arg or is a statement function actual argument with
226649cb1595SjeanPerier       // a different length than the dummy.
2267c0cb8f73SjeanPerier       mlir::Type castTy = builder.getRefType(converter.genType(var));
2268c0cb8f73SjeanPerier       addr = builder.createConvert(loc, castTy, addr);
2269c0cb8f73SjeanPerier     }
2270c0921586SKazu Hirata     if (std::optional<int64_t> cstLen = ba.getCharLenConst()) {
22719e37301cSJean Perier       // Static length
22729e37301cSJean Perier       len = builder.createIntegerConstant(loc, idxTy, *cstLen);
22739e37301cSJean Perier     } else {
22749e37301cSJean Perier       // Dynamic length
22759e37301cSJean Perier       if (genUnusedEntryPointBox())
22769e37301cSJean Perier         return;
2277c0921586SKazu Hirata       if (std::optional<Fortran::lower::SomeExpr> charLenExpr =
22789e37301cSJean Perier               ba.getCharLenExpr()) {
22799e37301cSJean Perier         // Explicit length
22809e37301cSJean Perier         mlir::Value rawLen = genValue(*charLenExpr);
2281859d4a18SValentin Clement         // If the length expression is negative, the length is zero. See
2282859d4a18SValentin Clement         // F2018 7.4.4.2 point 5.
22839e37301cSJean Perier         len = fir::factory::genMaxWithZero(builder, loc, rawLen);
22849e37301cSJean Perier       } else if (!len) {
22859e37301cSJean Perier         // Assumed length fir.box (possible for contiguous assumed shapes).
22869e37301cSJean Perier         // Read length from box.
2287fac349a1SChristian Sigg         assert(arg && mlir::isa<fir::BoxType>(arg.getType()) &&
22889e37301cSJean Perier                "must be character dummy fir.box");
22899e37301cSJean Perier         len = charHelp.readLengthFromBox(arg);
229037e84d9bSValentin Clement       }
2291de3efd1bSValentin Clement     }
229237e84d9bSValentin Clement   }
22932a59ead1SValentin Clement 
22948df59132SSlava Zakharin   // Compute array extents and lower bounds.
22958df59132SSlava Zakharin   if (ba.isArray()) {
22969e37301cSJean Perier     if (ba.isStaticArray()) {
22979e37301cSJean Perier       if (ba.lboundIsAllOnes()) {
22989e37301cSJean Perier         for (std::int64_t extent :
22999e37301cSJean Perier              recoverShapeVector(ba.staticShape(), preAlloc))
23009e37301cSJean Perier           extents.push_back(genExtentValue(builder, loc, idxTy, extent));
23019e37301cSJean Perier       } else {
23029e37301cSJean Perier         for (auto [lb, extent] :
23039e37301cSJean Perier              llvm::zip(ba.staticLBound(),
23049e37301cSJean Perier                        recoverShapeVector(ba.staticShape(), preAlloc))) {
23059e37301cSJean Perier           lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, lb));
23069e37301cSJean Perier           extents.emplace_back(genExtentValue(builder, loc, idxTy, extent));
23072a59ead1SValentin Clement         }
23089e37301cSJean Perier       }
23099e37301cSJean Perier     } else {
23109e37301cSJean Perier       // Non compile time constant shape.
23111e1f60c6SV Donaldson       if (genUnusedEntryPointBox())
23121e1f60c6SV Donaldson         return;
23139e37301cSJean Perier       if (ba.lboundIsAllOnes())
23149e37301cSJean Perier         populateShape(extents, ba.dynamicBound(), arg);
2315a1425019SValentin Clement       else
23169e37301cSJean Perier         populateLBoundsExtents(lbounds, extents, ba.dynamicBound(), arg);
2317a1425019SValentin Clement     }
2318a1425019SValentin Clement   }
23199e37301cSJean Perier 
23209e37301cSJean Perier   // Allocate or extract raw address for the entity
23219e37301cSJean Perier   if (!addr) {
23229e37301cSJean Perier     if (arg) {
2323ab9c4e9fSJean Perier       mlir::Type argType = arg.getType();
2324ab9c4e9fSJean Perier       const bool isCptrByVal = Fortran::semantics::IsBuiltinCPtr(sym) &&
2325ab9c4e9fSJean Perier                                Fortran::lower::isCPtrArgByValueType(argType);
2326ab9c4e9fSJean Perier       if (isCptrByVal || !fir::conformsWithPassByRef(argType)) {
2327ab9c4e9fSJean Perier         // Dummy argument passed in register. Place the value in memory at that
2328ab9c4e9fSJean Perier         // point since lowering expect symbols to be mapped to memory addresses.
2329ab9c4e9fSJean Perier         mlir::Type symType = converter.genType(sym);
2330ab9c4e9fSJean Perier         addr = builder.create<fir::AllocaOp>(loc, symType);
2331ab9c4e9fSJean Perier         if (isCptrByVal) {
2332ab9c4e9fSJean Perier           // Place the void* address into the CPTR address component.
2333ab9c4e9fSJean Perier           mlir::Value addrComponent =
2334ab9c4e9fSJean Perier               fir::factory::genCPtrOrCFunptrAddr(builder, loc, addr, symType);
2335ab9c4e9fSJean Perier           builder.createStoreWithConvert(loc, arg, addrComponent);
2336ab9c4e9fSJean Perier         } else {
2337ab9c4e9fSJean Perier           builder.createStoreWithConvert(loc, arg, addr);
2338ab9c4e9fSJean Perier         }
23399e37301cSJean Perier       } else {
23409e37301cSJean Perier         // Dummy address, or address of result whose storage is passed by the
23419e37301cSJean Perier         // caller.
2342ab9c4e9fSJean Perier         assert(fir::isa_ref_type(argType) && "must be a memory address");
23439e37301cSJean Perier         addr = arg;
23449e37301cSJean Perier       }
2345a1425019SValentin Clement     } else {
23469e37301cSJean Perier       // Local variables
23479e37301cSJean Perier       llvm::SmallVector<mlir::Value> typeParams;
23489e37301cSJean Perier       if (len)
23499e37301cSJean Perier         typeParams.emplace_back(len);
23509e37301cSJean Perier       addr = createNewLocal(converter, loc, var, preAlloc, extents, typeParams);
2351a1425019SValentin Clement     }
23529e37301cSJean Perier   }
2353a1425019SValentin Clement 
2354ab9c4e9fSJean Perier   ::genDeclareSymbol(converter, symMap, sym, addr, len, extents, lbounds,
23559e37301cSJean Perier                      replace);
2356a1425019SValentin Clement   return;
2357a1425019SValentin Clement }
23582c2e5a5dSValentin Clement 
235917d71347SValentin Clement void Fortran::lower::defineModuleVariable(
236017d71347SValentin Clement     AbstractConverter &converter, const Fortran::lower::pft::Variable &var) {
236117d71347SValentin Clement   // Use empty linkage for module variables, which makes them available
236217d71347SValentin Clement   // for use in another unit.
2363a1425019SValentin Clement   mlir::StringAttr linkage =
2364a1425019SValentin Clement       getLinkageAttribute(converter.getFirOpBuilder(), var);
236517d71347SValentin Clement   if (!var.isGlobal())
236617d71347SValentin Clement     fir::emitFatalError(converter.getCurrentLocation(),
236717d71347SValentin Clement                         "attempting to lower module variable as local");
236817d71347SValentin Clement   // Define aggregate storages for equivalenced objects.
236917d71347SValentin Clement   if (var.isAggregateStore()) {
2370a1425019SValentin Clement     const Fortran::lower::pft::Variable::AggregateStore &aggregate =
2371a1425019SValentin Clement         var.getAggregateStore();
23722c143345SV Donaldson     std::string aggName = mangleGlobalAggregateStore(converter, aggregate);
2373a1425019SValentin Clement     defineGlobalAggregateStore(converter, aggregate, aggName, linkage);
2374a1425019SValentin Clement     return;
237517d71347SValentin Clement   }
237617d71347SValentin Clement   const Fortran::semantics::Symbol &sym = var.getSymbol();
23775d25267dSValentin Clement   if (const Fortran::semantics::Symbol *common =
23785d25267dSValentin Clement           Fortran::semantics::FindCommonBlockContaining(var.getSymbol())) {
23792c8cb9acSJean Perier     // Nothing to do, common block are generated before everything. Ensure
23802c8cb9acSJean Perier     // this was done by calling getCommonBlockGlobal.
23812c8cb9acSJean Perier     getCommonBlockGlobal(converter, *common);
238217d71347SValentin Clement   } else if (var.isAlias()) {
238317d71347SValentin Clement     // Do nothing. Mapping will be done on user side.
238417d71347SValentin Clement   } else {
23852c143345SV Donaldson     std::string globalName = converter.mangleName(sym);
238645daa4fdSValentin Clement (バレンタイン クレメン)     cuf::DataAttributeAttr dataAttr =
238745daa4fdSValentin Clement (バレンタイン クレメン)         Fortran::lower::translateSymbolCUFDataAttribute(
2388314ef961SValentin Clement (バレンタイン クレメン)             converter.getFirOpBuilder().getContext(), sym);
238945daa4fdSValentin Clement (バレンタイン クレメン)     defineGlobal(converter, var, globalName, linkage, dataAttr);
239017d71347SValentin Clement   }
239117d71347SValentin Clement }
239217d71347SValentin Clement 
23932c2e5a5dSValentin Clement void Fortran::lower::instantiateVariable(AbstractConverter &converter,
23942c2e5a5dSValentin Clement                                          const pft::Variable &var,
2395a1425019SValentin Clement                                          Fortran::lower::SymMap &symMap,
23968c22cb84SValentin Clement                                          AggregateStoreMap &storeMap) {
23979e37301cSJean Perier   if (var.hasSymbol()) {
23989e37301cSJean Perier     // Do not try to instantiate symbols twice, except for dummies and results,
23999e37301cSJean Perier     // that may have been mapped to the MLIR entry block arguments, and for
24009e37301cSJean Perier     // which the explicit specifications, if any, has not yet been lowered.
24019e37301cSJean Perier     const auto &sym = var.getSymbol();
24029e37301cSJean Perier     if (!IsDummy(sym) && !IsFunctionResult(sym) && symMap.lookupSymbol(sym))
24039e37301cSJean Perier       return;
24049e37301cSJean Perier   }
2405518e6f12SV Donaldson   LLVM_DEBUG(llvm::dbgs() << "instantiateVariable: "; var.dump());
2406518e6f12SV Donaldson   if (var.isAggregateStore())
2407a1425019SValentin Clement     instantiateAggregateStore(converter, var, storeMap);
2408518e6f12SV Donaldson   else if (const Fortran::semantics::Symbol *common =
24095d25267dSValentin Clement                Fortran::semantics::FindCommonBlockContaining(
2410518e6f12SV Donaldson                    var.getSymbol().GetUltimate()))
24115d25267dSValentin Clement     instantiateCommon(converter, *common, var, symMap);
2412518e6f12SV Donaldson   else if (var.isAlias())
2413a1425019SValentin Clement     instantiateAlias(converter, var, symMap, storeMap);
2414518e6f12SV Donaldson   else if (var.isGlobal())
24158c22cb84SValentin Clement     instantiateGlobal(converter, var, symMap);
2416518e6f12SV Donaldson   else
24172c2e5a5dSValentin Clement     instantiateLocal(converter, var, symMap);
24182c2e5a5dSValentin Clement }
2419d0b70a07SValentin Clement 
24208eee2360SjeanPerier static void
24218eee2360SjeanPerier mapCallInterfaceSymbol(const Fortran::semantics::Symbol &interfaceSymbol,
24228eee2360SjeanPerier                        Fortran::lower::AbstractConverter &converter,
24238eee2360SjeanPerier                        const Fortran::lower::CallerInterface &caller,
24248eee2360SjeanPerier                        Fortran::lower::SymMap &symMap) {
24258c22cb84SValentin Clement   Fortran::lower::AggregateStoreMap storeMap;
2426d0b70a07SValentin Clement   for (Fortran::lower::pft::Variable var :
24278eee2360SjeanPerier        Fortran::lower::pft::getDependentVariableList(interfaceSymbol)) {
2428d0b70a07SValentin Clement     if (var.isAggregateStore()) {
24298c22cb84SValentin Clement       instantiateVariable(converter, var, symMap, storeMap);
2430518e6f12SV Donaldson       continue;
2431518e6f12SV Donaldson     }
2432d0b70a07SValentin Clement     const Fortran::semantics::Symbol &sym = var.getSymbol();
24338eee2360SjeanPerier     if (&sym == &interfaceSymbol)
2434518e6f12SV Donaldson       continue;
2435d0b70a07SValentin Clement     const auto *hostDetails =
2436d0b70a07SValentin Clement         sym.detailsIf<Fortran::semantics::HostAssocDetails>();
2437518e6f12SV Donaldson     if (hostDetails && !var.isModuleOrSubmoduleVariable()) {
2438d0b70a07SValentin Clement       // The callee is an internal procedure `A` whose result properties
2439d0b70a07SValentin Clement       // depend on host variables. The caller may be the host, or another
2440d0b70a07SValentin Clement       // internal procedure `B` contained in the same host. In the first
2441d0b70a07SValentin Clement       // case, the host symbol is obviously mapped, in the second case, it
2442d0b70a07SValentin Clement       // must also be mapped because
2443d0b70a07SValentin Clement       // HostAssociations::internalProcedureBindings that was called when
2444d0b70a07SValentin Clement       // lowering `B` will have mapped all host symbols of captured variables
2445d0b70a07SValentin Clement       // to the tuple argument containing the composite of all host associated
2446d0b70a07SValentin Clement       // variables, whether or not the host symbol is actually referred to in
2447d0b70a07SValentin Clement       // `B`. Hence it is possible to simply lookup the variable associated to
2448d0b70a07SValentin Clement       // the host symbol without having to go back to the tuple argument.
2449ab9c4e9fSJean Perier       symMap.copySymbolBinding(hostDetails->symbol(), sym);
2450d0b70a07SValentin Clement       // The SymbolBox associated to the host symbols is complete, skip
2451d0b70a07SValentin Clement       // instantiateVariable that would try to allocate a new storage.
2452d0b70a07SValentin Clement       continue;
2453d0b70a07SValentin Clement     }
24548eee2360SjeanPerier     if (Fortran::semantics::IsDummy(sym) &&
24558eee2360SjeanPerier         sym.owner() == interfaceSymbol.owner()) {
2456d0b70a07SValentin Clement       // Get the argument for the dummy argument symbols of the current call.
2457d0b70a07SValentin Clement       symMap.addSymbol(sym, caller.getArgumentValue(sym));
2458d0b70a07SValentin Clement       // All the properties of the dummy variable may not come from the actual
2459d0b70a07SValentin Clement       // argument, let instantiateVariable handle this.
2460d0b70a07SValentin Clement     }
2461d0b70a07SValentin Clement     // If this is neither a host associated or dummy symbol, it must be a
2462d0b70a07SValentin Clement     // module or common block variable to satisfy specification expression
2463d0b70a07SValentin Clement     // requirements in 10.1.11, instantiateVariable will get its address and
2464d0b70a07SValentin Clement     // properties.
24658c22cb84SValentin Clement     instantiateVariable(converter, var, symMap, storeMap);
2466d0b70a07SValentin Clement   }
2467d0b70a07SValentin Clement }
2468a1425019SValentin Clement 
24698eee2360SjeanPerier void Fortran::lower::mapCallInterfaceSymbolsForResult(
24708eee2360SjeanPerier     AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
24718eee2360SjeanPerier     SymMap &symMap) {
24728eee2360SjeanPerier   const Fortran::semantics::Symbol &result = caller.getResultSymbol();
24738eee2360SjeanPerier   mapCallInterfaceSymbol(result, converter, caller, symMap);
24748eee2360SjeanPerier }
24758eee2360SjeanPerier 
24768eee2360SjeanPerier void Fortran::lower::mapCallInterfaceSymbolsForDummyArgument(
24778eee2360SjeanPerier     AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
24788eee2360SjeanPerier     SymMap &symMap, const Fortran::semantics::Symbol &dummySymbol) {
24798eee2360SjeanPerier   mapCallInterfaceSymbol(dummySymbol, converter, caller, symMap);
24808eee2360SjeanPerier }
24818eee2360SjeanPerier 
24828febe678SJean Perier void Fortran::lower::mapSymbolAttributes(
24838febe678SJean Perier     AbstractConverter &converter, const Fortran::semantics::SymbolRef &symbol,
24848febe678SJean Perier     Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
24858febe678SJean Perier     mlir::Value preAlloc) {
24868febe678SJean Perier   mapSymbolAttributes(converter, pft::Variable{symbol}, symMap, stmtCtx,
24878febe678SJean Perier                       preAlloc);
24888febe678SJean Perier }
24898febe678SJean Perier 
24903aba9264Svdonaldson void Fortran::lower::createIntrinsicModuleGlobal(
24913aba9264Svdonaldson     Fortran::lower::AbstractConverter &converter, const pft::Variable &var) {
24923aba9264Svdonaldson   defineGlobal(converter, var, converter.mangleName(var.getSymbol()),
24933aba9264Svdonaldson                converter.getFirOpBuilder().createLinkOnceODRLinkage());
24943aba9264Svdonaldson }
24953aba9264Svdonaldson 
2496a1425019SValentin Clement void Fortran::lower::createRuntimeTypeInfoGlobal(
24973aba9264Svdonaldson     Fortran::lower::AbstractConverter &converter,
2498a1425019SValentin Clement     const Fortran::semantics::Symbol &typeInfoSym) {
2499a1425019SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
25002c143345SV Donaldson   std::string globalName = converter.mangleName(typeInfoSym);
2501a1425019SValentin Clement   auto var = Fortran::lower::pft::Variable(typeInfoSym, /*global=*/true);
2502a1425019SValentin Clement   mlir::StringAttr linkage = getLinkageAttribute(builder, var);
2503a1425019SValentin Clement   defineGlobal(converter, var, globalName, linkage);
2504a1425019SValentin Clement }
2505f8843efbSSlava Zakharin 
2506de7a50fbSjeanPerier mlir::Type Fortran::lower::getCrayPointeeBoxType(mlir::Type fortranType) {
2507de7a50fbSjeanPerier   mlir::Type baseType = hlfir::getFortranElementOrSequenceType(fortranType);
2508de7a50fbSjeanPerier   if (auto seqType = mlir::dyn_cast<fir::SequenceType>(baseType)) {
2509de7a50fbSjeanPerier     // The pointer box's sequence type must be with unknown shape.
2510de7a50fbSjeanPerier     llvm::SmallVector<int64_t> shape(seqType.getDimension(),
2511de7a50fbSjeanPerier                                      fir::SequenceType::getUnknownExtent());
2512de7a50fbSjeanPerier     baseType = fir::SequenceType::get(shape, seqType.getEleTy());
2513f8843efbSSlava Zakharin   }
2514de7a50fbSjeanPerier   return fir::BoxType::get(fir::PointerType::get(baseType));
2515f8843efbSSlava Zakharin }
2516