1 //===-- ConvertVariable.cpp -- bridge to lower to MLIR --------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
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
,
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
,
68 return hlfir::loadTrivialScalar(loc
, converter
.getFirOpBuilder(),
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
);
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
);
110 // Does this variable have an allocatable direct component?
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(
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
,
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
,
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
))
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.
194 hasDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol
&sym
) {
195 if (const Fortran::semantics::DeclTypeSpec
*declTy
= sym
.GetType())
196 if (const Fortran::semantics::DerivedTypeSpec
*derived
=
198 return Fortran::semantics::CountLenParameters(*derived
) > 0;
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
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
,
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
>(
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
245 if (sym
->owner().IsDerivedType())
247 // Length parameters processing will need care in global initializer
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())
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
,
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();
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
);
285 fir::factory::createUnallocatedBox(builder
, loc
, boxType
, {});
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
);
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
);
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
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.
345 genInitialDataTarget(converter
, loc
, componentTy
, *init
);
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
);
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
{
369 .detailsIf
<Fortran::semantics::ProcEntityDetails
>()}) {
370 if (proc
->init().has_value()) {
371 auto sym
{*proc
->init()};
372 if (sym
) // Has a procedure target.
374 Fortran::lower::convertProcedureDesignatorInitialTarget(converter
,
376 else // Has NULL() target.
378 fir::factory::createNullBoxProc(builder
, loc
, componentTy
);
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
)) {
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
>()
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
);
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
))
439 initialValue
= genComponentDefaultInit(converter
, loc
, component
, recTy
,
440 initialValue
, stmtCtx
);
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())
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
));
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
®ion
= global
.getRegion();
473 region
.push_back(new mlir::Block
);
474 mlir::Block
&block
= region
.back();
475 auto insertPt
= builder
.saveInsertionPoint();
476 builder
.setInsertionPointToStart(&block
);
478 builder
.restoreInsertionPoint(insertPt
);
481 static unsigned getAllocatorIdx(cuf::DataAttributeAttr 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
))
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
);
531 global
.setVisibility(mlir::SymbolTable::Visibility::Public
);
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
);
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(
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
);
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
);
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");
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
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
);
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
);
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
);
687 cuf::DataAttributeAttr dataAttr
=
688 Fortran::lower::translateSymbolCUFDataAttribute(builder
.getContext(),
690 global
= defineGlobal(converter
, var
, globalName
, linkage
, dataAttr
);
692 auto addrOf
= builder
.create
<fir::AddrOfOp
>(loc
, global
.resultType(),
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
705 static mlir::Value
createNewLocal(Fortran::lower::AbstractConverter
&converter
,
707 const Fortran::lower::pft::Variable
&var
,
708 mlir::Value preAlloc
,
709 llvm::ArrayRef
<mlir::Value
> shape
= {},
710 llvm::ArrayRef
<mlir::Value
> lenParams
= {}) {
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(),
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
);
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
);
756 /// Must \p var be default initialized at runtime when entering its scope.
758 mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable
&var
) {
759 if (!var
.hasSymbol())
761 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
763 // Global variables are statically initialized.
765 if (Fortran::semantics::IsDummy(sym
) && !Fortran::semantics::IsIntentOut(sym
))
767 // Polymorphic intent(out) dummy might need default initialization
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
))
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(),
793 builder
.genIfThen(loc
, isPresent
)
795 auto box
= builder
.createBox(loc
, exv
);
796 fir::runtime::genDerivedTypeInitialize(builder
, loc
, box
);
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())
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.
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
;
854 /// Check whether a variable needs the be finalized according to clause 7.5.6.3
856 /// Must be nonpointer, nonallocatable, INTENT (OUT) dummy argument.
858 needDummyIntentoutFinalization(const Fortran::lower::pft::Variable
&var
) {
859 if (!var
.hasSymbol())
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
))
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
))
872 // Intent(out) dummies must be finalized at runtime if their type has a
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(),
892 builder
.genIfThen(loc
, isPresent
)
894 auto box
= builder
.createBox(loc
, exv
);
895 fir::runtime::genDerivedTypeDestroy(builder
, loc
, box
);
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
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())
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
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
))
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
)
941 Fortran::lower::genDeallocateIfAllocated(converter
, *mutBox
, loc
);
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
)
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(),
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(),
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
);
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
);
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
,
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.
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.
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
))
1075 mlir::Location loc
= converter
.getCurrentLocation();
1076 mlir::Type aggTy
= getAggregateType(converter
, aggregate
);
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
);
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
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
);
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
))
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.
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
,
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
);
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
);
1166 builder
.allocateLocal(loc
, seqTy
, aggName
, "", std::nullopt
, std::nullopt
,
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
),
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(),
1217 //===--------------------------------------------------------------===//
1218 // COMMON blocks instantiation
1219 //===--------------------------------------------------------------===//
1221 /// Does any member of the common block has an initializer ?
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
>())
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
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
=
1292 .detailsIf
<Fortran::semantics::ObjectEntityDetails
>()) {
1293 const Fortran::semantics::Symbol
*com
=
1294 FindCommonBlockContaining(obj
.symbol
);
1295 if (!details
->init() || com
!= &common
)
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
);
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.
1320 fir::emitFatalError(converter
.genLocation(common
.name()),
1321 "COMMON block was not lowered before its usage");
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
);
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.
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
) {
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
));
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
,
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
);
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
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();
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()))
1501 // Non contiguous arrays must be tracked in an BoxValue.
1502 if (sym
.Rank() > 0 && !Fortran::evaluate::IsSimplyContiguous(
1503 sym
, converter
.getFoldingContext()))
1505 // Assumed rank and optional fir.box cannot yet be read while lowering the
1507 if (Fortran::evaluate::IsAssumedRank(sym
) ||
1508 Fortran::semantics::IsOptional(sym
))
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())
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())
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
));
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.
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
) {
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
));
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
));
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.
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
) {
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
1617 return fir::factory::genMaxWithZero(
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
;
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
1646 result
.assign(shapeVec
.begin(), shapeVec
.end());
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
)
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
);
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())
1705 if (funit
->getHostAssoc().isAssociated(sym
))
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
))
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
;
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
,
1760 cuf::DataAttributeAttr dataAttr
=
1761 Fortran::lower::translateSymbolCUFDataAttribute(builder
.getContext(),
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(
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())
1786 // Inherit the shape (and maybe length parameters) from the pointee
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
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
);
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
,
1808 symMap
.addVariableDefinition(sym
, newBase
, force
);
1813 if (!shape
.empty()) {
1814 if (!lbounds
.empty())
1815 symMap
.addCharSymbolWithBounds(sym
, base
, len
, shape
, lbounds
, force
);
1817 symMap
.addCharSymbolWithShape(sym
, base
, len
, shape
, force
);
1819 symMap
.addCharSymbol(sym
, base
, len
, force
);
1822 if (!shape
.empty()) {
1823 if (!lbounds
.empty())
1824 symMap
.addSymbolWithBounds(sym
, base
, shape
, lbounds
, force
);
1826 symMap
.addSymbolWithShape(sym
, base
, shape
, force
);
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
,
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(),
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
);
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.
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
);
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
);
1922 symMap
.addBoxSymbol(sym
, box
, lbounds
, explicitParams
, explicitExtents
,
1926 static unsigned getAllocatorIdx(const Fortran::semantics::Symbol
&sym
) {
1927 std::optional
<Fortran::common::CUDADataAttr
> cudaAttr
=
1928 Fortran::semantics::GetCUDADataAttr(&sym
.GetUltimate());
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
)) {
1977 mlir::Value boxAlloc
= preAlloc
;
1978 // dummy or passed result
1980 if (Fortran::lower::SymbolBox symbox
= symMap
.lookupSymbol(sym
))
1981 boxAlloc
= symbox
.getAddr();
1984 boxAlloc
= createNewLocal(converter
, loc
, var
, preAlloc
);
1985 genProcPointer(converter
, symMap
, sym
, boxAlloc
, replace
);
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
;
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.
2002 mlir::Value boxAlloc
= preAlloc
;
2003 // dummy or passed result
2005 if (Fortran::lower::SymbolBox symbox
= symMap
.lookupSymbol(sym
))
2006 boxAlloc
= symbox
.getAddr();
2007 assert((boxAlloc
|| !isAssumedRank
) && "assumed-ranks cannot be local");
2010 boxAlloc
= createNewLocal(converter
, loc
, var
, preAlloc
);
2011 // Lower non deferred parameters.
2012 llvm::SmallVector
<mlir::Value
> nonDeferredLenParams
;
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)
2026 "derived type allocatable or pointer with length parameters");
2028 fir::MutableBoxValue box
= Fortran::lower::createMutableBox(
2029 converter
, loc
, var
, boxAlloc
, nonDeferredLenParams
,
2031 converter
.getLoweringOptions().getLowerToHighLevelFIR(),
2032 getAllocatorIdx(var
.getSymbol()));
2033 genAllocatableOrPointerDeclare(converter
, symMap
, var
.getSymbol(), box
,
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
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
);
2063 .genIfOp(loc
, {refTy
, lenType
}, isPresent
,
2064 /*withElseRegion=*/true)
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
});
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
});
2081 addr
= addrAndLen
[0];
2082 len
= addrAndLen
[1];
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
);
2094 // TODO: derived type length parameters.
2095 if (!isAssumedRank
) {
2096 lowerExplicitLowerBounds(converter
, loc
, ba
, lbounds
, symMap
, stmtCtx
);
2097 lowerExplicitExtents(converter
, loc
, ba
, lbounds
, explicitExtents
,
2100 genBoxDeclare(converter
, symMap
, sym
, dummyArg
, lbounds
, explicitParams
,
2101 explicitExtents
, replace
);
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
) &&
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(
2143 fir::factory::createTempMutableBox(builder
, loc
, ty
, {}, {},
2145 fir::FortranVariableFlagsEnum::None
,
2146 converter
.isRegisteredDummySymbol(sym
));
2152 if (isAssumedRank
) {
2153 assert(isUnusedEntryDummy
&& "assumed rank must be pointers/allocatables "
2154 "or descriptor dummy arguments");
2155 genUnusedEntryPointBox();
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");
2181 builder
.createIntegerConstant(loc
, idxTy
, iter
.index());
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
));
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
;
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");
2205 builder
.createIntegerConstant(loc
, idxTy
, iter
.index());
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
);
2214 // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
2215 lbounds
.emplace_back(builder
.createIntegerConstant(loc
, idxTy
, 1));
2218 if (auto low
= spec
->lbound().GetExplicit()) {
2219 auto expr
= Fortran::lower::SomeExpr
{*low
};
2220 lb
= builder
.createConvert(loc
, idxTy
, genValue(expr
));
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
));
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
2242 // Lower the specification expressions.
2243 //===--------------------------------------------------------------===//
2246 llvm::SmallVector
<mlir::Value
> extents
;
2247 llvm::SmallVector
<mlir::Value
> lbounds
;
2248 auto arg
= symMap
.lookupSymbol(sym
).getAddr();
2249 mlir::Value addr
= preAlloc
;
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.
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
);
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()) {
2279 len
= builder
.createIntegerConstant(loc
, idxTy
, *cstLen
);
2282 if (genUnusedEntryPointBox())
2284 if (std::optional
<Fortran::lower::SomeExpr
> charLenExpr
=
2285 ba
.getCharLenExpr()) {
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
);
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.
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
));
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
));
2317 // Non compile time constant shape.
2318 if (genUnusedEntryPointBox())
2320 if (ba
.lboundIsAllOnes())
2321 populateShape(extents
, ba
.dynamicBound(), arg
);
2323 populateLBoundsExtents(lbounds
, extents
, ba
.dynamicBound(), arg
);
2327 // Allocate or extract raw address for the entity
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
);
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
);
2344 builder
.createStoreWithConvert(loc
, arg
, addr
);
2347 // Dummy address, or address of result whose storage is passed by the
2349 assert(fir::isa_ref_type(argType
) && "must be a memory address");
2354 llvm::SmallVector
<mlir::Value
> typeParams
;
2356 typeParams
.emplace_back(len
);
2357 addr
= createNewLocal(converter
, loc
, var
, preAlloc
, extents
, typeParams
);
2361 ::genDeclareSymbol(converter
, symMap
, sym
, addr
, len
, extents
, lbounds
,
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
);
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.
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
))
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
);
2424 instantiateLocal(converter
, var
, symMap
);
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
);
2439 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
2440 if (&sym
== &interfaceSymbol
)
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.
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
2472 instantiateVariable(converter
, var
, symMap
, storeMap
);
2476 void Fortran::lower::mapCallInterfaceSymbolsForResult(
2477 AbstractConverter
&converter
, const Fortran::lower::CallerInterface
&caller
,
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
,
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
));