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.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
= builder
.create
<fir::ZeroOp
>(loc
, symTy
);
639 builder
.create
<fir::HasValueOp
>(loc
, initValue
);
642 // Set public visibility to prevent global definition to be optimized out
643 // even if they have no initializer and are unused in this compilation unit.
644 global
.setVisibility(mlir::SymbolTable::Visibility::Public
);
648 /// Return linkage attribute for \p var.
649 static mlir::StringAttr
650 getLinkageAttribute(fir::FirOpBuilder
&builder
,
651 const Fortran::lower::pft::Variable
&var
) {
652 // Runtime type info for a same derived type is identical in each compilation
653 // unit. It desired to avoid having to link against module that only define a
654 // type. Therefore the runtime type info is generated everywhere it is needed
655 // with `linkonce_odr` LLVM linkage.
656 if (var
.isRuntimeTypeInfoData())
657 return builder
.createLinkOnceODRLinkage();
658 if (var
.isModuleOrSubmoduleVariable())
659 return {}; // external linkage
660 // Otherwise, the variable is owned by a procedure and must not be visible in
661 // other compilation units.
662 return builder
.createInternalLinkage();
665 /// Instantiate a global variable. If it hasn't already been processed, add
666 /// the global to the ModuleOp as a new uniqued symbol and initialize it with
667 /// the correct value. It will be referenced on demand using `fir.addr_of`.
668 static void instantiateGlobal(Fortran::lower::AbstractConverter
&converter
,
669 const Fortran::lower::pft::Variable
&var
,
670 Fortran::lower::SymMap
&symMap
) {
671 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
672 assert(!var
.isAlias() && "must be handled in instantiateAlias");
673 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
674 std::string globalName
= converter
.mangleName(sym
);
675 mlir::Location loc
= genLocation(converter
, sym
);
676 mlir::StringAttr linkage
= getLinkageAttribute(builder
, var
);
677 fir::GlobalOp global
;
678 if (var
.isModuleOrSubmoduleVariable()) {
679 // A non-intrinsic module global is defined when lowering the module.
680 // Emit only a declaration if the global does not exist.
681 global
= declareGlobal(converter
, var
, globalName
, linkage
);
683 cuf::DataAttributeAttr dataAttr
=
684 Fortran::lower::translateSymbolCUFDataAttribute(builder
.getContext(),
686 global
= defineGlobal(converter
, var
, globalName
, linkage
, dataAttr
);
688 auto addrOf
= builder
.create
<fir::AddrOfOp
>(loc
, global
.resultType(),
690 Fortran::lower::StatementContext stmtCtx
;
691 mapSymbolAttributes(converter
, var
, symMap
, stmtCtx
, addrOf
);
694 //===----------------------------------------------------------------===//
695 // Local variables instantiation (not for alias)
696 //===----------------------------------------------------------------===//
698 /// Create a stack slot for a local variable. Precondition: the insertion
699 /// point of the builder must be in the entry block, which is currently being
701 static mlir::Value
createNewLocal(Fortran::lower::AbstractConverter
&converter
,
703 const Fortran::lower::pft::Variable
&var
,
704 mlir::Value preAlloc
,
705 llvm::ArrayRef
<mlir::Value
> shape
= {},
706 llvm::ArrayRef
<mlir::Value
> lenParams
= {}) {
709 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
710 std::string nm
= converter
.mangleName(var
.getSymbol());
711 mlir::Type ty
= converter
.genType(var
);
712 const Fortran::semantics::Symbol
&ultimateSymbol
=
713 var
.getSymbol().GetUltimate();
714 llvm::StringRef symNm
= toStringRef(ultimateSymbol
.name());
715 bool isTarg
= var
.isTarget();
717 // Do not allocate storage for cray pointee. The address inside the cray
718 // pointer will be used instead when using the pointee. Allocating space
719 // would be a waste of space, and incorrect if the pointee is a non dummy
720 // assumed-size (possible with cray pointee).
721 if (ultimateSymbol
.test(Fortran::semantics::Symbol::Flag::CrayPointee
))
722 return builder
.create
<fir::ZeroOp
>(loc
, fir::ReferenceType::get(ty
));
724 if (Fortran::semantics::NeedCUDAAlloc(ultimateSymbol
)) {
725 cuf::DataAttributeAttr dataAttr
=
726 Fortran::lower::translateSymbolCUFDataAttribute(builder
.getContext(),
728 llvm::SmallVector
<mlir::Value
> indices
;
729 llvm::SmallVector
<mlir::Value
> elidedShape
=
730 fir::factory::elideExtentsAlreadyInType(ty
, shape
);
731 llvm::SmallVector
<mlir::Value
> elidedLenParams
=
732 fir::factory::elideLengthsAlreadyInType(ty
, lenParams
);
733 auto idxTy
= builder
.getIndexType();
734 for (mlir::Value sh
: elidedShape
)
735 indices
.push_back(builder
.createConvert(loc
, idxTy
, sh
));
736 mlir::Value alloc
= builder
.create
<cuf::AllocOp
>(
737 loc
, ty
, nm
, symNm
, dataAttr
, lenParams
, indices
);
741 // Let the builder do all the heavy lifting.
742 if (!Fortran::semantics::IsProcedurePointer(ultimateSymbol
))
743 return builder
.allocateLocal(loc
, ty
, nm
, symNm
, shape
, lenParams
, isTarg
);
745 // Local procedure pointer.
746 auto res
{builder
.allocateLocal(loc
, ty
, nm
, symNm
, shape
, lenParams
, isTarg
)};
747 auto box
{fir::factory::createNullBoxProc(builder
, loc
, ty
)};
748 builder
.create
<fir::StoreOp
>(loc
, box
, res
);
752 /// Must \p var be default initialized at runtime when entering its scope.
754 mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable
&var
) {
755 if (!var
.hasSymbol())
757 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
759 // Global variables are statically initialized.
761 if (Fortran::semantics::IsDummy(sym
) && !Fortran::semantics::IsIntentOut(sym
))
763 // Polymorphic intent(out) dummy might need default initialization
765 if (Fortran::semantics::IsPolymorphic(sym
) &&
766 Fortran::semantics::IsDummy(sym
) &&
767 Fortran::semantics::IsIntentOut(sym
) &&
768 !Fortran::semantics::IsAllocatable(sym
) &&
769 !Fortran::semantics::IsPointer(sym
))
771 // Local variables (including function results), and intent(out) dummies must
772 // be default initialized at runtime if their type has default initialization.
773 return Fortran::lower::hasDefaultInitialization(sym
);
776 /// Call default initialization runtime routine to initialize \p var.
777 void Fortran::lower::defaultInitializeAtRuntime(
778 Fortran::lower::AbstractConverter
&converter
,
779 const Fortran::semantics::Symbol
&sym
, Fortran::lower::SymMap
&symMap
) {
780 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
781 mlir::Location loc
= converter
.getCurrentLocation();
782 fir::ExtendedValue exv
= converter
.getSymbolExtendedValue(sym
, &symMap
);
783 if (Fortran::semantics::IsOptional(sym
)) {
784 // 15.5.2.12 point 3, absent optional dummies are not initialized.
785 // Creating descriptor/passing null descriptor to the runtime would
786 // create runtime crashes.
787 auto isPresent
= builder
.create
<fir::IsPresentOp
>(loc
, builder
.getI1Type(),
789 builder
.genIfThen(loc
, isPresent
)
791 auto box
= builder
.createBox(loc
, exv
);
792 fir::runtime::genDerivedTypeInitialize(builder
, loc
, box
);
796 mlir::Value box
= builder
.createBox(loc
, exv
);
797 fir::runtime::genDerivedTypeInitialize(builder
, loc
, box
);
801 enum class VariableCleanUp
{ Finalize
, Deallocate
};
802 /// Check whether a local variable needs to be finalized according to clause
803 /// 7.5.6.3 point 3 or if it is an allocatable that must be deallocated. Note
804 /// that deallocation will trigger finalization if the type has any.
805 static std::optional
<VariableCleanUp
>
806 needDeallocationOrFinalization(const Fortran::lower::pft::Variable
&var
) {
807 if (!var
.hasSymbol())
809 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
810 const Fortran::semantics::Scope
&owner
= sym
.owner();
811 if (owner
.kind() == Fortran::semantics::Scope::Kind::MainProgram
) {
812 // The standard does not require finalizing main program variables.
815 if (!Fortran::semantics::IsPointer(sym
) &&
816 !Fortran::semantics::IsDummy(sym
) &&
817 !Fortran::semantics::IsFunctionResult(sym
) &&
818 !Fortran::semantics::IsSaved(sym
)) {
819 if (Fortran::semantics::IsAllocatable(sym
))
820 return VariableCleanUp::Deallocate
;
821 if (hasFinalization(sym
))
822 return VariableCleanUp::Finalize
;
823 // hasFinalization() check above handled all cases that require
824 // finalization, but we also have to deallocate all allocatable
825 // components of local variables (since they are also local variables
826 // according to F18 5.4.3.2.2, p. 2, note 1).
827 // Here, the variable itself is not allocatable. If it has an allocatable
828 // component the Destroy runtime does the job. Use the Finalize clean-up,
829 // though there will be no finalization in runtime.
830 if (hasAllocatableDirectComponent(sym
))
831 return VariableCleanUp::Finalize
;
836 /// Check whether a variable needs the be finalized according to clause 7.5.6.3
838 /// Must be nonpointer, nonallocatable, INTENT (OUT) dummy argument.
840 needDummyIntentoutFinalization(const Fortran::lower::pft::Variable
&var
) {
841 if (!var
.hasSymbol())
843 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
844 if (!Fortran::semantics::IsDummy(sym
) ||
845 !Fortran::semantics::IsIntentOut(sym
) ||
846 Fortran::semantics::IsAllocatable(sym
) ||
847 Fortran::semantics::IsPointer(sym
))
849 // Polymorphic and unlimited polymorphic intent(out) dummy argument might need
850 // finalization at runtime.
851 if (Fortran::semantics::IsPolymorphic(sym
) ||
852 Fortran::semantics::IsUnlimitedPolymorphic(sym
))
854 // Intent(out) dummies must be finalized at runtime if their type has a
856 // Allocatable components of INTENT(OUT) dummies must be deallocated (9.7.3.2
857 // p6). Calling finalization runtime for this works even if the components
858 // have no final procedures.
859 return hasFinalization(sym
) || hasAllocatableDirectComponent(sym
);
862 /// Call default initialization runtime routine to initialize \p var.
863 static void finalizeAtRuntime(Fortran::lower::AbstractConverter
&converter
,
864 const Fortran::lower::pft::Variable
&var
,
865 Fortran::lower::SymMap
&symMap
) {
866 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
867 mlir::Location loc
= converter
.getCurrentLocation();
868 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
869 fir::ExtendedValue exv
= converter
.getSymbolExtendedValue(sym
, &symMap
);
870 if (Fortran::semantics::IsOptional(sym
)) {
871 // Only finalize if present.
872 auto isPresent
= builder
.create
<fir::IsPresentOp
>(loc
, builder
.getI1Type(),
874 builder
.genIfThen(loc
, isPresent
)
876 auto box
= builder
.createBox(loc
, exv
);
877 fir::runtime::genDerivedTypeDestroy(builder
, loc
, box
);
881 mlir::Value box
= builder
.createBox(loc
, exv
);
882 fir::runtime::genDerivedTypeDestroy(builder
, loc
, box
);
886 // Fortran 2018 - 9.7.3.2 point 6
887 // When a procedure is invoked, any allocated allocatable object that is an
888 // actual argument corresponding to an INTENT(OUT) allocatable dummy argument
889 // is deallocated; any allocated allocatable object that is a subobject of an
890 // actual argument corresponding to an INTENT(OUT) dummy argument is
892 // Note that allocatable components of non-ALLOCATABLE INTENT(OUT) dummy
893 // arguments are dealt with needDummyIntentoutFinalization (finalization runtime
894 // is called to reach the intended component deallocation effect).
895 static void deallocateIntentOut(Fortran::lower::AbstractConverter
&converter
,
896 const Fortran::lower::pft::Variable
&var
,
897 Fortran::lower::SymMap
&symMap
) {
898 if (!var
.hasSymbol())
901 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
902 if (Fortran::semantics::IsDummy(sym
) &&
903 Fortran::semantics::IsIntentOut(sym
) &&
904 Fortran::semantics::IsAllocatable(sym
)) {
905 fir::ExtendedValue extVal
= converter
.getSymbolExtendedValue(sym
, &symMap
);
906 if (auto mutBox
= extVal
.getBoxOf
<fir::MutableBoxValue
>()) {
907 // The dummy argument is not passed in the ENTRY so it should not be
909 if (mlir::Operation
*op
= mutBox
->getAddr().getDefiningOp()) {
910 if (auto declOp
= mlir::dyn_cast
<hlfir::DeclareOp
>(op
))
911 op
= declOp
.getMemref().getDefiningOp();
912 if (op
&& mlir::isa
<fir::AllocaOp
>(op
))
915 mlir::Location loc
= converter
.getCurrentLocation();
916 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
918 if (Fortran::semantics::IsOptional(sym
)) {
919 auto isPresent
= builder
.create
<fir::IsPresentOp
>(
920 loc
, builder
.getI1Type(), fir::getBase(extVal
));
921 builder
.genIfThen(loc
, isPresent
)
923 Fortran::lower::genDeallocateIfAllocated(converter
, *mutBox
, loc
);
927 Fortran::lower::genDeallocateIfAllocated(converter
, *mutBox
, loc
);
933 /// Instantiate a local variable. Precondition: Each variable will be visited
934 /// such that if its properties depend on other variables, the variables upon
935 /// which its properties depend will already have been visited.
936 static void instantiateLocal(Fortran::lower::AbstractConverter
&converter
,
937 const Fortran::lower::pft::Variable
&var
,
938 Fortran::lower::SymMap
&symMap
) {
939 assert(!var
.isAlias());
940 Fortran::lower::StatementContext stmtCtx
;
941 mapSymbolAttributes(converter
, var
, symMap
, stmtCtx
);
942 deallocateIntentOut(converter
, var
, symMap
);
943 if (needDummyIntentoutFinalization(var
))
944 finalizeAtRuntime(converter
, var
, symMap
);
945 if (mustBeDefaultInitializedAtRuntime(var
))
946 Fortran::lower::defaultInitializeAtRuntime(converter
, var
.getSymbol(),
948 if (Fortran::semantics::NeedCUDAAlloc(var
.getSymbol())) {
949 auto *builder
= &converter
.getFirOpBuilder();
950 mlir::Location loc
= converter
.getCurrentLocation();
951 fir::ExtendedValue exv
=
952 converter
.getSymbolExtendedValue(var
.getSymbol(), &symMap
);
953 auto *sym
= &var
.getSymbol();
954 converter
.getFctCtx().attachCleanup([builder
, loc
, exv
, sym
]() {
955 cuf::DataAttributeAttr dataAttr
=
956 Fortran::lower::translateSymbolCUFDataAttribute(builder
->getContext(),
958 builder
->create
<cuf::FreeOp
>(loc
, fir::getBase(exv
), dataAttr
);
961 if (std::optional
<VariableCleanUp
> cleanup
=
962 needDeallocationOrFinalization(var
)) {
963 auto *builder
= &converter
.getFirOpBuilder();
964 mlir::Location loc
= converter
.getCurrentLocation();
965 fir::ExtendedValue exv
=
966 converter
.getSymbolExtendedValue(var
.getSymbol(), &symMap
);
968 case VariableCleanUp::Finalize
:
969 converter
.getFctCtx().attachCleanup([builder
, loc
, exv
]() {
970 mlir::Value box
= builder
->createBox(loc
, exv
);
971 fir::runtime::genDerivedTypeDestroy(*builder
, loc
, box
);
974 case VariableCleanUp::Deallocate
:
975 auto *converterPtr
= &converter
;
976 auto *sym
= &var
.getSymbol();
977 converter
.getFctCtx().attachCleanup([converterPtr
, loc
, exv
, sym
]() {
978 const fir::MutableBoxValue
*mutableBox
=
979 exv
.getBoxOf
<fir::MutableBoxValue
>();
981 "trying to deallocate entity not lowered as allocatable");
982 Fortran::lower::genDeallocateIfAllocated(*converterPtr
, *mutableBox
,
990 //===----------------------------------------------------------------===//
991 // Aliased (EQUIVALENCE) variables instantiation
992 //===----------------------------------------------------------------===//
994 /// Insert \p aggregateStore instance into an AggregateStoreMap.
995 static void insertAggregateStore(Fortran::lower::AggregateStoreMap
&storeMap
,
996 const Fortran::lower::pft::Variable
&var
,
997 mlir::Value aggregateStore
) {
998 std::size_t off
= var
.getAggregateStore().getOffset();
999 Fortran::lower::AggregateStoreKey key
= {var
.getOwningScope(), off
};
1000 storeMap
[key
] = aggregateStore
;
1003 /// Retrieve the aggregate store instance of \p alias from an
1004 /// AggregateStoreMap.
1006 getAggregateStore(Fortran::lower::AggregateStoreMap
&storeMap
,
1007 const Fortran::lower::pft::Variable
&alias
) {
1008 Fortran::lower::AggregateStoreKey key
= {alias
.getOwningScope(),
1009 alias
.getAliasOffset()};
1010 auto iter
= storeMap
.find(key
);
1011 assert(iter
!= storeMap
.end());
1012 return iter
->second
;
1015 /// Build the name for the storage of a global equivalence.
1016 static std::string
mangleGlobalAggregateStore(
1017 Fortran::lower::AbstractConverter
&converter
,
1018 const Fortran::lower::pft::Variable::AggregateStore
&st
) {
1019 return converter
.mangleName(st
.getNamingSymbol());
1022 /// Build the type for the storage of an equivalence.
1024 getAggregateType(Fortran::lower::AbstractConverter
&converter
,
1025 const Fortran::lower::pft::Variable::AggregateStore
&st
) {
1026 if (const Fortran::semantics::Symbol
*initSym
= st
.getInitialValueSymbol())
1027 return converter
.genType(*initSym
);
1028 mlir::IntegerType byteTy
= converter
.getFirOpBuilder().getIntegerType(8);
1029 return fir::SequenceType::get(std::get
<1>(st
.interval
), byteTy
);
1032 /// Define a GlobalOp for the storage of a global equivalence described
1033 /// by \p aggregate. The global is named \p aggName and is created with
1034 /// the provided \p linkage.
1035 /// If any of the equivalence members are initialized, an initializer is
1036 /// created for the equivalence.
1037 /// This is to be used when lowering the scope that owns the equivalence
1038 /// (as opposed to simply using it through host or use association).
1039 /// This is not to be used for equivalence of common block members (they
1040 /// already have the common block GlobalOp for them, see defineCommonBlock).
1041 static fir::GlobalOp
defineGlobalAggregateStore(
1042 Fortran::lower::AbstractConverter
&converter
,
1043 const Fortran::lower::pft::Variable::AggregateStore
&aggregate
,
1044 llvm::StringRef aggName
, mlir::StringAttr linkage
) {
1045 assert(aggregate
.isGlobal() && "not a global interval");
1046 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1047 fir::GlobalOp global
= builder
.getNamedGlobal(aggName
);
1048 if (global
&& globalIsInitialized(global
))
1050 mlir::Location loc
= converter
.getCurrentLocation();
1051 mlir::Type aggTy
= getAggregateType(converter
, aggregate
);
1053 global
= builder
.createGlobal(loc
, aggTy
, aggName
, linkage
);
1055 if (const Fortran::semantics::Symbol
*initSym
=
1056 aggregate
.getInitialValueSymbol())
1057 if (const auto *objectDetails
=
1058 initSym
->detailsIf
<Fortran::semantics::ObjectEntityDetails
>())
1059 if (objectDetails
->init()) {
1060 Fortran::lower::createGlobalInitialization(
1061 builder
, global
, [&](fir::FirOpBuilder
&builder
) {
1062 Fortran::lower::StatementContext stmtCtx
;
1063 mlir::Value initVal
= fir::getBase(genInitializerExprValue(
1064 converter
, loc
, objectDetails
->init().value(), stmtCtx
));
1065 builder
.create
<fir::HasValueOp
>(loc
, initVal
);
1069 // Equivalence has no Fortran initial value. Create an undefined FIR initial
1070 // value to ensure this is consider an object definition in the IR regardless
1072 Fortran::lower::createGlobalInitialization(
1073 builder
, global
, [&](fir::FirOpBuilder
&builder
) {
1074 Fortran::lower::StatementContext stmtCtx
;
1075 mlir::Value initVal
= builder
.create
<fir::ZeroOp
>(loc
, aggTy
);
1076 builder
.create
<fir::HasValueOp
>(loc
, initVal
);
1081 /// Declare a GlobalOp for the storage of a global equivalence described
1082 /// by \p aggregate. The global is named \p aggName and is created with
1083 /// the provided \p linkage.
1084 /// No initializer is built for the created GlobalOp.
1085 /// This is to be used when lowering the scope that uses members of an
1086 /// equivalence it through host or use association.
1087 /// This is not to be used for equivalence of common block members (they
1088 /// already have the common block GlobalOp for them, see defineCommonBlock).
1089 static fir::GlobalOp
declareGlobalAggregateStore(
1090 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
1091 const Fortran::lower::pft::Variable::AggregateStore
&aggregate
,
1092 llvm::StringRef aggName
, mlir::StringAttr linkage
) {
1093 assert(aggregate
.isGlobal() && "not a global interval");
1094 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1095 if (fir::GlobalOp global
= builder
.getNamedGlobal(aggName
))
1097 mlir::Type aggTy
= getAggregateType(converter
, aggregate
);
1098 return builder
.createGlobal(loc
, aggTy
, aggName
, linkage
);
1101 /// This is an aggregate store for a set of EQUIVALENCED variables. Create the
1102 /// storage on the stack or global memory and add it to the map.
1104 instantiateAggregateStore(Fortran::lower::AbstractConverter
&converter
,
1105 const Fortran::lower::pft::Variable
&var
,
1106 Fortran::lower::AggregateStoreMap
&storeMap
) {
1107 assert(var
.isAggregateStore() && "not an interval");
1108 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1109 mlir::IntegerType i8Ty
= builder
.getIntegerType(8);
1110 mlir::Location loc
= converter
.getCurrentLocation();
1111 std::string aggName
=
1112 mangleGlobalAggregateStore(converter
, var
.getAggregateStore());
1113 if (var
.isGlobal()) {
1114 fir::GlobalOp global
;
1115 auto &aggregate
= var
.getAggregateStore();
1116 mlir::StringAttr linkage
= getLinkageAttribute(builder
, var
);
1117 if (var
.isModuleOrSubmoduleVariable()) {
1118 // A module global was or will be defined when lowering the module. Emit
1119 // only a declaration if the global does not exist at that point.
1120 global
= declareGlobalAggregateStore(converter
, loc
, aggregate
, aggName
,
1124 defineGlobalAggregateStore(converter
, aggregate
, aggName
, linkage
);
1126 auto addr
= builder
.create
<fir::AddrOfOp
>(loc
, global
.resultType(),
1127 global
.getSymbol());
1128 auto size
= std::get
<1>(var
.getInterval());
1129 fir::SequenceType::Shape
shape(1, size
);
1130 auto seqTy
= fir::SequenceType::get(shape
, i8Ty
);
1131 mlir::Type refTy
= builder
.getRefType(seqTy
);
1132 mlir::Value aggregateStore
= builder
.createConvert(loc
, refTy
, addr
);
1133 insertAggregateStore(storeMap
, var
, aggregateStore
);
1136 // This is a local aggregate, allocate an anonymous block of memory.
1137 auto size
= std::get
<1>(var
.getInterval());
1138 fir::SequenceType::Shape
shape(1, size
);
1139 auto seqTy
= fir::SequenceType::get(shape
, i8Ty
);
1141 builder
.allocateLocal(loc
, seqTy
, aggName
, "", std::nullopt
, std::nullopt
,
1143 insertAggregateStore(storeMap
, var
, local
);
1146 /// Cast an alias address (variable part of an equivalence) to fir.ptr so that
1147 /// the optimizer is conservative and avoids doing copy elision in assignment
1148 /// involving equivalenced variables.
1149 /// TODO: Represent the equivalence aliasing constraint in another way to avoid
1150 /// pessimizing array assignments involving equivalenced variables.
1151 static mlir::Value
castAliasToPointer(fir::FirOpBuilder
&builder
,
1152 mlir::Location loc
, mlir::Type aliasType
,
1153 mlir::Value aliasAddr
) {
1154 return builder
.createConvert(loc
, fir::PointerType::get(aliasType
),
1158 /// Instantiate a member of an equivalence. Compute its address in its
1159 /// aggregate storage and lower its attributes.
1160 static void instantiateAlias(Fortran::lower::AbstractConverter
&converter
,
1161 const Fortran::lower::pft::Variable
&var
,
1162 Fortran::lower::SymMap
&symMap
,
1163 Fortran::lower::AggregateStoreMap
&storeMap
) {
1164 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1165 assert(var
.isAlias());
1166 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
1167 const mlir::Location loc
= genLocation(converter
, sym
);
1168 mlir::IndexType idxTy
= builder
.getIndexType();
1169 mlir::IntegerType i8Ty
= builder
.getIntegerType(8);
1170 mlir::Type i8Ptr
= builder
.getRefType(i8Ty
);
1171 mlir::Type symType
= converter
.genType(sym
);
1172 std::size_t off
= sym
.GetUltimate().offset() - var
.getAliasOffset();
1173 mlir::Value storeAddr
= getAggregateStore(storeMap
, var
);
1174 mlir::Value offset
= builder
.createIntegerConstant(loc
, idxTy
, off
);
1175 mlir::Value bytePtr
= builder
.create
<fir::CoordinateOp
>(
1176 loc
, i8Ptr
, storeAddr
, mlir::ValueRange
{offset
});
1177 mlir::Value typedPtr
= castAliasToPointer(builder
, loc
, symType
, bytePtr
);
1178 Fortran::lower::StatementContext stmtCtx
;
1179 mapSymbolAttributes(converter
, var
, symMap
, stmtCtx
, typedPtr
);
1180 // Default initialization is possible for equivalence members: see
1181 // F2018 19.5.3.4. Note that if several equivalenced entities have
1182 // default initialization, they must have the same type, and the standard
1183 // allows the storage to be default initialized several times (this has
1184 // no consequences other than wasting some execution time). For now,
1185 // do not try optimizing this to single default initializations of
1186 // the equivalenced storages. Keep lowering simple.
1187 if (mustBeDefaultInitializedAtRuntime(var
))
1188 Fortran::lower::defaultInitializeAtRuntime(converter
, var
.getSymbol(),
1192 //===--------------------------------------------------------------===//
1193 // COMMON blocks instantiation
1194 //===--------------------------------------------------------------===//
1196 /// Does any member of the common block has an initializer ?
1198 commonBlockHasInit(const Fortran::semantics::MutableSymbolVector
&cmnBlkMems
) {
1199 for (const Fortran::semantics::MutableSymbolRef
&mem
: cmnBlkMems
) {
1200 if (const auto *memDet
=
1201 mem
->detailsIf
<Fortran::semantics::ObjectEntityDetails
>())
1208 /// Build a tuple type for a common block based on the common block
1209 /// members and the common block size.
1210 /// This type is only needed to build common block initializers where
1211 /// the initial value is the collection of the member initial values.
1212 static mlir::TupleType
getTypeOfCommonWithInit(
1213 Fortran::lower::AbstractConverter
&converter
,
1214 const Fortran::semantics::MutableSymbolVector
&cmnBlkMems
,
1215 std::size_t commonSize
) {
1216 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1217 llvm::SmallVector
<mlir::Type
> members
;
1218 std::size_t counter
= 0;
1219 for (const Fortran::semantics::MutableSymbolRef
&mem
: cmnBlkMems
) {
1220 if (const auto *memDet
=
1221 mem
->detailsIf
<Fortran::semantics::ObjectEntityDetails
>()) {
1222 if (mem
->offset() > counter
) {
1223 fir::SequenceType::Shape len
= {
1224 static_cast<fir::SequenceType::Extent
>(mem
->offset() - counter
)};
1225 mlir::IntegerType byteTy
= builder
.getIntegerType(8);
1226 auto memTy
= fir::SequenceType::get(len
, byteTy
);
1227 members
.push_back(memTy
);
1228 counter
= mem
->offset();
1230 if (memDet
->init()) {
1231 mlir::Type memTy
= converter
.genType(*mem
);
1232 members
.push_back(memTy
);
1233 counter
= mem
->offset() + mem
->size();
1237 if (counter
< commonSize
) {
1238 fir::SequenceType::Shape len
= {
1239 static_cast<fir::SequenceType::Extent
>(commonSize
- counter
)};
1240 mlir::IntegerType byteTy
= builder
.getIntegerType(8);
1241 auto memTy
= fir::SequenceType::get(len
, byteTy
);
1242 members
.push_back(memTy
);
1244 return mlir::TupleType::get(builder
.getContext(), members
);
1247 /// Common block members may have aliases. They are not in the common block
1248 /// member list from the symbol. We need to know about these aliases if they
1249 /// have initializer to generate the common initializer.
1250 /// This function takes care of adding aliases with initializer to the member
1252 static Fortran::semantics::MutableSymbolVector
1253 getCommonMembersWithInitAliases(const Fortran::semantics::Symbol
&common
) {
1254 const auto &commonDetails
=
1255 common
.get
<Fortran::semantics::CommonBlockDetails
>();
1256 auto members
= commonDetails
.objects();
1258 // The number and size of equivalence and common is expected to be small, so
1259 // no effort is given to optimize this loop of complexity equivalenced
1260 // common members * common members
1261 for (const Fortran::semantics::EquivalenceSet
&set
:
1262 common
.owner().equivalenceSets())
1263 for (const Fortran::semantics::EquivalenceObject
&obj
: set
) {
1264 if (!obj
.symbol
.test(Fortran::semantics::Symbol::Flag::CompilerCreated
)) {
1265 if (const auto &details
=
1267 .detailsIf
<Fortran::semantics::ObjectEntityDetails
>()) {
1268 const Fortran::semantics::Symbol
*com
=
1269 FindCommonBlockContaining(obj
.symbol
);
1270 if (!details
->init() || com
!= &common
)
1272 // This is an alias with an init that belongs to the list
1273 if (!llvm::is_contained(members
, obj
.symbol
))
1274 members
.emplace_back(obj
.symbol
);
1281 /// Return the fir::GlobalOp that was created of COMMON block \p common.
1282 /// It is an error if the fir::GlobalOp was not created before this is
1283 /// called (it cannot be created on the flight because it is not known here
1284 /// what mlir type the GlobalOp should have to satisfy all the
1285 /// appearances in the program).
1286 static fir::GlobalOp
1287 getCommonBlockGlobal(Fortran::lower::AbstractConverter
&converter
,
1288 const Fortran::semantics::Symbol
&common
) {
1289 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1290 std::string commonName
= converter
.mangleName(common
);
1291 fir::GlobalOp global
= builder
.getNamedGlobal(commonName
);
1292 // Common blocks are lowered before any subprograms to deal with common
1293 // whose size may not be the same in every subprograms.
1295 fir::emitFatalError(converter
.genLocation(common
.name()),
1296 "COMMON block was not lowered before its usage");
1300 /// Create the fir::GlobalOp for COMMON block \p common. If \p common has an
1301 /// initial value, it is not created yet. Instead, the common block list
1302 /// members is returned to later create the initial value in
1303 /// finalizeCommonBlockDefinition.
1304 static std::optional
<std::tuple
<
1305 fir::GlobalOp
, Fortran::semantics::MutableSymbolVector
, mlir::Location
>>
1306 declareCommonBlock(Fortran::lower::AbstractConverter
&converter
,
1307 const Fortran::semantics::Symbol
&common
,
1308 std::size_t commonSize
) {
1309 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1310 std::string commonName
= converter
.mangleName(common
);
1311 fir::GlobalOp global
= builder
.getNamedGlobal(commonName
);
1313 return std::nullopt
;
1314 Fortran::semantics::MutableSymbolVector cmnBlkMems
=
1315 getCommonMembersWithInitAliases(common
);
1316 mlir::Location loc
= converter
.genLocation(common
.name());
1317 mlir::StringAttr linkage
= builder
.createCommonLinkage();
1318 const auto *details
=
1319 common
.detailsIf
<Fortran::semantics::CommonBlockDetails
>();
1320 assert(details
&& "Expect CommonBlockDetails on the common symbol");
1321 if (!commonBlockHasInit(cmnBlkMems
)) {
1322 // A COMMON block sans initializers is initialized to zero.
1323 // mlir::Vector types must have a strictly positive size, so at least
1324 // temporarily, force a zero size COMMON block to have one byte.
1326 static_cast<fir::SequenceType::Extent
>(commonSize
> 0 ? commonSize
: 1);
1327 fir::SequenceType::Shape shape
= {sz
};
1328 mlir::IntegerType i8Ty
= builder
.getIntegerType(8);
1329 auto commonTy
= fir::SequenceType::get(shape
, i8Ty
);
1330 auto vecTy
= mlir::VectorType::get(sz
, i8Ty
);
1331 mlir::Attribute zero
= builder
.getIntegerAttr(i8Ty
, 0);
1332 auto init
= mlir::DenseElementsAttr::get(vecTy
, llvm::ArrayRef(zero
));
1333 global
= builder
.createGlobal(loc
, commonTy
, commonName
, linkage
, init
);
1334 global
.setAlignment(details
->alignment());
1335 // No need to add any initial value later.
1336 return std::nullopt
;
1338 // COMMON block with initializer (note that initialized blank common are
1339 // accepted as an extension by semantics). Sort members by offset before
1340 // generating the type and initializer.
1341 std::sort(cmnBlkMems
.begin(), cmnBlkMems
.end(),
1342 [](auto &s1
, auto &s2
) { return s1
->offset() < s2
->offset(); });
1343 mlir::TupleType commonTy
=
1344 getTypeOfCommonWithInit(converter
, cmnBlkMems
, commonSize
);
1345 // Create the global object, the initial value will be added later.
1346 global
= builder
.createGlobal(loc
, commonTy
, commonName
);
1347 global
.setAlignment(details
->alignment());
1348 return std::make_tuple(global
, std::move(cmnBlkMems
), loc
);
1351 /// Add initial value to a COMMON block fir::GlobalOp \p global given the list
1352 /// \p cmnBlkMems of the common block member symbols that contains symbols with
1353 /// an initial value.
1354 static void finalizeCommonBlockDefinition(
1355 mlir::Location loc
, Fortran::lower::AbstractConverter
&converter
,
1356 fir::GlobalOp global
,
1357 const Fortran::semantics::MutableSymbolVector
&cmnBlkMems
) {
1358 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1359 mlir::TupleType commonTy
= mlir::cast
<mlir::TupleType
>(global
.getType());
1360 auto initFunc
= [&](fir::FirOpBuilder
&builder
) {
1361 mlir::IndexType idxTy
= builder
.getIndexType();
1362 mlir::Value cb
= builder
.create
<fir::ZeroOp
>(loc
, commonTy
);
1363 unsigned tupIdx
= 0;
1364 std::size_t offset
= 0;
1365 LLVM_DEBUG(llvm::dbgs() << "block {\n");
1366 for (const Fortran::semantics::MutableSymbolRef
&mem
: cmnBlkMems
) {
1367 if (const auto *memDet
=
1368 mem
->detailsIf
<Fortran::semantics::ObjectEntityDetails
>()) {
1369 if (mem
->offset() > offset
) {
1371 offset
= mem
->offset();
1373 if (memDet
->init()) {
1374 LLVM_DEBUG(llvm::dbgs()
1375 << "offset: " << mem
->offset() << " is " << *mem
<< '\n');
1376 Fortran::lower::StatementContext stmtCtx
;
1377 auto initExpr
= memDet
->init().value();
1378 fir::ExtendedValue initVal
=
1379 Fortran::semantics::IsPointer(*mem
)
1380 ? Fortran::lower::genInitialDataTarget(
1381 converter
, loc
, converter
.genType(*mem
), initExpr
)
1382 : genInitializerExprValue(converter
, loc
, initExpr
, stmtCtx
);
1383 mlir::IntegerAttr offVal
= builder
.getIntegerAttr(idxTy
, tupIdx
);
1384 mlir::Value castVal
= builder
.createConvert(
1385 loc
, commonTy
.getType(tupIdx
), fir::getBase(initVal
));
1386 cb
= builder
.create
<fir::InsertValueOp
>(loc
, commonTy
, cb
, castVal
,
1387 builder
.getArrayAttr(offVal
));
1389 offset
= mem
->offset() + mem
->size();
1393 LLVM_DEBUG(llvm::dbgs() << "}\n");
1394 builder
.create
<fir::HasValueOp
>(loc
, cb
);
1396 Fortran::lower::createGlobalInitialization(builder
, global
, initFunc
);
1399 void Fortran::lower::defineCommonBlocks(
1400 Fortran::lower::AbstractConverter
&converter
,
1401 const Fortran::semantics::CommonBlockList
&commonBlocks
) {
1402 // Common blocks may depend on another common block address (if they contain
1403 // pointers with initial targets). To cover this case, create all common block
1404 // fir::Global before creating the initial values (if any).
1405 std::vector
<std::tuple
<fir::GlobalOp
, Fortran::semantics::MutableSymbolVector
,
1407 delayedInitializations
;
1408 for (const auto &[common
, size
] : commonBlocks
)
1409 if (auto delayedInit
= declareCommonBlock(converter
, common
, size
))
1410 delayedInitializations
.emplace_back(std::move(*delayedInit
));
1411 for (auto &[global
, cmnBlkMems
, loc
] : delayedInitializations
)
1412 finalizeCommonBlockDefinition(loc
, converter
, global
, cmnBlkMems
);
1415 mlir::Value
Fortran::lower::genCommonBlockMember(
1416 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
1417 const Fortran::semantics::Symbol
&sym
, mlir::Value commonValue
) {
1418 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1420 std::size_t byteOffset
= sym
.GetUltimate().offset();
1421 mlir::IntegerType i8Ty
= builder
.getIntegerType(8);
1422 mlir::Type i8Ptr
= builder
.getRefType(i8Ty
);
1423 mlir::Type seqTy
= builder
.getRefType(builder
.getVarLenSeqTy(i8Ty
));
1424 mlir::Value base
= builder
.createConvert(loc
, seqTy
, commonValue
);
1427 builder
.createIntegerConstant(loc
, builder
.getIndexType(), byteOffset
);
1428 mlir::Value varAddr
= builder
.create
<fir::CoordinateOp
>(
1429 loc
, i8Ptr
, base
, mlir::ValueRange
{offs
});
1430 mlir::Type symType
= converter
.genType(sym
);
1432 return Fortran::semantics::FindEquivalenceSet(sym
) != nullptr
1433 ? castAliasToPointer(builder
, loc
, symType
, varAddr
)
1434 : builder
.createConvert(loc
, builder
.getRefType(symType
), varAddr
);
1437 /// The COMMON block is a global structure. `var` will be at some offset
1438 /// within the COMMON block. Adds the address of `var` (COMMON + offset) to
1440 static void instantiateCommon(Fortran::lower::AbstractConverter
&converter
,
1441 const Fortran::semantics::Symbol
&common
,
1442 const Fortran::lower::pft::Variable
&var
,
1443 Fortran::lower::SymMap
&symMap
) {
1444 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1445 const Fortran::semantics::Symbol
&varSym
= var
.getSymbol();
1446 mlir::Location loc
= converter
.genLocation(varSym
.name());
1448 mlir::Value commonAddr
;
1449 if (Fortran::lower::SymbolBox symBox
= symMap
.lookupSymbol(common
))
1450 commonAddr
= symBox
.getAddr();
1452 // introduce a local AddrOf and add it to the map
1453 fir::GlobalOp global
= getCommonBlockGlobal(converter
, common
);
1454 commonAddr
= builder
.create
<fir::AddrOfOp
>(loc
, global
.resultType(),
1455 global
.getSymbol());
1457 symMap
.addSymbol(common
, commonAddr
);
1460 mlir::Value local
= genCommonBlockMember(converter
, loc
, varSym
, commonAddr
);
1461 Fortran::lower::StatementContext stmtCtx
;
1462 mapSymbolAttributes(converter
, var
, symMap
, stmtCtx
, local
);
1465 //===--------------------------------------------------------------===//
1466 // Lower Variables specification expressions and attributes
1467 //===--------------------------------------------------------------===//
1469 /// Helper to decide if a dummy argument must be tracked in an BoxValue.
1470 static bool lowerToBoxValue(const Fortran::semantics::Symbol
&sym
,
1471 mlir::Value dummyArg
,
1472 Fortran::lower::AbstractConverter
&converter
) {
1473 // Only dummy arguments coming as fir.box can be tracked in an BoxValue.
1474 if (!dummyArg
|| !mlir::isa
<fir::BaseBoxType
>(dummyArg
.getType()))
1476 // Non contiguous arrays must be tracked in an BoxValue.
1477 if (sym
.Rank() > 0 && !Fortran::evaluate::IsSimplyContiguous(
1478 sym
, converter
.getFoldingContext()))
1480 // Assumed rank and optional fir.box cannot yet be read while lowering the
1482 if (Fortran::evaluate::IsAssumedRank(sym
) ||
1483 Fortran::semantics::IsOptional(sym
))
1485 // Polymorphic entity should be tracked through a fir.box that has the
1486 // dynamic type info.
1487 if (const Fortran::semantics::DeclTypeSpec
*type
= sym
.GetType())
1488 if (type
->IsPolymorphic())
1493 /// Compute extent from lower and upper bound.
1494 static mlir::Value
computeExtent(fir::FirOpBuilder
&builder
, mlir::Location loc
,
1495 mlir::Value lb
, mlir::Value ub
) {
1496 mlir::IndexType idxTy
= builder
.getIndexType();
1497 // Let the folder deal with the common `ub - <const> + 1` case.
1498 auto diff
= builder
.create
<mlir::arith::SubIOp
>(loc
, idxTy
, ub
, lb
);
1499 mlir::Value one
= builder
.createIntegerConstant(loc
, idxTy
, 1);
1500 auto rawExtent
= builder
.create
<mlir::arith::AddIOp
>(loc
, idxTy
, diff
, one
);
1501 return fir::factory::genMaxWithZero(builder
, loc
, rawExtent
);
1504 /// Lower explicit lower bounds into \p result. Does nothing if this is not an
1505 /// array, or if the lower bounds are deferred, or all implicit or one.
1506 static void lowerExplicitLowerBounds(
1507 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
1508 const Fortran::lower::BoxAnalyzer
&box
,
1509 llvm::SmallVectorImpl
<mlir::Value
> &result
, Fortran::lower::SymMap
&symMap
,
1510 Fortran::lower::StatementContext
&stmtCtx
) {
1511 if (!box
.isArray() || box
.lboundIsAllOnes())
1513 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1514 mlir::IndexType idxTy
= builder
.getIndexType();
1515 if (box
.isStaticArray()) {
1516 for (int64_t lb
: box
.staticLBound())
1517 result
.emplace_back(builder
.createIntegerConstant(loc
, idxTy
, lb
));
1520 for (const Fortran::semantics::ShapeSpec
*spec
: box
.dynamicBound()) {
1521 if (auto low
= spec
->lbound().GetExplicit()) {
1522 auto expr
= Fortran::lower::SomeExpr
{*low
};
1523 mlir::Value lb
= builder
.createConvert(
1524 loc
, idxTy
, genScalarValue(converter
, loc
, expr
, symMap
, stmtCtx
));
1525 result
.emplace_back(lb
);
1528 assert(result
.empty() || result
.size() == box
.dynamicBound().size());
1531 /// Return -1 for the last dimension extent/upper bound of assumed-size arrays.
1532 /// This value is required to fulfill the requirements for assumed-rank
1533 /// associated with assumed-size (see for instance UBOUND in 16.9.196, and
1534 /// CFI_desc_t requirements in 18.5.3 point 5.).
1535 static mlir::Value
getAssumedSizeExtent(mlir::Location loc
,
1536 fir::FirOpBuilder
&builder
) {
1537 return builder
.createMinusOneInteger(loc
, builder
.getIndexType());
1540 /// Lower explicit extents into \p result if this is an explicit-shape or
1541 /// assumed-size array. Does nothing if this is not an explicit-shape or
1542 /// assumed-size array.
1544 lowerExplicitExtents(Fortran::lower::AbstractConverter
&converter
,
1545 mlir::Location loc
, const Fortran::lower::BoxAnalyzer
&box
,
1546 llvm::SmallVectorImpl
<mlir::Value
> &lowerBounds
,
1547 llvm::SmallVectorImpl
<mlir::Value
> &result
,
1548 Fortran::lower::SymMap
&symMap
,
1549 Fortran::lower::StatementContext
&stmtCtx
) {
1552 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1553 mlir::IndexType idxTy
= builder
.getIndexType();
1554 if (box
.isStaticArray()) {
1555 for (int64_t extent
: box
.staticShape())
1556 result
.emplace_back(builder
.createIntegerConstant(loc
, idxTy
, extent
));
1559 for (const auto &spec
: llvm::enumerate(box
.dynamicBound())) {
1560 if (auto up
= spec
.value()->ubound().GetExplicit()) {
1561 auto expr
= Fortran::lower::SomeExpr
{*up
};
1562 mlir::Value ub
= builder
.createConvert(
1563 loc
, idxTy
, genScalarValue(converter
, loc
, expr
, symMap
, stmtCtx
));
1564 if (lowerBounds
.empty())
1565 result
.emplace_back(fir::factory::genMaxWithZero(builder
, loc
, ub
));
1567 result
.emplace_back(
1568 computeExtent(builder
, loc
, lowerBounds
[spec
.index()], ub
));
1569 } else if (spec
.value()->ubound().isStar()) {
1570 result
.emplace_back(getAssumedSizeExtent(loc
, builder
));
1573 assert(result
.empty() || result
.size() == box
.dynamicBound().size());
1576 /// Lower explicit character length if any. Return empty mlir::Value if no
1577 /// explicit length.
1579 lowerExplicitCharLen(Fortran::lower::AbstractConverter
&converter
,
1580 mlir::Location loc
, const Fortran::lower::BoxAnalyzer
&box
,
1581 Fortran::lower::SymMap
&symMap
,
1582 Fortran::lower::StatementContext
&stmtCtx
) {
1584 return mlir::Value
{};
1585 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1586 mlir::Type lenTy
= builder
.getCharacterLengthType();
1587 if (std::optional
<int64_t> len
= box
.getCharLenConst())
1588 return builder
.createIntegerConstant(loc
, lenTy
, *len
);
1589 if (std::optional
<Fortran::lower::SomeExpr
> lenExpr
= box
.getCharLenExpr())
1590 // If the length expression is negative, the length is zero. See F2018
1592 return fir::factory::genMaxWithZero(
1594 genScalarValue(converter
, loc
, *lenExpr
, symMap
, stmtCtx
));
1595 return mlir::Value
{};
1598 /// Assumed size arrays last extent is -1 in the front end.
1599 static mlir::Value
genExtentValue(fir::FirOpBuilder
&builder
,
1600 mlir::Location loc
, mlir::Type idxTy
,
1601 long frontEndExtent
) {
1602 if (frontEndExtent
>= 0)
1603 return builder
.createIntegerConstant(loc
, idxTy
, frontEndExtent
);
1604 return getAssumedSizeExtent(loc
, builder
);
1607 /// If a symbol is an array, it may have been declared with unknown extent
1608 /// parameters (e.g., `*`), but if it has an initial value then the actual size
1609 /// may be available from the initial array value's type.
1610 inline static llvm::SmallVector
<std::int64_t>
1611 recoverShapeVector(llvm::ArrayRef
<std::int64_t> shapeVec
, mlir::Value initVal
) {
1612 llvm::SmallVector
<std::int64_t> result
;
1614 if (auto seqTy
= fir::unwrapUntilSeqType(initVal
.getType())) {
1615 for (auto [fst
, snd
] : llvm::zip(shapeVec
, seqTy
.getShape()))
1616 result
.push_back(fst
== fir::SequenceType::getUnknownExtent() ? snd
1621 result
.assign(shapeVec
.begin(), shapeVec
.end());
1625 fir::FortranVariableFlagsAttr
Fortran::lower::translateSymbolAttributes(
1626 mlir::MLIRContext
*mlirContext
, const Fortran::semantics::Symbol
&sym
,
1627 fir::FortranVariableFlagsEnum extraFlags
) {
1628 fir::FortranVariableFlagsEnum flags
= extraFlags
;
1629 if (sym
.test(Fortran::semantics::Symbol::Flag::CrayPointee
)) {
1630 // CrayPointee are represented as pointers.
1631 flags
= flags
| fir::FortranVariableFlagsEnum::pointer
;
1632 return fir::FortranVariableFlagsAttr::get(mlirContext
, flags
);
1634 const auto &attrs
= sym
.attrs();
1635 if (attrs
.test(Fortran::semantics::Attr::ALLOCATABLE
))
1636 flags
= flags
| fir::FortranVariableFlagsEnum::allocatable
;
1637 if (attrs
.test(Fortran::semantics::Attr::ASYNCHRONOUS
))
1638 flags
= flags
| fir::FortranVariableFlagsEnum::asynchronous
;
1639 if (attrs
.test(Fortran::semantics::Attr::BIND_C
))
1640 flags
= flags
| fir::FortranVariableFlagsEnum::bind_c
;
1641 if (attrs
.test(Fortran::semantics::Attr::CONTIGUOUS
))
1642 flags
= flags
| fir::FortranVariableFlagsEnum::contiguous
;
1643 if (attrs
.test(Fortran::semantics::Attr::INTENT_IN
))
1644 flags
= flags
| fir::FortranVariableFlagsEnum::intent_in
;
1645 if (attrs
.test(Fortran::semantics::Attr::INTENT_INOUT
))
1646 flags
= flags
| fir::FortranVariableFlagsEnum::intent_inout
;
1647 if (attrs
.test(Fortran::semantics::Attr::INTENT_OUT
))
1648 flags
= flags
| fir::FortranVariableFlagsEnum::intent_out
;
1649 if (attrs
.test(Fortran::semantics::Attr::OPTIONAL
))
1650 flags
= flags
| fir::FortranVariableFlagsEnum::optional
;
1651 if (attrs
.test(Fortran::semantics::Attr::PARAMETER
))
1652 flags
= flags
| fir::FortranVariableFlagsEnum::parameter
;
1653 if (attrs
.test(Fortran::semantics::Attr::POINTER
))
1654 flags
= flags
| fir::FortranVariableFlagsEnum::pointer
;
1655 if (attrs
.test(Fortran::semantics::Attr::TARGET
))
1656 flags
= flags
| fir::FortranVariableFlagsEnum::target
;
1657 if (attrs
.test(Fortran::semantics::Attr::VALUE
))
1658 flags
= flags
| fir::FortranVariableFlagsEnum::value
;
1659 if (attrs
.test(Fortran::semantics::Attr::VOLATILE
))
1660 flags
= flags
| fir::FortranVariableFlagsEnum::fortran_volatile
;
1661 if (flags
== fir::FortranVariableFlagsEnum::None
)
1663 return fir::FortranVariableFlagsAttr::get(mlirContext
, flags
);
1666 cuf::DataAttributeAttr
Fortran::lower::translateSymbolCUFDataAttribute(
1667 mlir::MLIRContext
*mlirContext
, const Fortran::semantics::Symbol
&sym
) {
1668 std::optional
<Fortran::common::CUDADataAttr
> cudaAttr
=
1669 Fortran::semantics::GetCUDADataAttr(&sym
.GetUltimate());
1670 return cuf::getDataAttribute(mlirContext
, cudaAttr
);
1673 /// Map a symbol to its FIR address and evaluated specification expressions.
1674 /// Not for symbols lowered to fir.box.
1675 /// Will optionally create fir.declare.
1676 static void genDeclareSymbol(Fortran::lower::AbstractConverter
&converter
,
1677 Fortran::lower::SymMap
&symMap
,
1678 const Fortran::semantics::Symbol
&sym
,
1679 mlir::Value base
, mlir::Value len
= {},
1680 llvm::ArrayRef
<mlir::Value
> shape
= std::nullopt
,
1681 llvm::ArrayRef
<mlir::Value
> lbounds
= std::nullopt
,
1682 bool force
= false) {
1683 // In HLFIR, procedure dummy symbols are not added with an hlfir.declare
1684 // because they are "values", and hlfir.declare is intended for variables. It
1685 // would add too much complexity to hlfir.declare to support this case, and
1686 // this would bring very little (the only point being debug info, that are not
1687 // yet emitted) since alias analysis is meaningless for those.
1688 // Commonblock names are not variables, but in some lowerings (like OpenMP) it
1689 // is useful to maintain the address of the commonblock in an MLIR value and
1690 // query it. hlfir.declare need not be created for these.
1691 if (converter
.getLoweringOptions().getLowerToHighLevelFIR() &&
1692 (!Fortran::semantics::IsProcedure(sym
) ||
1693 Fortran::semantics::IsPointer(sym
)) &&
1694 !sym
.detailsIf
<Fortran::semantics::CommonBlockDetails
>()) {
1695 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1696 const mlir::Location loc
= genLocation(converter
, sym
);
1697 mlir::Value shapeOrShift
;
1698 if (!shape
.empty() && !lbounds
.empty())
1699 shapeOrShift
= builder
.genShape(loc
, lbounds
, shape
);
1700 else if (!shape
.empty())
1701 shapeOrShift
= builder
.genShape(loc
, shape
);
1702 else if (!lbounds
.empty())
1703 shapeOrShift
= builder
.genShift(loc
, lbounds
);
1704 llvm::SmallVector
<mlir::Value
> lenParams
;
1706 lenParams
.emplace_back(len
);
1707 auto name
= converter
.mangleName(sym
);
1708 fir::FortranVariableFlagsAttr attributes
=
1709 Fortran::lower::translateSymbolAttributes(builder
.getContext(), sym
);
1710 cuf::DataAttributeAttr dataAttr
=
1711 Fortran::lower::translateSymbolCUFDataAttribute(builder
.getContext(),
1714 if (sym
.test(Fortran::semantics::Symbol::Flag::CrayPointee
)) {
1715 mlir::Type ptrBoxType
=
1716 Fortran::lower::getCrayPointeeBoxType(base
.getType());
1717 mlir::Value boxAlloc
= builder
.createTemporary(
1719 /*name=*/{}, /*shape=*/{}, /*lenParams=*/{}, /*attrs=*/{},
1720 Fortran::semantics::GetCUDADataAttr(&sym
.GetUltimate()));
1722 // Declare a local pointer variable.
1723 auto newBase
= builder
.create
<hlfir::DeclareOp
>(
1724 loc
, boxAlloc
, name
, /*shape=*/nullptr, lenParams
,
1725 /*dummy_scope=*/nullptr, attributes
);
1726 mlir::Value nullAddr
= builder
.createNullConstant(
1727 loc
, llvm::cast
<fir::BaseBoxType
>(ptrBoxType
).getEleTy());
1729 // If the element type is known-length character, then
1730 // EmboxOp does not need the length parameters.
1731 if (auto charType
= mlir::dyn_cast
<fir::CharacterType
>(
1732 hlfir::getFortranElementType(base
.getType())))
1733 if (!charType
.hasDynamicLen())
1736 // Inherit the shape (and maybe length parameters) from the pointee
1738 mlir::Value initVal
=
1739 builder
.create
<fir::EmboxOp
>(loc
, ptrBoxType
, nullAddr
, shapeOrShift
,
1740 /*slice=*/nullptr, lenParams
);
1741 builder
.create
<fir::StoreOp
>(loc
, initVal
, newBase
.getBase());
1743 // Any reference to the pointee is going to be using the pointer
1744 // box from now on. The base_addr of the descriptor must be updated
1745 // to hold the value of the Cray pointer at the point of the pointee
1747 // Note that the same Cray pointer may be associated with
1748 // multiple pointees and each of them has its own descriptor.
1749 symMap
.addVariableDefinition(sym
, newBase
, force
);
1752 mlir::Value dummyScope
;
1753 if (converter
.isRegisteredDummySymbol(sym
))
1754 dummyScope
= converter
.dummyArgsScopeValue();
1755 auto newBase
= builder
.create
<hlfir::DeclareOp
>(
1756 loc
, base
, name
, shapeOrShift
, lenParams
, dummyScope
, attributes
,
1758 symMap
.addVariableDefinition(sym
, newBase
, force
);
1763 if (!shape
.empty()) {
1764 if (!lbounds
.empty())
1765 symMap
.addCharSymbolWithBounds(sym
, base
, len
, shape
, lbounds
, force
);
1767 symMap
.addCharSymbolWithShape(sym
, base
, len
, shape
, force
);
1769 symMap
.addCharSymbol(sym
, base
, len
, force
);
1772 if (!shape
.empty()) {
1773 if (!lbounds
.empty())
1774 symMap
.addSymbolWithBounds(sym
, base
, shape
, lbounds
, force
);
1776 symMap
.addSymbolWithShape(sym
, base
, shape
, force
);
1778 symMap
.addSymbol(sym
, base
, force
);
1783 /// Map a symbol to its FIR address and evaluated specification expressions
1784 /// provided as a fir::ExtendedValue. Will optionally create fir.declare.
1785 void Fortran::lower::genDeclareSymbol(
1786 Fortran::lower::AbstractConverter
&converter
,
1787 Fortran::lower::SymMap
&symMap
, const Fortran::semantics::Symbol
&sym
,
1788 const fir::ExtendedValue
&exv
, fir::FortranVariableFlagsEnum extraFlags
,
1790 if (converter
.getLoweringOptions().getLowerToHighLevelFIR() &&
1791 (!Fortran::semantics::IsProcedure(sym
) ||
1792 Fortran::semantics::IsPointer(sym
)) &&
1793 !sym
.detailsIf
<Fortran::semantics::CommonBlockDetails
>()) {
1794 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1795 const mlir::Location loc
= genLocation(converter
, sym
);
1796 // FIXME: Using the ultimate symbol for translating symbol attributes will
1797 // lead to situations where the VOLATILE/ASYNCHRONOUS attributes are not
1798 // propagated to the hlfir.declare (these attributes can be added when
1799 // using module variables).
1800 fir::FortranVariableFlagsAttr attributes
=
1801 Fortran::lower::translateSymbolAttributes(
1802 builder
.getContext(), sym
.GetUltimate(), extraFlags
);
1803 cuf::DataAttributeAttr dataAttr
=
1804 Fortran::lower::translateSymbolCUFDataAttribute(builder
.getContext(),
1806 auto name
= converter
.mangleName(sym
);
1807 mlir::Value dummyScope
;
1808 if (converter
.isRegisteredDummySymbol(sym
))
1809 dummyScope
= converter
.dummyArgsScopeValue();
1810 hlfir::EntityWithAttributes declare
= hlfir::genDeclare(
1811 loc
, builder
, exv
, name
, attributes
, dummyScope
, dataAttr
);
1812 symMap
.addVariableDefinition(sym
, declare
.getIfVariableInterface(), force
);
1815 symMap
.addSymbol(sym
, exv
, force
);
1818 /// Map an allocatable or pointer symbol to its FIR address and evaluated
1819 /// specification expressions. Will optionally create fir.declare.
1821 genAllocatableOrPointerDeclare(Fortran::lower::AbstractConverter
&converter
,
1822 Fortran::lower::SymMap
&symMap
,
1823 const Fortran::semantics::Symbol
&sym
,
1824 fir::MutableBoxValue box
, bool force
= false) {
1825 if (!converter
.getLoweringOptions().getLowerToHighLevelFIR()) {
1826 symMap
.addAllocatableOrPointer(sym
, box
, force
);
1829 assert(!box
.isDescribedByVariables() &&
1830 "HLFIR alloctables/pointers must be fir.ref<fir.box>");
1831 mlir::Value base
= box
.getAddr();
1832 mlir::Value explictLength
;
1833 if (box
.hasNonDeferredLenParams()) {
1834 if (!box
.isCharacter())
1835 TODO(genLocation(converter
, sym
),
1836 "Pointer or Allocatable parametrized derived type");
1837 explictLength
= box
.nonDeferredLenParams()[0];
1839 genDeclareSymbol(converter
, symMap
, sym
, base
, explictLength
,
1840 /*shape=*/std::nullopt
,
1841 /*lbounds=*/std::nullopt
, force
);
1844 /// Map a procedure pointer
1845 static void genProcPointer(Fortran::lower::AbstractConverter
&converter
,
1846 Fortran::lower::SymMap
&symMap
,
1847 const Fortran::semantics::Symbol
&sym
,
1848 mlir::Value addr
, bool force
= false) {
1849 genDeclareSymbol(converter
, symMap
, sym
, addr
, mlir::Value
{},
1850 /*shape=*/std::nullopt
,
1851 /*lbounds=*/std::nullopt
, force
);
1854 /// Map a symbol represented with a runtime descriptor to its FIR fir.box and
1855 /// evaluated specification expressions. Will optionally create fir.declare.
1856 static void genBoxDeclare(Fortran::lower::AbstractConverter
&converter
,
1857 Fortran::lower::SymMap
&symMap
,
1858 const Fortran::semantics::Symbol
&sym
,
1859 mlir::Value box
, llvm::ArrayRef
<mlir::Value
> lbounds
,
1860 llvm::ArrayRef
<mlir::Value
> explicitParams
,
1861 llvm::ArrayRef
<mlir::Value
> explicitExtents
,
1862 bool replace
= false) {
1863 if (converter
.getLoweringOptions().getLowerToHighLevelFIR()) {
1864 fir::BoxValue boxValue
{box
, lbounds
, explicitParams
, explicitExtents
};
1865 Fortran::lower::genDeclareSymbol(
1866 converter
, symMap
, sym
, std::move(boxValue
),
1867 fir::FortranVariableFlagsEnum::None
, replace
);
1870 symMap
.addBoxSymbol(sym
, box
, lbounds
, explicitParams
, explicitExtents
,
1874 static unsigned getAllocatorIdx(const Fortran::semantics::Symbol
&sym
) {
1875 std::optional
<Fortran::common::CUDADataAttr
> cudaAttr
=
1876 Fortran::semantics::GetCUDADataAttr(&sym
.GetUltimate());
1878 if (*cudaAttr
== Fortran::common::CUDADataAttr::Pinned
)
1879 return kPinnedAllocatorPos
;
1880 if (*cudaAttr
== Fortran::common::CUDADataAttr::Device
)
1881 return kDeviceAllocatorPos
;
1882 if (*cudaAttr
== Fortran::common::CUDADataAttr::Managed
)
1883 return kManagedAllocatorPos
;
1884 if (*cudaAttr
== Fortran::common::CUDADataAttr::Unified
)
1885 return kUnifiedAllocatorPos
;
1887 return kDefaultAllocator
;
1890 /// Lower specification expressions and attributes of variable \p var and
1891 /// add it to the symbol map. For a global or an alias, the address must be
1892 /// pre-computed and provided in \p preAlloc. A dummy argument for the current
1893 /// entry point has already been mapped to an mlir block argument in
1894 /// mapDummiesAndResults. Its mapping may be updated here.
1895 void Fortran::lower::mapSymbolAttributes(
1896 AbstractConverter
&converter
, const Fortran::lower::pft::Variable
&var
,
1897 Fortran::lower::SymMap
&symMap
, Fortran::lower::StatementContext
&stmtCtx
,
1898 mlir::Value preAlloc
) {
1899 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
1900 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
1901 const mlir::Location loc
= genLocation(converter
, sym
);
1902 mlir::IndexType idxTy
= builder
.getIndexType();
1903 const bool isDeclaredDummy
= Fortran::semantics::IsDummy(sym
);
1904 // An active dummy from the current entry point.
1905 const bool isDummy
= isDeclaredDummy
&& symMap
.lookupSymbol(sym
).getAddr();
1906 // An unused dummy from another entry point.
1907 const bool isUnusedEntryDummy
= isDeclaredDummy
&& !isDummy
;
1908 const bool isResult
= Fortran::semantics::IsFunctionResult(sym
);
1909 const bool replace
= isDummy
|| isResult
;
1910 fir::factory::CharacterExprHelper charHelp
{builder
, loc
};
1912 if (Fortran::semantics::IsProcedure(sym
)) {
1913 if (isUnusedEntryDummy
) {
1914 // Additional discussion below.
1915 mlir::Type dummyProcType
=
1916 Fortran::lower::getDummyProcedureType(sym
, converter
);
1917 mlir::Value undefOp
= builder
.create
<fir::UndefOp
>(loc
, dummyProcType
);
1919 Fortran::lower::genDeclareSymbol(converter
, symMap
, sym
, undefOp
);
1922 // Procedure pointer.
1923 if (Fortran::semantics::IsPointer(sym
)) {
1925 mlir::Value boxAlloc
= preAlloc
;
1926 // dummy or passed result
1928 if (Fortran::lower::SymbolBox symbox
= symMap
.lookupSymbol(sym
))
1929 boxAlloc
= symbox
.getAddr();
1932 boxAlloc
= createNewLocal(converter
, loc
, var
, preAlloc
);
1933 genProcPointer(converter
, symMap
, sym
, boxAlloc
, replace
);
1938 const bool isAssumedRank
= Fortran::evaluate::IsAssumedRank(sym
);
1939 if (isAssumedRank
&& !allowAssumedRank
)
1940 TODO(loc
, "assumed-rank variable in procedure implemented in Fortran");
1942 Fortran::lower::BoxAnalyzer ba
;
1945 // First deal with pointers and allocatables, because their handling here
1946 // is the same regardless of their rank.
1947 if (Fortran::semantics::IsAllocatableOrPointer(sym
)) {
1948 // Get address of fir.box describing the entity.
1950 mlir::Value boxAlloc
= preAlloc
;
1951 // dummy or passed result
1953 if (Fortran::lower::SymbolBox symbox
= symMap
.lookupSymbol(sym
))
1954 boxAlloc
= symbox
.getAddr();
1955 assert((boxAlloc
|| !isAssumedRank
) && "assumed-ranks cannot be local");
1958 boxAlloc
= createNewLocal(converter
, loc
, var
, preAlloc
);
1959 // Lower non deferred parameters.
1960 llvm::SmallVector
<mlir::Value
> nonDeferredLenParams
;
1962 if (mlir::Value len
=
1963 lowerExplicitCharLen(converter
, loc
, ba
, symMap
, stmtCtx
))
1964 nonDeferredLenParams
.push_back(len
);
1965 else if (Fortran::semantics::IsAssumedLengthCharacter(sym
))
1966 nonDeferredLenParams
.push_back(
1967 Fortran::lower::getAssumedCharAllocatableOrPointerLen(
1968 builder
, loc
, sym
, boxAlloc
));
1969 } else if (const Fortran::semantics::DeclTypeSpec
*declTy
= sym
.GetType()) {
1970 if (const Fortran::semantics::DerivedTypeSpec
*derived
=
1971 declTy
->AsDerived())
1972 if (Fortran::semantics::CountLenParameters(*derived
) != 0)
1974 "derived type allocatable or pointer with length parameters");
1976 fir::MutableBoxValue box
= Fortran::lower::createMutableBox(
1977 converter
, loc
, var
, boxAlloc
, nonDeferredLenParams
,
1979 converter
.getLoweringOptions().getLowerToHighLevelFIR(),
1980 getAllocatorIdx(var
.getSymbol()));
1981 genAllocatableOrPointerDeclare(converter
, symMap
, var
.getSymbol(), box
,
1987 mlir::Value dummyArg
= symMap
.lookupSymbol(sym
).getAddr();
1988 if (lowerToBoxValue(sym
, dummyArg
, converter
)) {
1989 llvm::SmallVector
<mlir::Value
> lbounds
;
1990 llvm::SmallVector
<mlir::Value
> explicitExtents
;
1991 llvm::SmallVector
<mlir::Value
> explicitParams
;
1992 // Lower lower bounds, explicit type parameters and explicit
1995 if (mlir::Value len
=
1996 lowerExplicitCharLen(converter
, loc
, ba
, symMap
, stmtCtx
))
1997 explicitParams
.push_back(len
);
1998 if (!isAssumedRank
&& sym
.Rank() == 0) {
1999 // Do not keep scalar characters as fir.box (even when optional).
2000 // Lowering and FIR is not meant to deal with scalar characters as
2001 // fir.box outside of calls.
2002 auto boxTy
= mlir::dyn_cast
<fir::BaseBoxType
>(dummyArg
.getType());
2003 mlir::Type refTy
= builder
.getRefType(boxTy
.getEleTy());
2004 mlir::Type lenType
= builder
.getCharacterLengthType();
2005 mlir::Value addr
, len
;
2006 if (Fortran::semantics::IsOptional(sym
)) {
2007 auto isPresent
= builder
.create
<fir::IsPresentOp
>(
2008 loc
, builder
.getI1Type(), dummyArg
);
2011 .genIfOp(loc
, {refTy
, lenType
}, isPresent
,
2012 /*withElseRegion=*/true)
2014 mlir::Value readAddr
=
2015 builder
.create
<fir::BoxAddrOp
>(loc
, refTy
, dummyArg
);
2016 mlir::Value readLength
=
2017 charHelp
.readLengthFromBox(dummyArg
);
2018 builder
.create
<fir::ResultOp
>(
2019 loc
, mlir::ValueRange
{readAddr
, readLength
});
2022 mlir::Value readAddr
= builder
.genAbsentOp(loc
, refTy
);
2023 mlir::Value readLength
=
2024 fir::factory::createZeroValue(builder
, loc
, lenType
);
2025 builder
.create
<fir::ResultOp
>(
2026 loc
, mlir::ValueRange
{readAddr
, readLength
});
2029 addr
= addrAndLen
[0];
2030 len
= addrAndLen
[1];
2032 addr
= builder
.create
<fir::BoxAddrOp
>(loc
, refTy
, dummyArg
);
2033 len
= charHelp
.readLengthFromBox(dummyArg
);
2035 if (!explicitParams
.empty())
2036 len
= explicitParams
[0];
2037 ::genDeclareSymbol(converter
, symMap
, sym
, addr
, len
, /*extents=*/{},
2038 /*lbounds=*/{}, replace
);
2042 // TODO: derived type length parameters.
2043 if (!isAssumedRank
) {
2044 lowerExplicitLowerBounds(converter
, loc
, ba
, lbounds
, symMap
, stmtCtx
);
2045 lowerExplicitExtents(converter
, loc
, ba
, lbounds
, explicitExtents
,
2048 genBoxDeclare(converter
, symMap
, sym
, dummyArg
, lbounds
, explicitParams
,
2049 explicitExtents
, replace
);
2054 // A dummy from another entry point that is not declared in the current
2055 // entry point requires a skeleton definition. Most such "unused" dummies
2056 // will not survive into final generated code, but some will. It is illegal
2057 // to reference one at run time if it does. Such a dummy is mapped to a
2058 // value in one of three ways:
2060 // - Generate a fir::UndefOp value. This is lightweight, easy to clean up,
2061 // and often valid, but it may fail for a dummy with dynamic bounds,
2062 // or a dummy used to define another dummy. Information to distinguish
2063 // valid cases is not generally available here, with the exception of
2064 // dummy procedures. See the first function exit above.
2066 // - Allocate an uninitialized stack slot. This is an intermediate-weight
2067 // solution that is harder to clean up. It is often valid, but may fail
2068 // for an object with dynamic bounds. This option is "automatically"
2069 // used by default for cases that do not use one of the other options.
2071 // - Allocate a heap box/descriptor, initialized to zero. This always
2072 // works, but is more heavyweight and harder to clean up. It is used
2073 // for dynamic objects via calls to genUnusedEntryPointBox.
2075 auto genUnusedEntryPointBox
= [&]() {
2076 if (isUnusedEntryDummy
) {
2077 assert(!Fortran::semantics::IsAllocatableOrPointer(sym
) &&
2079 // The box is read right away because lowering code does not expect
2080 // a non pointer/allocatable symbol to be mapped to a MutableBox.
2081 mlir::Type ty
= converter
.genType(var
);
2082 bool isPolymorphic
= false;
2083 if (auto boxTy
= mlir::dyn_cast
<fir::BaseBoxType
>(ty
)) {
2084 isPolymorphic
= mlir::isa
<fir::ClassType
>(ty
);
2085 ty
= boxTy
.getEleTy();
2087 Fortran::lower::genDeclareSymbol(
2088 converter
, symMap
, sym
,
2089 fir::factory::genMutableBoxRead(
2091 fir::factory::createTempMutableBox(builder
, loc
, ty
, {}, {},
2093 fir::FortranVariableFlagsEnum::None
,
2094 converter
.isRegisteredDummySymbol(sym
));
2100 if (isAssumedRank
) {
2101 assert(isUnusedEntryDummy
&& "assumed rank must be pointers/allocatables "
2102 "or descriptor dummy arguments");
2103 genUnusedEntryPointBox();
2107 // Helper to generate scalars for the symbol properties.
2108 auto genValue
= [&](const Fortran::lower::SomeExpr
&expr
) {
2109 return genScalarValue(converter
, loc
, expr
, symMap
, stmtCtx
);
2112 // For symbols reaching this point, all properties are constant and can be
2113 // read/computed already into ssa values.
2115 // The origin must be \vec{1}.
2116 auto populateShape
= [&](auto &shapes
, const auto &bounds
, mlir::Value box
) {
2117 for (auto iter
: llvm::enumerate(bounds
)) {
2118 auto *spec
= iter
.value();
2119 assert(spec
->lbound().GetExplicit() &&
2120 "lbound must be explicit with constant value 1");
2121 if (auto high
= spec
->ubound().GetExplicit()) {
2122 Fortran::lower::SomeExpr highEx
{*high
};
2123 mlir::Value ub
= genValue(highEx
);
2124 ub
= builder
.createConvert(loc
, idxTy
, ub
);
2125 shapes
.emplace_back(fir::factory::genMaxWithZero(builder
, loc
, ub
));
2126 } else if (spec
->ubound().isColon()) {
2127 assert(box
&& "assumed bounds require a descriptor");
2129 builder
.createIntegerConstant(loc
, idxTy
, iter
.index());
2131 builder
.create
<fir::BoxDimsOp
>(loc
, idxTy
, idxTy
, idxTy
, box
, dim
);
2132 shapes
.emplace_back(dimInfo
.getResult(1));
2133 } else if (spec
->ubound().isStar()) {
2134 shapes
.emplace_back(getAssumedSizeExtent(loc
, builder
));
2136 llvm::report_fatal_error("unknown bound category");
2141 // The origin is not \vec{1}.
2142 auto populateLBoundsExtents
= [&](auto &lbounds
, auto &extents
,
2143 const auto &bounds
, mlir::Value box
) {
2144 for (auto iter
: llvm::enumerate(bounds
)) {
2145 auto *spec
= iter
.value();
2146 fir::BoxDimsOp dimInfo
;
2148 if (spec
->lbound().isColon() || spec
->ubound().isColon()) {
2149 // This is an assumed shape because allocatables and pointers extents
2150 // are not constant in the scope and are not read here.
2151 assert(box
&& "deferred bounds require a descriptor");
2153 builder
.createIntegerConstant(loc
, idxTy
, iter
.index());
2155 builder
.create
<fir::BoxDimsOp
>(loc
, idxTy
, idxTy
, idxTy
, box
, dim
);
2156 extents
.emplace_back(dimInfo
.getResult(1));
2157 if (auto low
= spec
->lbound().GetExplicit()) {
2158 auto expr
= Fortran::lower::SomeExpr
{*low
};
2159 mlir::Value lb
= builder
.createConvert(loc
, idxTy
, genValue(expr
));
2160 lbounds
.emplace_back(lb
);
2162 // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
2163 lbounds
.emplace_back(builder
.createIntegerConstant(loc
, idxTy
, 1));
2166 if (auto low
= spec
->lbound().GetExplicit()) {
2167 auto expr
= Fortran::lower::SomeExpr
{*low
};
2168 lb
= builder
.createConvert(loc
, idxTy
, genValue(expr
));
2170 TODO(loc
, "support for assumed rank entities");
2172 lbounds
.emplace_back(lb
);
2174 if (auto high
= spec
->ubound().GetExplicit()) {
2175 auto expr
= Fortran::lower::SomeExpr
{*high
};
2176 ub
= builder
.createConvert(loc
, idxTy
, genValue(expr
));
2177 extents
.emplace_back(computeExtent(builder
, loc
, lb
, ub
));
2179 // An assumed size array. The extent is not computed.
2180 assert(spec
->ubound().isStar() && "expected assumed size");
2181 extents
.emplace_back(getAssumedSizeExtent(loc
, builder
));
2187 //===--------------------------------------------------------------===//
2188 // Non Pointer non allocatable scalar, explicit shape, and assumed
2190 // Lower the specification expressions.
2191 //===--------------------------------------------------------------===//
2194 llvm::SmallVector
<mlir::Value
> extents
;
2195 llvm::SmallVector
<mlir::Value
> lbounds
;
2196 auto arg
= symMap
.lookupSymbol(sym
).getAddr();
2197 mlir::Value addr
= preAlloc
;
2200 if (auto boxTy
= mlir::dyn_cast
<fir::BaseBoxType
>(arg
.getType())) {
2201 // Contiguous assumed shape that can be tracked without a fir.box.
2202 mlir::Type refTy
= builder
.getRefType(boxTy
.getEleTy());
2203 addr
= builder
.create
<fir::BoxAddrOp
>(loc
, refTy
, arg
);
2206 // Compute/Extract character length.
2209 assert(!preAlloc
&& "dummy cannot be pre-allocated");
2210 if (mlir::isa
<fir::BoxCharType
>(arg
.getType())) {
2211 std::tie(addr
, len
) = charHelp
.createUnboxChar(arg
);
2212 } else if (mlir::isa
<fir::CharacterType
>(arg
.getType())) {
2213 // fir.char<1> passed by value (BIND(C) with VALUE attribute).
2214 addr
= builder
.create
<fir::AllocaOp
>(loc
, arg
.getType());
2215 builder
.create
<fir::StoreOp
>(loc
, arg
, addr
);
2219 // Ensure proper type is given to array/scalar that was transmitted as a
2220 // fir.boxchar arg or is a statement function actual argument with
2221 // a different length than the dummy.
2222 mlir::Type castTy
= builder
.getRefType(converter
.genType(var
));
2223 addr
= builder
.createConvert(loc
, castTy
, addr
);
2225 if (std::optional
<int64_t> cstLen
= ba
.getCharLenConst()) {
2227 len
= builder
.createIntegerConstant(loc
, idxTy
, *cstLen
);
2230 if (genUnusedEntryPointBox())
2232 if (std::optional
<Fortran::lower::SomeExpr
> charLenExpr
=
2233 ba
.getCharLenExpr()) {
2235 mlir::Value rawLen
= genValue(*charLenExpr
);
2236 // If the length expression is negative, the length is zero. See
2237 // F2018 7.4.4.2 point 5.
2238 len
= fir::factory::genMaxWithZero(builder
, loc
, rawLen
);
2240 // Assumed length fir.box (possible for contiguous assumed shapes).
2241 // Read length from box.
2242 assert(arg
&& mlir::isa
<fir::BoxType
>(arg
.getType()) &&
2243 "must be character dummy fir.box");
2244 len
= charHelp
.readLengthFromBox(arg
);
2249 // Compute array extents and lower bounds.
2251 if (ba
.isStaticArray()) {
2252 if (ba
.lboundIsAllOnes()) {
2253 for (std::int64_t extent
:
2254 recoverShapeVector(ba
.staticShape(), preAlloc
))
2255 extents
.push_back(genExtentValue(builder
, loc
, idxTy
, extent
));
2257 for (auto [lb
, extent
] :
2258 llvm::zip(ba
.staticLBound(),
2259 recoverShapeVector(ba
.staticShape(), preAlloc
))) {
2260 lbounds
.emplace_back(builder
.createIntegerConstant(loc
, idxTy
, lb
));
2261 extents
.emplace_back(genExtentValue(builder
, loc
, idxTy
, extent
));
2265 // Non compile time constant shape.
2266 if (genUnusedEntryPointBox())
2268 if (ba
.lboundIsAllOnes())
2269 populateShape(extents
, ba
.dynamicBound(), arg
);
2271 populateLBoundsExtents(lbounds
, extents
, ba
.dynamicBound(), arg
);
2275 // Allocate or extract raw address for the entity
2278 mlir::Type argType
= arg
.getType();
2279 const bool isCptrByVal
= Fortran::semantics::IsBuiltinCPtr(sym
) &&
2280 Fortran::lower::isCPtrArgByValueType(argType
);
2281 if (isCptrByVal
|| !fir::conformsWithPassByRef(argType
)) {
2282 // Dummy argument passed in register. Place the value in memory at that
2283 // point since lowering expect symbols to be mapped to memory addresses.
2284 mlir::Type symType
= converter
.genType(sym
);
2285 addr
= builder
.create
<fir::AllocaOp
>(loc
, symType
);
2287 // Place the void* address into the CPTR address component.
2288 mlir::Value addrComponent
=
2289 fir::factory::genCPtrOrCFunptrAddr(builder
, loc
, addr
, symType
);
2290 builder
.createStoreWithConvert(loc
, arg
, addrComponent
);
2292 builder
.createStoreWithConvert(loc
, arg
, addr
);
2295 // Dummy address, or address of result whose storage is passed by the
2297 assert(fir::isa_ref_type(argType
) && "must be a memory address");
2302 llvm::SmallVector
<mlir::Value
> typeParams
;
2304 typeParams
.emplace_back(len
);
2305 addr
= createNewLocal(converter
, loc
, var
, preAlloc
, extents
, typeParams
);
2309 ::genDeclareSymbol(converter
, symMap
, sym
, addr
, len
, extents
, lbounds
,
2314 void Fortran::lower::defineModuleVariable(
2315 AbstractConverter
&converter
, const Fortran::lower::pft::Variable
&var
) {
2316 // Use empty linkage for module variables, which makes them available
2317 // for use in another unit.
2318 mlir::StringAttr linkage
=
2319 getLinkageAttribute(converter
.getFirOpBuilder(), var
);
2320 if (!var
.isGlobal())
2321 fir::emitFatalError(converter
.getCurrentLocation(),
2322 "attempting to lower module variable as local");
2323 // Define aggregate storages for equivalenced objects.
2324 if (var
.isAggregateStore()) {
2325 const Fortran::lower::pft::Variable::AggregateStore
&aggregate
=
2326 var
.getAggregateStore();
2327 std::string aggName
= mangleGlobalAggregateStore(converter
, aggregate
);
2328 defineGlobalAggregateStore(converter
, aggregate
, aggName
, linkage
);
2331 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
2332 if (const Fortran::semantics::Symbol
*common
=
2333 Fortran::semantics::FindCommonBlockContaining(var
.getSymbol())) {
2334 // Nothing to do, common block are generated before everything. Ensure
2335 // this was done by calling getCommonBlockGlobal.
2336 getCommonBlockGlobal(converter
, *common
);
2337 } else if (var
.isAlias()) {
2338 // Do nothing. Mapping will be done on user side.
2340 std::string globalName
= converter
.mangleName(sym
);
2341 cuf::DataAttributeAttr dataAttr
=
2342 Fortran::lower::translateSymbolCUFDataAttribute(
2343 converter
.getFirOpBuilder().getContext(), sym
);
2344 defineGlobal(converter
, var
, globalName
, linkage
, dataAttr
);
2348 void Fortran::lower::instantiateVariable(AbstractConverter
&converter
,
2349 const pft::Variable
&var
,
2350 Fortran::lower::SymMap
&symMap
,
2351 AggregateStoreMap
&storeMap
) {
2352 if (var
.hasSymbol()) {
2353 // Do not try to instantiate symbols twice, except for dummies and results,
2354 // that may have been mapped to the MLIR entry block arguments, and for
2355 // which the explicit specifications, if any, has not yet been lowered.
2356 const auto &sym
= var
.getSymbol();
2357 if (!IsDummy(sym
) && !IsFunctionResult(sym
) && symMap
.lookupSymbol(sym
))
2360 LLVM_DEBUG(llvm::dbgs() << "instantiateVariable: "; var
.dump());
2361 if (var
.isAggregateStore())
2362 instantiateAggregateStore(converter
, var
, storeMap
);
2363 else if (const Fortran::semantics::Symbol
*common
=
2364 Fortran::semantics::FindCommonBlockContaining(
2365 var
.getSymbol().GetUltimate()))
2366 instantiateCommon(converter
, *common
, var
, symMap
);
2367 else if (var
.isAlias())
2368 instantiateAlias(converter
, var
, symMap
, storeMap
);
2369 else if (var
.isGlobal())
2370 instantiateGlobal(converter
, var
, symMap
);
2372 instantiateLocal(converter
, var
, symMap
);
2376 mapCallInterfaceSymbol(const Fortran::semantics::Symbol
&interfaceSymbol
,
2377 Fortran::lower::AbstractConverter
&converter
,
2378 const Fortran::lower::CallerInterface
&caller
,
2379 Fortran::lower::SymMap
&symMap
) {
2380 Fortran::lower::AggregateStoreMap storeMap
;
2381 for (Fortran::lower::pft::Variable var
:
2382 Fortran::lower::pft::getDependentVariableList(interfaceSymbol
)) {
2383 if (var
.isAggregateStore()) {
2384 instantiateVariable(converter
, var
, symMap
, storeMap
);
2387 const Fortran::semantics::Symbol
&sym
= var
.getSymbol();
2388 if (&sym
== &interfaceSymbol
)
2390 const auto *hostDetails
=
2391 sym
.detailsIf
<Fortran::semantics::HostAssocDetails
>();
2392 if (hostDetails
&& !var
.isModuleOrSubmoduleVariable()) {
2393 // The callee is an internal procedure `A` whose result properties
2394 // depend on host variables. The caller may be the host, or another
2395 // internal procedure `B` contained in the same host. In the first
2396 // case, the host symbol is obviously mapped, in the second case, it
2397 // must also be mapped because
2398 // HostAssociations::internalProcedureBindings that was called when
2399 // lowering `B` will have mapped all host symbols of captured variables
2400 // to the tuple argument containing the composite of all host associated
2401 // variables, whether or not the host symbol is actually referred to in
2402 // `B`. Hence it is possible to simply lookup the variable associated to
2403 // the host symbol without having to go back to the tuple argument.
2404 symMap
.copySymbolBinding(hostDetails
->symbol(), sym
);
2405 // The SymbolBox associated to the host symbols is complete, skip
2406 // instantiateVariable that would try to allocate a new storage.
2409 if (Fortran::semantics::IsDummy(sym
) &&
2410 sym
.owner() == interfaceSymbol
.owner()) {
2411 // Get the argument for the dummy argument symbols of the current call.
2412 symMap
.addSymbol(sym
, caller
.getArgumentValue(sym
));
2413 // All the properties of the dummy variable may not come from the actual
2414 // argument, let instantiateVariable handle this.
2416 // If this is neither a host associated or dummy symbol, it must be a
2417 // module or common block variable to satisfy specification expression
2418 // requirements in 10.1.11, instantiateVariable will get its address and
2420 instantiateVariable(converter
, var
, symMap
, storeMap
);
2424 void Fortran::lower::mapCallInterfaceSymbolsForResult(
2425 AbstractConverter
&converter
, const Fortran::lower::CallerInterface
&caller
,
2427 const Fortran::semantics::Symbol
&result
= caller
.getResultSymbol();
2428 mapCallInterfaceSymbol(result
, converter
, caller
, symMap
);
2431 void Fortran::lower::mapCallInterfaceSymbolsForDummyArgument(
2432 AbstractConverter
&converter
, const Fortran::lower::CallerInterface
&caller
,
2433 SymMap
&symMap
, const Fortran::semantics::Symbol
&dummySymbol
) {
2434 mapCallInterfaceSymbol(dummySymbol
, converter
, caller
, symMap
);
2437 void Fortran::lower::mapSymbolAttributes(
2438 AbstractConverter
&converter
, const Fortran::semantics::SymbolRef
&symbol
,
2439 Fortran::lower::SymMap
&symMap
, Fortran::lower::StatementContext
&stmtCtx
,
2440 mlir::Value preAlloc
) {
2441 mapSymbolAttributes(converter
, pft::Variable
{symbol
}, symMap
, stmtCtx
,
2445 void Fortran::lower::createIntrinsicModuleGlobal(
2446 Fortran::lower::AbstractConverter
&converter
, const pft::Variable
&var
) {
2447 defineGlobal(converter
, var
, converter
.mangleName(var
.getSymbol()),
2448 converter
.getFirOpBuilder().createLinkOnceODRLinkage());
2451 void Fortran::lower::createRuntimeTypeInfoGlobal(
2452 Fortran::lower::AbstractConverter
&converter
,
2453 const Fortran::semantics::Symbol
&typeInfoSym
) {
2454 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
2455 std::string globalName
= converter
.mangleName(typeInfoSym
);
2456 auto var
= Fortran::lower::pft::Variable(typeInfoSym
, /*global=*/true);
2457 mlir::StringAttr linkage
= getLinkageAttribute(builder
, var
);
2458 defineGlobal(converter
, var
, globalName
, linkage
);
2461 mlir::Type
Fortran::lower::getCrayPointeeBoxType(mlir::Type fortranType
) {
2462 mlir::Type baseType
= hlfir::getFortranElementOrSequenceType(fortranType
);
2463 if (auto seqType
= mlir::dyn_cast
<fir::SequenceType
>(baseType
)) {
2464 // The pointer box's sequence type must be with unknown shape.
2465 llvm::SmallVector
<int64_t> shape(seqType
.getDimension(),
2466 fir::SequenceType::getUnknownExtent());
2467 baseType
= fir::SequenceType::get(shape
, seqType
.getEleTy());
2469 return fir::BoxType::get(fir::PointerType::get(baseType
));