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