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 ®ion = 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