[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / flang / lib / Lower / ConvertVariable.cpp
blobcc51d5a9bb8daf12a3bfd77dc95f11bf1f46a865
1 //===-- ConvertVariable.cpp -- bridge to lower to MLIR --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
11 //===----------------------------------------------------------------------===//
13 #include "flang/Lower/ConvertVariable.h"
14 #include "flang/Lower/AbstractConverter.h"
15 #include "flang/Lower/Allocatable.h"
16 #include "flang/Lower/BoxAnalyzer.h"
17 #include "flang/Lower/CallInterface.h"
18 #include "flang/Lower/ConvertConstant.h"
19 #include "flang/Lower/ConvertExpr.h"
20 #include "flang/Lower/ConvertExprToHLFIR.h"
21 #include "flang/Lower/ConvertProcedureDesignator.h"
22 #include "flang/Lower/Mangler.h"
23 #include "flang/Lower/PFTBuilder.h"
24 #include "flang/Lower/StatementContext.h"
25 #include "flang/Lower/Support/Utils.h"
26 #include "flang/Lower/SymbolMap.h"
27 #include "flang/Optimizer/Builder/Character.h"
28 #include "flang/Optimizer/Builder/FIRBuilder.h"
29 #include "flang/Optimizer/Builder/HLFIRTools.h"
30 #include "flang/Optimizer/Builder/IntrinsicCall.h"
31 #include "flang/Optimizer/Builder/Runtime/Derived.h"
32 #include "flang/Optimizer/Builder/Todo.h"
33 #include "flang/Optimizer/Dialect/CUF/CUFOps.h"
34 #include "flang/Optimizer/Dialect/FIRAttr.h"
35 #include "flang/Optimizer/Dialect/FIRDialect.h"
36 #include "flang/Optimizer/Dialect/FIROps.h"
37 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
38 #include "flang/Optimizer/HLFIR/HLFIROps.h"
39 #include "flang/Optimizer/Support/FatalError.h"
40 #include "flang/Optimizer/Support/InternalNames.h"
41 #include "flang/Optimizer/Support/Utils.h"
42 #include "flang/Runtime/allocator-registry.h"
43 #include "flang/Semantics/runtime-type-info.h"
44 #include "flang/Semantics/tools.h"
45 #include "llvm/Support/CommandLine.h"
46 #include "llvm/Support/Debug.h"
47 #include <optional>
49 static llvm::cl::opt<bool>
50 allowAssumedRank("allow-assumed-rank",
51 llvm::cl::desc("Enable assumed rank lowering"),
52 llvm::cl::init(true));
54 #define DEBUG_TYPE "flang-lower-variable"
56 /// Helper to lower a scalar expression using a specific symbol mapping.
57 static mlir::Value genScalarValue(Fortran::lower::AbstractConverter &converter,
58 mlir::Location loc,
59 const Fortran::lower::SomeExpr &expr,
60 Fortran::lower::SymMap &symMap,
61 Fortran::lower::StatementContext &context) {
62 // This does not use the AbstractConverter member function to override the
63 // symbol mapping to be used expression lowering.
64 if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
65 hlfir::EntityWithAttributes loweredExpr =
66 Fortran::lower::convertExprToHLFIR(loc, converter, expr, symMap,
67 context);
68 return hlfir::loadTrivialScalar(loc, converter.getFirOpBuilder(),
69 loweredExpr);
71 return fir::getBase(Fortran::lower::createSomeExtendedExpression(
72 loc, converter, expr, symMap, context));
75 /// Does this variable have a default initialization?
76 bool Fortran::lower::hasDefaultInitialization(
77 const Fortran::semantics::Symbol &sym) {
78 if (sym.has<Fortran::semantics::ObjectEntityDetails>() && sym.size())
79 if (!Fortran::semantics::IsAllocatableOrPointer(sym))
80 if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
81 if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
82 declTypeSpec->AsDerived()) {
83 // Pointer assignments in the runtime may hit undefined behaviors if
84 // the RHS contains garbage. Pointer objects are always established by
85 // lowering to NULL() (in Fortran::lower::createMutableBox). However,
86 // pointer components need special care here so that local and global
87 // derived type containing pointers are always initialized.
88 // Intent(out), however, do not need to be initialized since the
89 // related descriptor storage comes from a local or global that has
90 // been initialized (it may not be NULL() anymore, but the rank, type,
91 // and non deferred length parameters are still correct in a
92 // conformant program, and that is what matters).
93 const bool ignorePointer = Fortran::semantics::IsIntentOut(sym);
94 return derivedTypeSpec->HasDefaultInitialization(
95 /*ignoreAllocatable=*/false, ignorePointer);
97 return false;
100 // Does this variable have a finalization?
101 static bool hasFinalization(const Fortran::semantics::Symbol &sym) {
102 if (sym.has<Fortran::semantics::ObjectEntityDetails>())
103 if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
104 if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
105 declTypeSpec->AsDerived())
106 return Fortran::semantics::IsFinalizable(*derivedTypeSpec);
107 return false;
110 // Does this variable have an allocatable direct component?
111 static bool
112 hasAllocatableDirectComponent(const Fortran::semantics::Symbol &sym) {
113 if (sym.has<Fortran::semantics::ObjectEntityDetails>())
114 if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType())
115 if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
116 declTypeSpec->AsDerived())
117 return Fortran::semantics::HasAllocatableDirectComponent(
118 *derivedTypeSpec);
119 return false;
121 //===----------------------------------------------------------------===//
122 // Global variables instantiation (not for alias and common)
123 //===----------------------------------------------------------------===//
125 /// Helper to generate expression value inside global initializer.
126 static fir::ExtendedValue
127 genInitializerExprValue(Fortran::lower::AbstractConverter &converter,
128 mlir::Location loc,
129 const Fortran::lower::SomeExpr &expr,
130 Fortran::lower::StatementContext &stmtCtx) {
131 // Data initializer are constant value and should not depend on other symbols
132 // given the front-end fold parameter references. In any case, the "current"
133 // map of the converter should not be used since it holds mapping to
134 // mlir::Value from another mlir region. If these value are used by accident
135 // in the initializer, this will lead to segfaults in mlir code.
136 Fortran::lower::SymMap emptyMap;
137 return Fortran::lower::createSomeInitializerExpression(loc, converter, expr,
138 emptyMap, stmtCtx);
141 /// Can this symbol constant be placed in read-only memory?
142 static bool isConstant(const Fortran::semantics::Symbol &sym) {
143 return sym.attrs().test(Fortran::semantics::Attr::PARAMETER) ||
144 sym.test(Fortran::semantics::Symbol::Flag::ReadOnly);
147 static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
148 const Fortran::lower::pft::Variable &var,
149 llvm::StringRef globalName,
150 mlir::StringAttr linkage,
151 cuf::DataAttributeAttr dataAttr = {});
153 static mlir::Location genLocation(Fortran::lower::AbstractConverter &converter,
154 const Fortran::semantics::Symbol &sym) {
155 // Compiler generated name cannot be used as source location, their name
156 // is not pointing to the source files.
157 if (!sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated))
158 return converter.genLocation(sym.name());
159 return converter.getCurrentLocation();
162 /// Create the global op declaration without any initializer
163 static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
164 const Fortran::lower::pft::Variable &var,
165 llvm::StringRef globalName,
166 mlir::StringAttr linkage) {
167 fir::FirOpBuilder &builder = converter.getFirOpBuilder();
168 if (fir::GlobalOp global = builder.getNamedGlobal(globalName))
169 return global;
170 const Fortran::semantics::Symbol &sym = var.getSymbol();
171 cuf::DataAttributeAttr dataAttr =
172 Fortran::lower::translateSymbolCUFDataAttribute(
173 converter.getFirOpBuilder().getContext(), sym);
174 // Always define linkonce data since it may be optimized out from the module
175 // that actually owns the variable if it does not refers to it.
176 if (linkage == builder.createLinkOnceODRLinkage() ||
177 linkage == builder.createLinkOnceLinkage())
178 return defineGlobal(converter, var, globalName, linkage, dataAttr);
179 mlir::Location loc = genLocation(converter, sym);
180 // Resolve potential host and module association before checking that this
181 // symbol is an object of a function pointer.
182 const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
183 if (!ultimate.has<Fortran::semantics::ObjectEntityDetails>() &&
184 !Fortran::semantics::IsProcedurePointer(ultimate))
185 mlir::emitError(loc, "processing global declaration: symbol '")
186 << toStringRef(sym.name()) << "' has unexpected details\n";
187 return builder.createGlobal(loc, converter.genType(var), globalName, linkage,
188 mlir::Attribute{}, isConstant(ultimate),
189 var.isTarget(), dataAttr);
192 /// Temporary helper to catch todos in initial data target lowering.
193 static bool
194 hasDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol &sym) {
195 if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType())
196 if (const Fortran::semantics::DerivedTypeSpec *derived =
197 declTy->AsDerived())
198 return Fortran::semantics::CountLenParameters(*derived) > 0;
199 return false;
202 fir::ExtendedValue Fortran::lower::genExtAddrInInitializer(
203 Fortran::lower::AbstractConverter &converter, mlir::Location loc,
204 const Fortran::lower::SomeExpr &addr) {
205 Fortran::lower::SymMap globalOpSymMap;
206 Fortran::lower::AggregateStoreMap storeMap;
207 Fortran::lower::StatementContext stmtCtx;
208 if (const Fortran::semantics::Symbol *sym =
209 Fortran::evaluate::GetFirstSymbol(addr)) {
210 // Length parameters processing will need care in global initializer
211 // context.
212 if (hasDerivedTypeWithLengthParameters(*sym))
213 TODO(loc, "initial-data-target with derived type length parameters");
215 auto var = Fortran::lower::pft::Variable(*sym, /*global=*/true);
216 Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
217 storeMap);
220 if (converter.getLoweringOptions().getLowerToHighLevelFIR())
221 return Fortran::lower::convertExprToAddress(loc, converter, addr,
222 globalOpSymMap, stmtCtx);
223 return Fortran::lower::createInitializerAddress(loc, converter, addr,
224 globalOpSymMap, stmtCtx);
227 /// create initial-data-target fir.box in a global initializer region.
228 mlir::Value Fortran::lower::genInitialDataTarget(
229 Fortran::lower::AbstractConverter &converter, mlir::Location loc,
230 mlir::Type boxType, const Fortran::lower::SomeExpr &initialTarget,
231 bool couldBeInEquivalence) {
232 Fortran::lower::SymMap globalOpSymMap;
233 Fortran::lower::AggregateStoreMap storeMap;
234 Fortran::lower::StatementContext stmtCtx;
235 fir::FirOpBuilder &builder = converter.getFirOpBuilder();
236 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
237 initialTarget))
238 return fir::factory::createUnallocatedBox(
239 builder, loc, boxType,
240 /*nonDeferredParams=*/std::nullopt);
241 // Pointer initial data target, and NULL(mold).
242 for (const auto &sym : Fortran::evaluate::CollectSymbols(initialTarget)) {
243 // Derived type component symbols should not be instantiated as objects
244 // on their own.
245 if (sym->owner().IsDerivedType())
246 continue;
247 // Length parameters processing will need care in global initializer
248 // context.
249 if (hasDerivedTypeWithLengthParameters(sym))
250 TODO(loc, "initial-data-target with derived type length parameters");
251 auto var = Fortran::lower::pft::Variable(sym, /*global=*/true);
252 if (couldBeInEquivalence) {
253 auto dependentVariableList =
254 Fortran::lower::pft::getDependentVariableList(sym);
255 for (Fortran::lower::pft::Variable var : dependentVariableList) {
256 if (!var.isAggregateStore())
257 break;
258 instantiateVariable(converter, var, globalOpSymMap, storeMap);
260 var = dependentVariableList.back();
261 assert(var.getSymbol().name() == sym->name() &&
262 "missing symbol in dependence list");
264 Fortran::lower::instantiateVariable(converter, var, globalOpSymMap,
265 storeMap);
268 // Handle NULL(mold) as a special case. Return an unallocated box of MOLD
269 // type. The return box is correctly created as a fir.box<fir.ptr<T>> where
270 // T is extracted from the MOLD argument.
271 if (const Fortran::evaluate::ProcedureRef *procRef =
272 Fortran::evaluate::UnwrapProcedureRef(initialTarget)) {
273 const Fortran::evaluate::SpecificIntrinsic *intrinsic =
274 procRef->proc().GetSpecificIntrinsic();
275 if (intrinsic && intrinsic->name == "null") {
276 assert(procRef->arguments().size() == 1 &&
277 "Expecting mold argument for NULL intrinsic");
278 const auto *argExpr = procRef->arguments()[0].value().UnwrapExpr();
279 assert(argExpr);
280 const Fortran::semantics::Symbol *sym =
281 Fortran::evaluate::GetFirstSymbol(*argExpr);
282 assert(sym && "MOLD must be a pointer or allocatable symbol");
283 mlir::Type boxType = converter.genType(*sym);
284 mlir::Value box =
285 fir::factory::createUnallocatedBox(builder, loc, boxType, {});
286 return box;
290 mlir::Value targetBox;
291 mlir::Value targetShift;
292 if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
293 auto target = Fortran::lower::convertExprToBox(
294 loc, converter, initialTarget, globalOpSymMap, stmtCtx);
295 targetBox = fir::getBase(target);
296 targetShift = builder.createShape(loc, target);
297 } else {
298 if (initialTarget.Rank() > 0) {
299 auto target = Fortran::lower::createSomeArrayBox(converter, initialTarget,
300 globalOpSymMap, stmtCtx);
301 targetBox = fir::getBase(target);
302 targetShift = builder.createShape(loc, target);
303 } else {
304 fir::ExtendedValue addr = Fortran::lower::createInitializerAddress(
305 loc, converter, initialTarget, globalOpSymMap, stmtCtx);
306 targetBox = builder.createBox(loc, addr);
307 // Nothing to do for targetShift, the target is a scalar.
310 // The targetBox is a fir.box<T>, not a fir.box<fir.ptr<T>> as it should for
311 // pointers (this matters to get the POINTER attribute correctly inside the
312 // initial value of the descriptor).
313 // Create a fir.rebox to set the attribute correctly, and use targetShift
314 // to preserve the target lower bounds if any.
315 return builder.create<fir::ReboxOp>(loc, boxType, targetBox, targetShift,
316 /*slice=*/mlir::Value{});
319 /// Generate default initial value for a derived type object \p sym with mlir
320 /// type \p symTy.
321 static mlir::Value genDefaultInitializerValue(
322 Fortran::lower::AbstractConverter &converter, mlir::Location loc,
323 const Fortran::semantics::Symbol &sym, mlir::Type symTy,
324 Fortran::lower::StatementContext &stmtCtx);
326 /// Generate the initial value of a derived component \p component and insert
327 /// it into the derived type initial value \p insertInto of type \p recTy.
328 /// Return the new derived type initial value after the insertion.
329 static mlir::Value genComponentDefaultInit(
330 Fortran::lower::AbstractConverter &converter, mlir::Location loc,
331 const Fortran::semantics::Symbol &component, fir::RecordType recTy,
332 mlir::Value insertInto, Fortran::lower::StatementContext &stmtCtx) {
333 fir::FirOpBuilder &builder = converter.getFirOpBuilder();
334 std::string name = converter.getRecordTypeFieldName(component);
335 mlir::Type componentTy = recTy.getType(name);
336 assert(componentTy && "component not found in type");
337 mlir::Value componentValue;
338 if (const auto *object{
339 component.detailsIf<Fortran::semantics::ObjectEntityDetails>()}) {
340 if (const auto &init = object->init()) {
341 // Component has explicit initialization.
342 if (Fortran::semantics::IsPointer(component))
343 // Initial data target.
344 componentValue =
345 genInitialDataTarget(converter, loc, componentTy, *init);
346 else
347 // Initial value.
348 componentValue = fir::getBase(
349 genInitializerExprValue(converter, loc, *init, stmtCtx));
350 } else if (Fortran::semantics::IsAllocatableOrPointer(component)) {
351 // Pointer or allocatable without initialization.
352 // Create deallocated/disassociated value.
353 // From a standard point of view, pointer without initialization do not
354 // need to be disassociated, but for sanity and simplicity, do it in
355 // global constructor since this has no runtime cost.
356 componentValue = fir::factory::createUnallocatedBox(
357 builder, loc, componentTy, std::nullopt);
358 } else if (Fortran::lower::hasDefaultInitialization(component)) {
359 // Component type has default initialization.
360 componentValue = genDefaultInitializerValue(converter, loc, component,
361 componentTy, stmtCtx);
362 } else {
363 // Component has no initial value. Set its bits to zero by extension
364 // to match what is expected because other compilers are doing it.
365 componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
367 } else if (const auto *proc{
368 component
369 .detailsIf<Fortran::semantics::ProcEntityDetails>()}) {
370 if (proc->init().has_value()) {
371 auto sym{*proc->init()};
372 if (sym) // Has a procedure target.
373 componentValue =
374 Fortran::lower::convertProcedureDesignatorInitialTarget(converter,
375 loc, *sym);
376 else // Has NULL() target.
377 componentValue =
378 fir::factory::createNullBoxProc(builder, loc, componentTy);
379 } else
380 componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
382 assert(componentValue && "must have been computed");
383 componentValue = builder.createConvert(loc, componentTy, componentValue);
384 auto fieldTy = fir::FieldType::get(recTy.getContext());
385 // FIXME: type parameters must come from the derived-type-spec
386 auto field = builder.create<fir::FieldIndexOp>(
387 loc, fieldTy, name, recTy,
388 /*typeParams=*/mlir::ValueRange{} /*TODO*/);
389 return builder.create<fir::InsertValueOp>(
390 loc, recTy, insertInto, componentValue,
391 builder.getArrayAttr(field.getAttributes()));
394 static mlir::Value genDefaultInitializerValue(
395 Fortran::lower::AbstractConverter &converter, mlir::Location loc,
396 const Fortran::semantics::Symbol &sym, mlir::Type symTy,
397 Fortran::lower::StatementContext &stmtCtx) {
398 fir::FirOpBuilder &builder = converter.getFirOpBuilder();
399 mlir::Type scalarType = symTy;
400 fir::SequenceType sequenceType;
401 if (auto ty = mlir::dyn_cast<fir::SequenceType>(symTy)) {
402 sequenceType = ty;
403 scalarType = ty.getEleTy();
405 // Build a scalar default value of the symbol type, looping through the
406 // components to build each component initial value.
407 auto recTy = mlir::cast<fir::RecordType>(scalarType);
408 mlir::Value initialValue = builder.create<fir::UndefOp>(loc, scalarType);
409 const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
410 assert(declTy && "var with default initialization must have a type");
412 if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
413 // In HLFIR, the parent type is the first component, while in FIR there is
414 // not parent component in the fir.type and the component of the parent are
415 // "inlined" at the beginning of the fir.type.
416 const Fortran::semantics::Symbol &typeSymbol =
417 declTy->derivedTypeSpec().typeSymbol();
418 const Fortran::semantics::Scope *derivedScope =
419 declTy->derivedTypeSpec().GetScope();
420 assert(derivedScope && "failed to retrieve derived type scope");
421 for (const auto &componentName :
422 typeSymbol.get<Fortran::semantics::DerivedTypeDetails>()
423 .componentNames()) {
424 auto scopeIter = derivedScope->find(componentName);
425 assert(scopeIter != derivedScope->cend() &&
426 "failed to find derived type component symbol");
427 const Fortran::semantics::Symbol &component = scopeIter->second.get();
428 initialValue = genComponentDefaultInit(converter, loc, component, recTy,
429 initialValue, stmtCtx);
431 } else {
432 Fortran::semantics::OrderedComponentIterator components(
433 declTy->derivedTypeSpec());
434 for (const auto &component : components) {
435 // Skip parent components, the sub-components of parent types are part of
436 // components and will be looped through right after.
437 if (component.test(Fortran::semantics::Symbol::Flag::ParentComp))
438 continue;
439 initialValue = genComponentDefaultInit(converter, loc, component, recTy,
440 initialValue, stmtCtx);
444 if (sequenceType) {
445 // For arrays, duplicate the scalar value to all elements with an
446 // fir.insert_range covering the whole array.
447 auto arrayInitialValue = builder.create<fir::UndefOp>(loc, sequenceType);
448 llvm::SmallVector<int64_t> rangeBounds;
449 for (int64_t extent : sequenceType.getShape()) {
450 if (extent == fir::SequenceType::getUnknownExtent())
451 TODO(loc,
452 "default initial value of array component with length parameters");
453 rangeBounds.push_back(0);
454 rangeBounds.push_back(extent - 1);
456 return builder.create<fir::InsertOnRangeOp>(
457 loc, sequenceType, arrayInitialValue, initialValue,
458 builder.getIndexVectorAttr(rangeBounds));
460 return initialValue;
463 /// Does this global already have an initializer ?
464 static bool globalIsInitialized(fir::GlobalOp global) {
465 return !global.getRegion().empty() || global.getInitVal();
468 /// Call \p genInit to generate code inside \p global initializer region.
469 void Fortran::lower::createGlobalInitialization(
470 fir::FirOpBuilder &builder, fir::GlobalOp global,
471 std::function<void(fir::FirOpBuilder &)> genInit) {
472 mlir::Region &region = global.getRegion();
473 region.push_back(new mlir::Block);
474 mlir::Block &block = region.back();
475 auto insertPt = builder.saveInsertionPoint();
476 builder.setInsertionPointToStart(&block);
477 genInit(builder);
478 builder.restoreInsertionPoint(insertPt);
481 static unsigned getAllocatorIdx(cuf::DataAttributeAttr dataAttr) {
482 if (dataAttr) {
483 if (dataAttr.getValue() == cuf::DataAttribute::Pinned)
484 return kPinnedAllocatorPos;
485 if (dataAttr.getValue() == cuf::DataAttribute::Device)
486 return kDeviceAllocatorPos;
487 if (dataAttr.getValue() == cuf::DataAttribute::Managed)
488 return kManagedAllocatorPos;
489 if (dataAttr.getValue() == cuf::DataAttribute::Unified)
490 return kUnifiedAllocatorPos;
492 return kDefaultAllocator;
495 /// Create the global op and its init if it has one
496 static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
497 const Fortran::lower::pft::Variable &var,
498 llvm::StringRef globalName,
499 mlir::StringAttr linkage,
500 cuf::DataAttributeAttr dataAttr) {
501 fir::FirOpBuilder &builder = converter.getFirOpBuilder();
502 const Fortran::semantics::Symbol &sym = var.getSymbol();
503 mlir::Location loc = genLocation(converter, sym);
504 bool isConst = isConstant(sym);
505 fir::GlobalOp global = builder.getNamedGlobal(globalName);
506 mlir::Type symTy = converter.genType(var);
508 if (global && globalIsInitialized(global))
509 return global;
511 if (!converter.getLoweringOptions().getLowerToHighLevelFIR() &&
512 Fortran::semantics::IsProcedurePointer(sym))
513 TODO(loc, "procedure pointer globals");
515 // If this is an array, check to see if we can use a dense attribute
516 // with a tensor mlir type. This optimization currently only supports
517 // Fortran arrays of integer, real, complex, or logical. The tensor
518 // type does not support nested structures.
519 if (mlir::isa<fir::SequenceType>(symTy) &&
520 !Fortran::semantics::IsAllocatableOrPointer(sym)) {
521 mlir::Type eleTy = mlir::cast<fir::SequenceType>(symTy).getElementType();
522 if (mlir::isa<mlir::IntegerType, mlir::FloatType, mlir::ComplexType,
523 fir::LogicalType>(eleTy)) {
524 const auto *details =
525 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
526 if (details->init()) {
527 global = Fortran::lower::tryCreatingDenseGlobal(
528 builder, loc, symTy, globalName, linkage, isConst,
529 details->init().value(), dataAttr);
530 if (global) {
531 global.setVisibility(mlir::SymbolTable::Visibility::Public);
532 return global;
537 if (!global)
538 global =
539 builder.createGlobal(loc, symTy, globalName, linkage, mlir::Attribute{},
540 isConst, var.isTarget(), dataAttr);
541 if (Fortran::semantics::IsAllocatableOrPointer(sym) &&
542 !Fortran::semantics::IsProcedure(sym)) {
543 const auto *details =
544 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
545 if (details && details->init()) {
546 auto expr = *details->init();
547 Fortran::lower::createGlobalInitialization(
548 builder, global, [&](fir::FirOpBuilder &b) {
549 mlir::Value box = Fortran::lower::genInitialDataTarget(
550 converter, loc, symTy, expr);
551 b.create<fir::HasValueOp>(loc, box);
553 } else {
554 // Create unallocated/disassociated descriptor if no explicit init
555 Fortran::lower::createGlobalInitialization(
556 builder, global, [&](fir::FirOpBuilder &b) {
557 mlir::Value box = fir::factory::createUnallocatedBox(
558 b, loc, symTy,
559 /*nonDeferredParams=*/std::nullopt,
560 /*typeSourceBox=*/{}, getAllocatorIdx(dataAttr));
561 b.create<fir::HasValueOp>(loc, box);
564 } else if (const auto *details =
565 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
566 if (details->init()) {
567 Fortran::lower::createGlobalInitialization(
568 builder, global, [&](fir::FirOpBuilder &builder) {
569 Fortran::lower::StatementContext stmtCtx(
570 /*cleanupProhibited=*/true);
571 fir::ExtendedValue initVal = genInitializerExprValue(
572 converter, loc, details->init().value(), stmtCtx);
573 mlir::Value castTo =
574 builder.createConvert(loc, symTy, fir::getBase(initVal));
575 builder.create<fir::HasValueOp>(loc, castTo);
577 } else if (Fortran::lower::hasDefaultInitialization(sym)) {
578 Fortran::lower::createGlobalInitialization(
579 builder, global, [&](fir::FirOpBuilder &builder) {
580 Fortran::lower::StatementContext stmtCtx(
581 /*cleanupProhibited=*/true);
582 mlir::Value initVal =
583 genDefaultInitializerValue(converter, loc, sym, symTy, stmtCtx);
584 mlir::Value castTo = builder.createConvert(loc, symTy, initVal);
585 builder.create<fir::HasValueOp>(loc, castTo);
588 } else if (Fortran::semantics::IsProcedurePointer(sym)) {
589 const auto *details{sym.detailsIf<Fortran::semantics::ProcEntityDetails>()};
590 if (details && details->init()) {
591 auto sym{*details->init()};
592 if (sym) // Has a procedure target.
593 Fortran::lower::createGlobalInitialization(
594 builder, global, [&](fir::FirOpBuilder &b) {
595 Fortran::lower::StatementContext stmtCtx(
596 /*cleanupProhibited=*/true);
597 auto box{Fortran::lower::convertProcedureDesignatorInitialTarget(
598 converter, loc, *sym)};
599 auto castTo{builder.createConvert(loc, symTy, box)};
600 b.create<fir::HasValueOp>(loc, castTo);
602 else { // Has NULL() target.
603 Fortran::lower::createGlobalInitialization(
604 builder, global, [&](fir::FirOpBuilder &b) {
605 auto box{fir::factory::createNullBoxProc(b, loc, symTy)};
606 b.create<fir::HasValueOp>(loc, box);
609 } else {
610 // No initialization.
611 Fortran::lower::createGlobalInitialization(
612 builder, global, [&](fir::FirOpBuilder &b) {
613 auto box{fir::factory::createNullBoxProc(b, loc, symTy)};
614 b.create<fir::HasValueOp>(loc, box);
617 } else if (sym.has<Fortran::semantics::CommonBlockDetails>()) {
618 mlir::emitError(loc, "COMMON symbol processed elsewhere");
619 } else {
620 TODO(loc, "global"); // Something else
622 // Creates zero initializer for globals without initializers, this is a common
623 // and expected behavior (although not required by the standard)
624 if (!globalIsInitialized(global)) {
625 // Fortran does not provide means to specify that a BIND(C) module
626 // uninitialized variables will be defined in C.
627 // Add the common linkage to those to allow some level of support
628 // for this use case. Note that this use case will not work if the Fortran
629 // module code is placed in a shared library since, at least for the ELF
630 // format, common symbols are assigned a section in shared libraries.
631 // The best is still to declare C defined variables in a Fortran module file
632 // with no other definitions, and to never link the resulting module object
633 // file.
634 if (sym.attrs().test(Fortran::semantics::Attr::BIND_C))
635 global.setLinkName(builder.createCommonLinkage());
636 Fortran::lower::createGlobalInitialization(
637 builder, global, [&](fir::FirOpBuilder &builder) {
638 mlir::Value initValue = 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);
645 return global;
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);
682 } else {
683 cuf::DataAttributeAttr dataAttr =
684 Fortran::lower::translateSymbolCUFDataAttribute(builder.getContext(),
685 sym);
686 global = defineGlobal(converter, var, globalName, linkage, dataAttr);
688 auto addrOf = builder.create<fir::AddrOfOp>(loc, global.resultType(),
689 global.getSymbol());
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
700 /// constructed.
701 static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
702 mlir::Location loc,
703 const Fortran::lower::pft::Variable &var,
704 mlir::Value preAlloc,
705 llvm::ArrayRef<mlir::Value> shape = {},
706 llvm::ArrayRef<mlir::Value> lenParams = {}) {
707 if (preAlloc)
708 return preAlloc;
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(),
727 ultimateSymbol);
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);
738 return alloc;
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);
749 return res;
752 /// Must \p var be default initialized at runtime when entering its scope.
753 static bool
754 mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable &var) {
755 if (!var.hasSymbol())
756 return false;
757 const Fortran::semantics::Symbol &sym = var.getSymbol();
758 if (var.isGlobal())
759 // Global variables are statically initialized.
760 return false;
761 if (Fortran::semantics::IsDummy(sym) && !Fortran::semantics::IsIntentOut(sym))
762 return false;
763 // Polymorphic intent(out) dummy might need default initialization
764 // at runtime.
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))
770 return true;
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(),
788 fir::getBase(exv));
789 builder.genIfThen(loc, isPresent)
790 .genThen([&]() {
791 auto box = builder.createBox(loc, exv);
792 fir::runtime::genDerivedTypeInitialize(builder, loc, box);
794 .end();
795 } else {
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())
808 return std::nullopt;
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.
813 return std::nullopt;
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;
833 return std::nullopt;
836 /// Check whether a variable needs the be finalized according to clause 7.5.6.3
837 /// point 7.
838 /// Must be nonpointer, nonallocatable, INTENT (OUT) dummy argument.
839 static bool
840 needDummyIntentoutFinalization(const Fortran::lower::pft::Variable &var) {
841 if (!var.hasSymbol())
842 return false;
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))
848 return false;
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))
853 return true;
854 // Intent(out) dummies must be finalized at runtime if their type has a
855 // finalization.
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(),
873 fir::getBase(exv));
874 builder.genIfThen(loc, isPresent)
875 .genThen([&]() {
876 auto box = builder.createBox(loc, exv);
877 fir::runtime::genDerivedTypeDestroy(builder, loc, box);
879 .end();
880 } else {
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
891 // deallocated.
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())
899 return;
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
908 // deallocated.
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))
913 return;
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)
922 .genThen([&]() {
923 Fortran::lower::genDeallocateIfAllocated(converter, *mutBox, loc);
925 .end();
926 } else {
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(),
947 symMap);
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(),
957 *sym);
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);
967 switch (*cleanup) {
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);
973 break;
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>();
980 assert(mutableBox &&
981 "trying to deallocate entity not lowered as allocatable");
982 Fortran::lower::genDeallocateIfAllocated(*converterPtr, *mutableBox,
983 loc, sym);
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.
1005 static mlir::Value
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.
1023 static mlir::Type
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))
1049 return global;
1050 mlir::Location loc = converter.getCurrentLocation();
1051 mlir::Type aggTy = getAggregateType(converter, aggregate);
1052 if (!global)
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);
1067 return global;
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
1071 // of the linkage.
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);
1078 return global;
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))
1096 return global;
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.
1103 static void
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,
1121 linkage);
1122 } else {
1123 global =
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);
1134 return;
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);
1140 mlir::Value local =
1141 builder.allocateLocal(loc, seqTy, aggName, "", std::nullopt, std::nullopt,
1142 /*target=*/false);
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),
1155 aliasAddr);
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(),
1189 symMap);
1192 //===--------------------------------------------------------------===//
1193 // COMMON blocks instantiation
1194 //===--------------------------------------------------------------===//
1196 /// Does any member of the common block has an initializer ?
1197 static bool
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>())
1202 if (memDet->init())
1203 return true;
1205 return false;
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
1251 /// list.
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 =
1266 obj.symbol
1267 .detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
1268 const Fortran::semantics::Symbol *com =
1269 FindCommonBlockContaining(obj.symbol);
1270 if (!details->init() || com != &common)
1271 continue;
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);
1278 return members;
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.
1294 if (!global)
1295 fir::emitFatalError(converter.genLocation(common.name()),
1296 "COMMON block was not lowered before its usage");
1297 return global;
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);
1312 if (global)
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.
1325 const auto sz =
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) {
1370 ++tupIdx;
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));
1388 ++tupIdx;
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,
1406 mlir::Location>>
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);
1426 mlir::Value offs =
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
1439 /// the symbol map.
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();
1451 if (!commonAddr) {
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()))
1475 return false;
1476 // Non contiguous arrays must be tracked in an BoxValue.
1477 if (sym.Rank() > 0 && !Fortran::evaluate::IsSimplyContiguous(
1478 sym, converter.getFoldingContext()))
1479 return true;
1480 // Assumed rank and optional fir.box cannot yet be read while lowering the
1481 // specifications.
1482 if (Fortran::evaluate::IsAssumedRank(sym) ||
1483 Fortran::semantics::IsOptional(sym))
1484 return true;
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())
1489 return true;
1490 return false;
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())
1512 return;
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));
1518 return;
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.
1543 static void
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) {
1550 if (!box.isArray())
1551 return;
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));
1557 return;
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));
1566 else
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.
1578 static mlir::Value
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) {
1583 if (!box.isChar())
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
1591 // 7.4.4.2 point 5.
1592 return fir::factory::genMaxWithZero(
1593 builder, loc,
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;
1613 if (initVal) {
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
1617 : fst);
1618 return result;
1621 result.assign(shapeVec.begin(), shapeVec.end());
1622 return result;
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)
1662 return {};
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;
1705 if (len)
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(),
1712 sym);
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(
1718 loc, ptrBoxType,
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())
1734 lenParams.clear();
1736 // Inherit the shape (and maybe length parameters) from the pointee
1737 // declaration.
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
1746 // access.
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);
1750 return;
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,
1757 dataAttr);
1758 symMap.addVariableDefinition(sym, newBase, force);
1759 return;
1762 if (len) {
1763 if (!shape.empty()) {
1764 if (!lbounds.empty())
1765 symMap.addCharSymbolWithBounds(sym, base, len, shape, lbounds, force);
1766 else
1767 symMap.addCharSymbolWithShape(sym, base, len, shape, force);
1768 } else {
1769 symMap.addCharSymbol(sym, base, len, force);
1771 } else {
1772 if (!shape.empty()) {
1773 if (!lbounds.empty())
1774 symMap.addSymbolWithBounds(sym, base, shape, lbounds, force);
1775 else
1776 symMap.addSymbolWithShape(sym, base, shape, force);
1777 } else {
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,
1789 bool force) {
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(),
1805 sym.GetUltimate());
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);
1813 return;
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.
1820 static void
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);
1827 return;
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);
1868 return;
1870 symMap.addBoxSymbol(sym, box, lbounds, explicitParams, explicitExtents,
1871 replace);
1874 static unsigned getAllocatorIdx(const Fortran::semantics::Symbol &sym) {
1875 std::optional<Fortran::common::CUDADataAttr> cudaAttr =
1876 Fortran::semantics::GetCUDADataAttr(&sym.GetUltimate());
1877 if (cudaAttr) {
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)) {
1924 // global
1925 mlir::Value boxAlloc = preAlloc;
1926 // dummy or passed result
1927 if (!boxAlloc)
1928 if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
1929 boxAlloc = symbox.getAddr();
1930 // local
1931 if (!boxAlloc)
1932 boxAlloc = createNewLocal(converter, loc, var, preAlloc);
1933 genProcPointer(converter, symMap, sym, boxAlloc, replace);
1935 return;
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;
1943 ba.analyze(sym);
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.
1949 // global
1950 mlir::Value boxAlloc = preAlloc;
1951 // dummy or passed result
1952 if (!boxAlloc)
1953 if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym))
1954 boxAlloc = symbox.getAddr();
1955 assert((boxAlloc || !isAssumedRank) && "assumed-ranks cannot be local");
1956 // local
1957 if (!boxAlloc)
1958 boxAlloc = createNewLocal(converter, loc, var, preAlloc);
1959 // Lower non deferred parameters.
1960 llvm::SmallVector<mlir::Value> nonDeferredLenParams;
1961 if (ba.isChar()) {
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)
1973 TODO(loc,
1974 "derived type allocatable or pointer with length parameters");
1976 fir::MutableBoxValue box = Fortran::lower::createMutableBox(
1977 converter, loc, var, boxAlloc, nonDeferredLenParams,
1978 /*alwaysUseBox=*/
1979 converter.getLoweringOptions().getLowerToHighLevelFIR(),
1980 getAllocatorIdx(var.getSymbol()));
1981 genAllocatableOrPointerDeclare(converter, symMap, var.getSymbol(), box,
1982 replace);
1983 return;
1986 if (isDummy) {
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
1993 // extents if any.
1994 if (ba.isChar()) {
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);
2009 auto addrAndLen =
2010 builder
2011 .genIfOp(loc, {refTy, lenType}, isPresent,
2012 /*withElseRegion=*/true)
2013 .genThen([&]() {
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});
2021 .genElse([&] {
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});
2028 .getResults();
2029 addr = addrAndLen[0];
2030 len = addrAndLen[1];
2031 } else {
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);
2039 return;
2042 // TODO: derived type length parameters.
2043 if (!isAssumedRank) {
2044 lowerExplicitLowerBounds(converter, loc, ba, lbounds, symMap, stmtCtx);
2045 lowerExplicitExtents(converter, loc, ba, lbounds, explicitExtents,
2046 symMap, stmtCtx);
2048 genBoxDeclare(converter, symMap, sym, dummyArg, lbounds, explicitParams,
2049 explicitExtents, replace);
2050 return;
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) &&
2078 "handled above");
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(
2090 builder, loc,
2091 fir::factory::createTempMutableBox(builder, loc, ty, {}, {},
2092 isPolymorphic)),
2093 fir::FortranVariableFlagsEnum::None,
2094 converter.isRegisteredDummySymbol(sym));
2095 return true;
2097 return false;
2100 if (isAssumedRank) {
2101 assert(isUnusedEntryDummy && "assumed rank must be pointers/allocatables "
2102 "or descriptor dummy arguments");
2103 genUnusedEntryPointBox();
2104 return;
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");
2128 mlir::Value dim =
2129 builder.createIntegerConstant(loc, idxTy, iter.index());
2130 auto dimInfo =
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));
2135 } else {
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;
2147 mlir::Value ub, lb;
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");
2152 mlir::Value dim =
2153 builder.createIntegerConstant(loc, idxTy, iter.index());
2154 dimInfo =
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);
2161 } else {
2162 // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.)
2163 lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, 1));
2165 } else {
2166 if (auto low = spec->lbound().GetExplicit()) {
2167 auto expr = Fortran::lower::SomeExpr{*low};
2168 lb = builder.createConvert(loc, idxTy, genValue(expr));
2169 } else {
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));
2178 } else {
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
2189 // size arrays.
2190 // Lower the specification expressions.
2191 //===--------------------------------------------------------------===//
2193 mlir::Value len;
2194 llvm::SmallVector<mlir::Value> extents;
2195 llvm::SmallVector<mlir::Value> lbounds;
2196 auto arg = symMap.lookupSymbol(sym).getAddr();
2197 mlir::Value addr = preAlloc;
2199 if (arg)
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.
2207 if (ba.isChar()) {
2208 if (arg) {
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);
2216 } else if (!addr) {
2217 addr = arg;
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()) {
2226 // Static length
2227 len = builder.createIntegerConstant(loc, idxTy, *cstLen);
2228 } else {
2229 // Dynamic length
2230 if (genUnusedEntryPointBox())
2231 return;
2232 if (std::optional<Fortran::lower::SomeExpr> charLenExpr =
2233 ba.getCharLenExpr()) {
2234 // Explicit length
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);
2239 } else if (!len) {
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.
2250 if (ba.isArray()) {
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));
2256 } else {
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));
2264 } else {
2265 // Non compile time constant shape.
2266 if (genUnusedEntryPointBox())
2267 return;
2268 if (ba.lboundIsAllOnes())
2269 populateShape(extents, ba.dynamicBound(), arg);
2270 else
2271 populateLBoundsExtents(lbounds, extents, ba.dynamicBound(), arg);
2275 // Allocate or extract raw address for the entity
2276 if (!addr) {
2277 if (arg) {
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);
2286 if (isCptrByVal) {
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);
2291 } else {
2292 builder.createStoreWithConvert(loc, arg, addr);
2294 } else {
2295 // Dummy address, or address of result whose storage is passed by the
2296 // caller.
2297 assert(fir::isa_ref_type(argType) && "must be a memory address");
2298 addr = arg;
2300 } else {
2301 // Local variables
2302 llvm::SmallVector<mlir::Value> typeParams;
2303 if (len)
2304 typeParams.emplace_back(len);
2305 addr = createNewLocal(converter, loc, var, preAlloc, extents, typeParams);
2309 ::genDeclareSymbol(converter, symMap, sym, addr, len, extents, lbounds,
2310 replace);
2311 return;
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);
2329 return;
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.
2339 } else {
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))
2358 return;
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);
2371 else
2372 instantiateLocal(converter, var, symMap);
2375 static void
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);
2385 continue;
2387 const Fortran::semantics::Symbol &sym = var.getSymbol();
2388 if (&sym == &interfaceSymbol)
2389 continue;
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.
2407 continue;
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
2419 // properties.
2420 instantiateVariable(converter, var, symMap, storeMap);
2424 void Fortran::lower::mapCallInterfaceSymbolsForResult(
2425 AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
2426 SymMap &symMap) {
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,
2442 preAlloc);
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));