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/ 10 // 11 //===----------------------------------------------------------------------===// 12 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/ConvertExpr.h" 19 #include "flang/Lower/IntrinsicCall.h" 20 #include "flang/Lower/Mangler.h" 21 #include "flang/Lower/PFTBuilder.h" 22 #include "flang/Lower/StatementContext.h" 23 #include "flang/Lower/Support/Utils.h" 24 #include "flang/Lower/SymbolMap.h" 25 #include "flang/Optimizer/Builder/Character.h" 26 #include "flang/Optimizer/Builder/FIRBuilder.h" 27 #include "flang/Optimizer/Builder/Runtime/Derived.h" 28 #include "flang/Optimizer/Builder/Todo.h" 29 #include "flang/Optimizer/Dialect/FIRAttr.h" 30 #include "flang/Optimizer/Dialect/FIRDialect.h" 31 #include "flang/Optimizer/Dialect/FIROps.h" 32 #include "flang/Optimizer/Support/FIRContext.h" 33 #include "flang/Optimizer/Support/FatalError.h" 34 #include "flang/Semantics/runtime-type-info.h" 35 #include "flang/Semantics/tools.h" 36 #include "llvm/Support/Debug.h" 37 38 #define DEBUG_TYPE "flang-lower-variable" 39 40 /// Helper to lower a scalar expression using a specific symbol mapping. 41 static mlir::Value genScalarValue(Fortran::lower::AbstractConverter &converter, 42 mlir::Location loc, 43 const Fortran::lower::SomeExpr &expr, 44 Fortran::lower::SymMap &symMap, 45 Fortran::lower::StatementContext &context) { 46 // This does not use the AbstractConverter member function to override the 47 // symbol mapping to be used expression lowering. 48 return fir::getBase(Fortran::lower::createSomeExtendedExpression( 49 loc, converter, expr, symMap, context)); 50 } 51 /// Does this variable have a default initialization? 52 static bool hasDefaultInitialization(const Fortran::semantics::Symbol &sym) { 53 if (sym.has<Fortran::semantics::ObjectEntityDetails>() && sym.size()) 54 if (!Fortran::semantics::IsAllocatableOrPointer(sym)) 55 if (const Fortran::semantics::DeclTypeSpec *declTypeSpec = sym.GetType()) 56 if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec = 57 declTypeSpec->AsDerived()) 58 return derivedTypeSpec->HasDefaultInitialization(); 59 return false; 60 } 61 62 //===----------------------------------------------------------------===// 63 // Global variables instantiation (not for alias and common) 64 //===----------------------------------------------------------------===// 65 66 /// Helper to generate expression value inside global initializer. 67 static fir::ExtendedValue 68 genInitializerExprValue(Fortran::lower::AbstractConverter &converter, 69 mlir::Location loc, 70 const Fortran::lower::SomeExpr &expr, 71 Fortran::lower::StatementContext &stmtCtx) { 72 // Data initializer are constant value and should not depend on other symbols 73 // given the front-end fold parameter references. In any case, the "current" 74 // map of the converter should not be used since it holds mapping to 75 // mlir::Value from another mlir region. If these value are used by accident 76 // in the initializer, this will lead to segfaults in mlir code. 77 Fortran::lower::SymMap emptyMap; 78 return Fortran::lower::createSomeInitializerExpression(loc, converter, expr, 79 emptyMap, stmtCtx); 80 } 81 82 /// Can this symbol constant be placed in read-only memory? 83 static bool isConstant(const Fortran::semantics::Symbol &sym) { 84 return sym.attrs().test(Fortran::semantics::Attr::PARAMETER) || 85 sym.test(Fortran::semantics::Symbol::Flag::ReadOnly); 86 } 87 88 /// Is this a compiler generated symbol to describe derived types ? 89 static bool isRuntimeTypeInfoData(const Fortran::semantics::Symbol &sym) { 90 // So far, use flags to detect if this symbol were generated during 91 // semantics::BuildRuntimeDerivedTypeTables(). Scope cannot be used since the 92 // symbols are injected in the user scopes defining the described derived 93 // types. A robustness improvement for this test could be to get hands on the 94 // semantics::RuntimeDerivedTypeTables and to check if the symbol names 95 // belongs to this structure. 96 return sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated) && 97 sym.test(Fortran::semantics::Symbol::Flag::ReadOnly); 98 } 99 100 static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter, 101 const Fortran::lower::pft::Variable &var, 102 llvm::StringRef globalName, 103 mlir::StringAttr linkage); 104 105 static mlir::Location genLocation(Fortran::lower::AbstractConverter &converter, 106 const Fortran::semantics::Symbol &sym) { 107 // Compiler generated name cannot be used as source location, their name 108 // is not pointing to the source files. 109 if (!sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated)) 110 return converter.genLocation(sym.name()); 111 return converter.getCurrentLocation(); 112 } 113 114 /// Create the global op declaration without any initializer 115 static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter, 116 const Fortran::lower::pft::Variable &var, 117 llvm::StringRef globalName, 118 mlir::StringAttr linkage) { 119 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 120 if (fir::GlobalOp global = builder.getNamedGlobal(globalName)) 121 return global; 122 // Always define linkonce data since it may be optimized out from the module 123 // that actually owns the variable if it does not refers to it. 124 if (linkage == builder.createLinkOnceODRLinkage() || 125 linkage == builder.createLinkOnceLinkage()) 126 return defineGlobal(converter, var, globalName, linkage); 127 const Fortran::semantics::Symbol &sym = var.getSymbol(); 128 mlir::Location loc = genLocation(converter, sym); 129 // Resolve potential host and module association before checking that this 130 // symbol is an object of a function pointer. 131 const Fortran::semantics::Symbol &ultimate = sym.GetUltimate(); 132 if (!ultimate.has<Fortran::semantics::ObjectEntityDetails>() && 133 !Fortran::semantics::IsProcedurePointer(ultimate)) 134 mlir::emitError(loc, "processing global declaration: symbol '") 135 << toStringRef(sym.name()) << "' has unexpected details\n"; 136 return builder.createGlobal(loc, converter.genType(var), globalName, linkage, 137 mlir::Attribute{}, isConstant(ultimate)); 138 } 139 140 /// Temporary helper to catch todos in initial data target lowering. 141 static bool 142 hasDerivedTypeWithLengthParameters(const Fortran::semantics::Symbol &sym) { 143 if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) 144 if (const Fortran::semantics::DerivedTypeSpec *derived = 145 declTy->AsDerived()) 146 return Fortran::semantics::CountLenParameters(*derived) > 0; 147 return false; 148 } 149 150 static mlir::Type unwrapElementType(mlir::Type type) { 151 if (mlir::Type ty = fir::dyn_cast_ptrOrBoxEleTy(type)) 152 type = ty; 153 if (auto seqType = type.dyn_cast<fir::SequenceType>()) 154 type = seqType.getEleTy(); 155 return type; 156 } 157 158 fir::ExtendedValue Fortran::lower::genExtAddrInInitializer( 159 Fortran::lower::AbstractConverter &converter, mlir::Location loc, 160 const Fortran::lower::SomeExpr &addr) { 161 Fortran::lower::SymMap globalOpSymMap; 162 Fortran::lower::AggregateStoreMap storeMap; 163 Fortran::lower::StatementContext stmtCtx; 164 if (const Fortran::semantics::Symbol *sym = 165 Fortran::evaluate::GetFirstSymbol(addr)) { 166 // Length parameters processing will need care in global initializer 167 // context. 168 if (hasDerivedTypeWithLengthParameters(*sym)) 169 TODO(loc, "initial-data-target with derived type length parameters"); 170 171 auto var = Fortran::lower::pft::Variable(*sym, /*global=*/true); 172 Fortran::lower::instantiateVariable(converter, var, globalOpSymMap, 173 storeMap); 174 } 175 return Fortran::lower::createInitializerAddress(loc, converter, addr, 176 globalOpSymMap, stmtCtx); 177 } 178 179 /// create initial-data-target fir.box in a global initializer region. 180 mlir::Value Fortran::lower::genInitialDataTarget( 181 Fortran::lower::AbstractConverter &converter, mlir::Location loc, 182 mlir::Type boxType, const Fortran::lower::SomeExpr &initialTarget) { 183 Fortran::lower::SymMap globalOpSymMap; 184 Fortran::lower::AggregateStoreMap storeMap; 185 Fortran::lower::StatementContext stmtCtx; 186 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 187 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>( 188 initialTarget)) 189 return fir::factory::createUnallocatedBox(builder, loc, boxType, 190 /*nonDeferredParams=*/llvm::None); 191 // Pointer initial data target, and NULL(mold). 192 if (const Fortran::semantics::Symbol *sym = 193 Fortran::evaluate::GetFirstSymbol(initialTarget)) { 194 // Length parameters processing will need care in global initializer 195 // context. 196 if (hasDerivedTypeWithLengthParameters(*sym)) 197 TODO(loc, "initial-data-target with derived type length parameters"); 198 199 auto var = Fortran::lower::pft::Variable(*sym, /*global=*/true); 200 Fortran::lower::instantiateVariable(converter, var, globalOpSymMap, 201 storeMap); 202 } 203 mlir::Value box; 204 if (initialTarget.Rank() > 0) { 205 box = fir::getBase(Fortran::lower::createSomeArrayBox( 206 converter, initialTarget, globalOpSymMap, stmtCtx)); 207 } else { 208 fir::ExtendedValue addr = Fortran::lower::createInitializerAddress( 209 loc, converter, initialTarget, globalOpSymMap, stmtCtx); 210 box = builder.createBox(loc, addr); 211 } 212 // box is a fir.box<T>, not a fir.box<fir.ptr<T>> as it should to be used 213 // for pointers. A fir.convert should not be used here, because it would 214 // not actually set the pointer attribute in the descriptor. 215 // In a normal context, fir.rebox would be used to set the pointer attribute 216 // while copying the projection from another fir.box. But fir.rebox cannot be 217 // used in initializer because its current codegen expects that the input 218 // fir.box is in memory, which is not the case in initializers. 219 // So, just replace the fir.embox that created addr with one with 220 // fir.box<fir.ptr<T>> result type. 221 // Note that the descriptor cannot have been created with fir.rebox because 222 // the initial-data-target cannot be a fir.box itself (it cannot be 223 // assumed-shape, deferred-shape, or polymorphic as per C765). However the 224 // case where the initial data target is a derived type with length parameters 225 // will most likely be a bit trickier, hence the TODO above. 226 227 mlir::Operation *op = box.getDefiningOp(); 228 if (!op || !mlir::isa<fir::EmboxOp>(*op)) 229 fir::emitFatalError( 230 loc, "fir.box must be created with embox in global initializers"); 231 mlir::Type targetEleTy = unwrapElementType(box.getType()); 232 if (!fir::isa_char(targetEleTy)) 233 return builder.create<fir::EmboxOp>(loc, boxType, op->getOperands(), 234 op->getAttrs()); 235 236 // Handle the character case length particularities: embox takes a length 237 // value argument when the result type has unknown length, but not when the 238 // result type has constant length. The type of the initial target must be 239 // constant length, but the one of the pointer may not be. In this case, a 240 // length operand must be added. 241 auto targetLen = targetEleTy.cast<fir::CharacterType>().getLen(); 242 auto ptrLen = unwrapElementType(boxType).cast<fir::CharacterType>().getLen(); 243 if (ptrLen == targetLen) 244 // Nothing to do 245 return builder.create<fir::EmboxOp>(loc, boxType, op->getOperands(), 246 op->getAttrs()); 247 auto embox = mlir::cast<fir::EmboxOp>(*op); 248 auto ptrType = boxType.cast<fir::BoxType>().getEleTy(); 249 mlir::Value memref = builder.createConvert(loc, ptrType, embox.getMemref()); 250 if (targetLen == fir::CharacterType::unknownLen()) 251 // Drop the length argument. 252 return builder.create<fir::EmboxOp>(loc, boxType, memref, embox.getShape(), 253 embox.getSlice()); 254 // targetLen is constant and ptrLen is unknown. Add a length argument. 255 mlir::Value targetLenValue = 256 builder.createIntegerConstant(loc, builder.getIndexType(), targetLen); 257 return builder.create<fir::EmboxOp>(loc, boxType, memref, embox.getShape(), 258 embox.getSlice(), 259 mlir::ValueRange{targetLenValue}); 260 } 261 262 static mlir::Value genDefaultInitializerValue( 263 Fortran::lower::AbstractConverter &converter, mlir::Location loc, 264 const Fortran::semantics::Symbol &sym, mlir::Type symTy, 265 Fortran::lower::StatementContext &stmtCtx) { 266 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 267 mlir::Type scalarType = symTy; 268 fir::SequenceType sequenceType; 269 if (auto ty = symTy.dyn_cast<fir::SequenceType>()) { 270 sequenceType = ty; 271 scalarType = ty.getEleTy(); 272 } 273 // Build a scalar default value of the symbol type, looping through the 274 // components to build each component initial value. 275 auto recTy = scalarType.cast<fir::RecordType>(); 276 auto fieldTy = fir::FieldType::get(scalarType.getContext()); 277 mlir::Value initialValue = builder.create<fir::UndefOp>(loc, scalarType); 278 const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType(); 279 assert(declTy && "var with default initialization must have a type"); 280 Fortran::semantics::OrderedComponentIterator components( 281 declTy->derivedTypeSpec()); 282 for (const auto &component : components) { 283 // Skip parent components, the sub-components of parent types are part of 284 // components and will be looped through right after. 285 if (component.test(Fortran::semantics::Symbol::Flag::ParentComp)) 286 continue; 287 mlir::Value componentValue; 288 llvm::StringRef name = toStringRef(component.name()); 289 mlir::Type componentTy = recTy.getType(name); 290 assert(componentTy && "component not found in type"); 291 if (const auto *object{ 292 component.detailsIf<Fortran::semantics::ObjectEntityDetails>()}) { 293 if (const auto &init = object->init()) { 294 // Component has explicit initialization. 295 if (Fortran::semantics::IsPointer(component)) 296 // Initial data target. 297 componentValue = 298 genInitialDataTarget(converter, loc, componentTy, *init); 299 else 300 // Initial value. 301 componentValue = fir::getBase( 302 genInitializerExprValue(converter, loc, *init, stmtCtx)); 303 } else if (Fortran::semantics::IsAllocatableOrPointer(component)) { 304 // Pointer or allocatable without initialization. 305 // Create deallocated/disassociated value. 306 // From a standard point of view, pointer without initialization do not 307 // need to be disassociated, but for sanity and simplicity, do it in 308 // global constructor since this has no runtime cost. 309 componentValue = fir::factory::createUnallocatedBox( 310 builder, loc, componentTy, llvm::None); 311 } else if (hasDefaultInitialization(component)) { 312 // Component type has default initialization. 313 componentValue = genDefaultInitializerValue(converter, loc, component, 314 componentTy, stmtCtx); 315 } else { 316 // Component has no initial value. 317 componentValue = builder.create<fir::UndefOp>(loc, componentTy); 318 } 319 } else if (const auto *proc{ 320 component 321 .detailsIf<Fortran::semantics::ProcEntityDetails>()}) { 322 if (proc->init().has_value()) 323 TODO(loc, "procedure pointer component default initialization"); 324 else 325 componentValue = builder.create<fir::UndefOp>(loc, componentTy); 326 } 327 assert(componentValue && "must have been computed"); 328 componentValue = builder.createConvert(loc, componentTy, componentValue); 329 // FIXME: type parameters must come from the derived-type-spec 330 auto field = builder.create<fir::FieldIndexOp>( 331 loc, fieldTy, name, scalarType, 332 /*typeParams=*/mlir::ValueRange{} /*TODO*/); 333 initialValue = builder.create<fir::InsertValueOp>( 334 loc, recTy, initialValue, componentValue, 335 builder.getArrayAttr(field.getAttributes())); 336 } 337 338 if (sequenceType) { 339 // For arrays, duplicate the scalar value to all elements with an 340 // fir.insert_range covering the whole array. 341 auto arrayInitialValue = builder.create<fir::UndefOp>(loc, sequenceType); 342 llvm::SmallVector<int64_t> rangeBounds; 343 for (int64_t extent : sequenceType.getShape()) { 344 if (extent == fir::SequenceType::getUnknownExtent()) 345 TODO(loc, 346 "default initial value of array component with length parameters"); 347 rangeBounds.push_back(0); 348 rangeBounds.push_back(extent - 1); 349 } 350 return builder.create<fir::InsertOnRangeOp>( 351 loc, sequenceType, arrayInitialValue, initialValue, 352 builder.getIndexVectorAttr(rangeBounds)); 353 } 354 return initialValue; 355 } 356 357 /// Does this global already have an initializer ? 358 static bool globalIsInitialized(fir::GlobalOp global) { 359 return !global.getRegion().empty() || global.getInitVal(); 360 } 361 362 /// Call \p genInit to generate code inside \p global initializer region. 363 static void 364 createGlobalInitialization(fir::FirOpBuilder &builder, fir::GlobalOp global, 365 std::function<void(fir::FirOpBuilder &)> genInit) { 366 mlir::Region ®ion = global.getRegion(); 367 region.push_back(new mlir::Block); 368 mlir::Block &block = region.back(); 369 auto insertPt = builder.saveInsertionPoint(); 370 builder.setInsertionPointToStart(&block); 371 genInit(builder); 372 builder.restoreInsertionPoint(insertPt); 373 } 374 375 /// Create the global op and its init if it has one 376 static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter, 377 const Fortran::lower::pft::Variable &var, 378 llvm::StringRef globalName, 379 mlir::StringAttr linkage) { 380 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 381 const Fortran::semantics::Symbol &sym = var.getSymbol(); 382 mlir::Location loc = genLocation(converter, sym); 383 bool isConst = isConstant(sym); 384 fir::GlobalOp global = builder.getNamedGlobal(globalName); 385 mlir::Type symTy = converter.genType(var); 386 387 if (global && globalIsInitialized(global)) 388 return global; 389 390 if (Fortran::semantics::IsProcedurePointer(sym)) 391 TODO(loc, "procedure pointer globals"); 392 393 // If this is an array, check to see if we can use a dense attribute 394 // with a tensor mlir type. This optimization currently only supports 395 // rank-1 Fortran arrays of integer, real, or logical. The tensor 396 // type does not support nested structures which are needed for 397 // complex numbers. 398 // To get multidimensional arrays to work, we will have to use column major 399 // array ordering with the tensor type (so it matches column major ordering 400 // with the Fortran fir.array). By default, tensor types assume row major 401 // ordering. How to create this tensor type is to be determined. 402 if (symTy.isa<fir::SequenceType>() && sym.Rank() == 1 && 403 !Fortran::semantics::IsAllocatableOrPointer(sym)) { 404 mlir::Type eleTy = symTy.cast<fir::SequenceType>().getEleTy(); 405 if (eleTy.isa<mlir::IntegerType, mlir::FloatType, fir::LogicalType>()) { 406 const auto *details = 407 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>(); 408 if (details->init()) { 409 global = Fortran::lower::createDenseGlobal( 410 loc, symTy, globalName, linkage, isConst, details->init().value(), 411 converter); 412 if (global) { 413 global.setVisibility(mlir::SymbolTable::Visibility::Public); 414 return global; 415 } 416 } 417 } 418 } 419 if (!global) 420 global = builder.createGlobal(loc, symTy, globalName, linkage, 421 mlir::Attribute{}, isConst); 422 if (Fortran::semantics::IsAllocatableOrPointer(sym)) { 423 const auto *details = 424 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>(); 425 if (details && details->init()) { 426 auto expr = *details->init(); 427 createGlobalInitialization(builder, global, [&](fir::FirOpBuilder &b) { 428 mlir::Value box = 429 Fortran::lower::genInitialDataTarget(converter, loc, symTy, expr); 430 b.create<fir::HasValueOp>(loc, box); 431 }); 432 } else { 433 // Create unallocated/disassociated descriptor if no explicit init 434 createGlobalInitialization(builder, global, [&](fir::FirOpBuilder &b) { 435 mlir::Value box = 436 fir::factory::createUnallocatedBox(b, loc, symTy, llvm::None); 437 b.create<fir::HasValueOp>(loc, box); 438 }); 439 } 440 441 } else if (const auto *details = 442 sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) { 443 if (details->init()) { 444 createGlobalInitialization( 445 builder, global, [&](fir::FirOpBuilder &builder) { 446 Fortran::lower::StatementContext stmtCtx( 447 /*cleanupProhibited=*/true); 448 fir::ExtendedValue initVal = genInitializerExprValue( 449 converter, loc, details->init().value(), stmtCtx); 450 mlir::Value castTo = 451 builder.createConvert(loc, symTy, fir::getBase(initVal)); 452 builder.create<fir::HasValueOp>(loc, castTo); 453 }); 454 } else if (hasDefaultInitialization(sym)) { 455 createGlobalInitialization( 456 builder, global, [&](fir::FirOpBuilder &builder) { 457 Fortran::lower::StatementContext stmtCtx( 458 /*cleanupProhibited=*/true); 459 mlir::Value initVal = 460 genDefaultInitializerValue(converter, loc, sym, symTy, stmtCtx); 461 mlir::Value castTo = builder.createConvert(loc, symTy, initVal); 462 builder.create<fir::HasValueOp>(loc, castTo); 463 }); 464 } 465 } else if (sym.has<Fortran::semantics::CommonBlockDetails>()) { 466 mlir::emitError(loc, "COMMON symbol processed elsewhere"); 467 } else { 468 TODO(loc, "global"); // Procedure pointer or something else 469 } 470 // Creates undefined initializer for globals without initializers 471 if (!globalIsInitialized(global)) { 472 // TODO: Is it really required to add the undef init if the Public 473 // visibility is set ? We need to make sure the global is not optimized out 474 // by LLVM if unused in the current compilation unit, but at least for 475 // BIND(C) variables, an initial value may be given in another compilation 476 // unit (on the C side), and setting an undef init here creates linkage 477 // conflicts. 478 if (sym.attrs().test(Fortran::semantics::Attr::BIND_C)) 479 TODO(loc, "BIND(C) module variable linkage"); 480 createGlobalInitialization( 481 builder, global, [&](fir::FirOpBuilder &builder) { 482 builder.create<fir::HasValueOp>( 483 loc, builder.create<fir::UndefOp>(loc, symTy)); 484 }); 485 } 486 // Set public visibility to prevent global definition to be optimized out 487 // even if they have no initializer and are unused in this compilation unit. 488 global.setVisibility(mlir::SymbolTable::Visibility::Public); 489 return global; 490 } 491 492 /// Return linkage attribute for \p var. 493 static mlir::StringAttr 494 getLinkageAttribute(fir::FirOpBuilder &builder, 495 const Fortran::lower::pft::Variable &var) { 496 // Runtime type info for a same derived type is identical in each compilation 497 // unit. It desired to avoid having to link against module that only define a 498 // type. Therefore the runtime type info is generated everywhere it is needed 499 // with `linkonce_odr` LLVM linkage. 500 if (var.hasSymbol() && isRuntimeTypeInfoData(var.getSymbol())) 501 return builder.createLinkOnceODRLinkage(); 502 if (var.isModuleVariable()) 503 return {}; // external linkage 504 // Otherwise, the variable is owned by a procedure and must not be visible in 505 // other compilation units. 506 return builder.createInternalLinkage(); 507 } 508 509 /// Instantiate a global variable. If it hasn't already been processed, add 510 /// the global to the ModuleOp as a new uniqued symbol and initialize it with 511 /// the correct value. It will be referenced on demand using `fir.addr_of`. 512 static void instantiateGlobal(Fortran::lower::AbstractConverter &converter, 513 const Fortran::lower::pft::Variable &var, 514 Fortran::lower::SymMap &symMap) { 515 const Fortran::semantics::Symbol &sym = var.getSymbol(); 516 assert(!var.isAlias() && "must be handled in instantiateAlias"); 517 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 518 std::string globalName = Fortran::lower::mangle::mangleName(sym); 519 mlir::Location loc = genLocation(converter, sym); 520 fir::GlobalOp global = builder.getNamedGlobal(globalName); 521 mlir::StringAttr linkage = getLinkageAttribute(builder, var); 522 if (var.isModuleVariable()) { 523 // A module global was or will be defined when lowering the module. Emit 524 // only a declaration if the global does not exist at that point. 525 global = declareGlobal(converter, var, globalName, linkage); 526 } else { 527 global = defineGlobal(converter, var, globalName, linkage); 528 } 529 auto addrOf = builder.create<fir::AddrOfOp>(loc, global.resultType(), 530 global.getSymbol()); 531 Fortran::lower::StatementContext stmtCtx; 532 mapSymbolAttributes(converter, var, symMap, stmtCtx, addrOf); 533 } 534 535 //===----------------------------------------------------------------===// 536 // Local variables instantiation (not for alias) 537 //===----------------------------------------------------------------===// 538 539 /// Create a stack slot for a local variable. Precondition: the insertion 540 /// point of the builder must be in the entry block, which is currently being 541 /// constructed. 542 static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter, 543 mlir::Location loc, 544 const Fortran::lower::pft::Variable &var, 545 mlir::Value preAlloc, 546 llvm::ArrayRef<mlir::Value> shape = {}, 547 llvm::ArrayRef<mlir::Value> lenParams = {}) { 548 if (preAlloc) 549 return preAlloc; 550 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 551 std::string nm = Fortran::lower::mangle::mangleName(var.getSymbol()); 552 mlir::Type ty = converter.genType(var); 553 const Fortran::semantics::Symbol &ultimateSymbol = 554 var.getSymbol().GetUltimate(); 555 llvm::StringRef symNm = toStringRef(ultimateSymbol.name()); 556 bool isTarg = var.isTarget(); 557 // Let the builder do all the heavy lifting. 558 return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg); 559 } 560 561 /// Must \p var be default initialized at runtime when entering its scope. 562 static bool 563 mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable &var) { 564 if (!var.hasSymbol()) 565 return false; 566 const Fortran::semantics::Symbol &sym = var.getSymbol(); 567 if (var.isGlobal()) 568 // Global variables are statically initialized. 569 return false; 570 if (Fortran::semantics::IsDummy(sym) && !Fortran::semantics::IsIntentOut(sym)) 571 return false; 572 // Local variables (including function results), and intent(out) dummies must 573 // be default initialized at runtime if their type has default initialization. 574 return hasDefaultInitialization(sym); 575 } 576 577 /// Call default initialization runtime routine to initialize \p var. 578 static void 579 defaultInitializeAtRuntime(Fortran::lower::AbstractConverter &converter, 580 const Fortran::lower::pft::Variable &var, 581 Fortran::lower::SymMap &symMap) { 582 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 583 mlir::Location loc = converter.getCurrentLocation(); 584 const Fortran::semantics::Symbol &sym = var.getSymbol(); 585 fir::ExtendedValue exv = symMap.lookupSymbol(sym).toExtendedValue(); 586 if (Fortran::semantics::IsOptional(sym)) { 587 // 15.5.2.12 point 3, absent optional dummies are not initialized. 588 // Creating descriptor/passing null descriptor to the runtime would 589 // create runtime crashes. 590 auto isPresent = builder.create<fir::IsPresentOp>(loc, builder.getI1Type(), 591 fir::getBase(exv)); 592 builder.genIfThen(loc, isPresent) 593 .genThen([&]() { 594 auto box = builder.createBox(loc, exv); 595 fir::runtime::genDerivedTypeInitialize(builder, loc, box); 596 }) 597 .end(); 598 } else { 599 mlir::Value box = builder.createBox(loc, exv); 600 fir::runtime::genDerivedTypeInitialize(builder, loc, box); 601 } 602 } 603 604 /// Instantiate a local variable. Precondition: Each variable will be visited 605 /// such that if its properties depend on other variables, the variables upon 606 /// which its properties depend will already have been visited. 607 static void instantiateLocal(Fortran::lower::AbstractConverter &converter, 608 const Fortran::lower::pft::Variable &var, 609 Fortran::lower::SymMap &symMap) { 610 assert(!var.isAlias()); 611 Fortran::lower::StatementContext stmtCtx; 612 mapSymbolAttributes(converter, var, symMap, stmtCtx); 613 if (mustBeDefaultInitializedAtRuntime(var)) 614 defaultInitializeAtRuntime(converter, var, symMap); 615 } 616 617 //===----------------------------------------------------------------===// 618 // Aliased (EQUIVALENCE) variables instantiation 619 //===----------------------------------------------------------------===// 620 621 /// Insert \p aggregateStore instance into an AggregateStoreMap. 622 static void insertAggregateStore(Fortran::lower::AggregateStoreMap &storeMap, 623 const Fortran::lower::pft::Variable &var, 624 mlir::Value aggregateStore) { 625 std::size_t off = var.getAggregateStore().getOffset(); 626 Fortran::lower::AggregateStoreKey key = {var.getOwningScope(), off}; 627 storeMap[key] = aggregateStore; 628 } 629 630 /// Retrieve the aggregate store instance of \p alias from an 631 /// AggregateStoreMap. 632 static mlir::Value 633 getAggregateStore(Fortran::lower::AggregateStoreMap &storeMap, 634 const Fortran::lower::pft::Variable &alias) { 635 Fortran::lower::AggregateStoreKey key = {alias.getOwningScope(), 636 alias.getAlias()}; 637 auto iter = storeMap.find(key); 638 assert(iter != storeMap.end()); 639 return iter->second; 640 } 641 642 /// Build the name for the storage of a global equivalence. 643 static std::string mangleGlobalAggregateStore( 644 const Fortran::lower::pft::Variable::AggregateStore &st) { 645 return Fortran::lower::mangle::mangleName(st.getNamingSymbol()); 646 } 647 648 /// Build the type for the storage of an equivalence. 649 static mlir::Type 650 getAggregateType(Fortran::lower::AbstractConverter &converter, 651 const Fortran::lower::pft::Variable::AggregateStore &st) { 652 if (const Fortran::semantics::Symbol *initSym = st.getInitialValueSymbol()) 653 return converter.genType(*initSym); 654 mlir::IntegerType byteTy = converter.getFirOpBuilder().getIntegerType(8); 655 return fir::SequenceType::get(std::get<1>(st.interval), byteTy); 656 } 657 658 /// Define a GlobalOp for the storage of a global equivalence described 659 /// by \p aggregate. The global is named \p aggName and is created with 660 /// the provided \p linkage. 661 /// If any of the equivalence members are initialized, an initializer is 662 /// created for the equivalence. 663 /// This is to be used when lowering the scope that owns the equivalence 664 /// (as opposed to simply using it through host or use association). 665 /// This is not to be used for equivalence of common block members (they 666 /// already have the common block GlobalOp for them, see defineCommonBlock). 667 static fir::GlobalOp defineGlobalAggregateStore( 668 Fortran::lower::AbstractConverter &converter, 669 const Fortran::lower::pft::Variable::AggregateStore &aggregate, 670 llvm::StringRef aggName, mlir::StringAttr linkage) { 671 assert(aggregate.isGlobal() && "not a global interval"); 672 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 673 fir::GlobalOp global = builder.getNamedGlobal(aggName); 674 if (global && globalIsInitialized(global)) 675 return global; 676 mlir::Location loc = converter.getCurrentLocation(); 677 mlir::Type aggTy = getAggregateType(converter, aggregate); 678 if (!global) 679 global = builder.createGlobal(loc, aggTy, aggName, linkage); 680 681 if (const Fortran::semantics::Symbol *initSym = 682 aggregate.getInitialValueSymbol()) 683 if (const auto *objectDetails = 684 initSym->detailsIf<Fortran::semantics::ObjectEntityDetails>()) 685 if (objectDetails->init()) { 686 createGlobalInitialization( 687 builder, global, [&](fir::FirOpBuilder &builder) { 688 Fortran::lower::StatementContext stmtCtx; 689 mlir::Value initVal = fir::getBase(genInitializerExprValue( 690 converter, loc, objectDetails->init().value(), stmtCtx)); 691 builder.create<fir::HasValueOp>(loc, initVal); 692 }); 693 return global; 694 } 695 // Equivalence has no Fortran initial value. Create an undefined FIR initial 696 // value to ensure this is consider an object definition in the IR regardless 697 // of the linkage. 698 createGlobalInitialization(builder, global, [&](fir::FirOpBuilder &builder) { 699 Fortran::lower::StatementContext stmtCtx; 700 mlir::Value initVal = builder.create<fir::UndefOp>(loc, aggTy); 701 builder.create<fir::HasValueOp>(loc, initVal); 702 }); 703 return global; 704 } 705 706 /// Declare a GlobalOp for the storage of a global equivalence described 707 /// by \p aggregate. The global is named \p aggName and is created with 708 /// the provided \p linkage. 709 /// No initializer is built for the created GlobalOp. 710 /// This is to be used when lowering the scope that uses members of an 711 /// equivalence it through host or use association. 712 /// This is not to be used for equivalence of common block members (they 713 /// already have the common block GlobalOp for them, see defineCommonBlock). 714 static fir::GlobalOp declareGlobalAggregateStore( 715 Fortran::lower::AbstractConverter &converter, mlir::Location loc, 716 const Fortran::lower::pft::Variable::AggregateStore &aggregate, 717 llvm::StringRef aggName, mlir::StringAttr linkage) { 718 assert(aggregate.isGlobal() && "not a global interval"); 719 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 720 if (fir::GlobalOp global = builder.getNamedGlobal(aggName)) 721 return global; 722 mlir::Type aggTy = getAggregateType(converter, aggregate); 723 return builder.createGlobal(loc, aggTy, aggName, linkage); 724 } 725 726 /// This is an aggregate store for a set of EQUIVALENCED variables. Create the 727 /// storage on the stack or global memory and add it to the map. 728 static void 729 instantiateAggregateStore(Fortran::lower::AbstractConverter &converter, 730 const Fortran::lower::pft::Variable &var, 731 Fortran::lower::AggregateStoreMap &storeMap) { 732 assert(var.isAggregateStore() && "not an interval"); 733 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 734 mlir::IntegerType i8Ty = builder.getIntegerType(8); 735 mlir::Location loc = converter.getCurrentLocation(); 736 std::string aggName = mangleGlobalAggregateStore(var.getAggregateStore()); 737 if (var.isGlobal()) { 738 fir::GlobalOp global; 739 auto &aggregate = var.getAggregateStore(); 740 mlir::StringAttr linkage = getLinkageAttribute(builder, var); 741 if (var.isModuleVariable()) { 742 // A module global was or will be defined when lowering the module. Emit 743 // only a declaration if the global does not exist at that point. 744 global = declareGlobalAggregateStore(converter, loc, aggregate, aggName, 745 linkage); 746 } else { 747 global = 748 defineGlobalAggregateStore(converter, aggregate, aggName, linkage); 749 } 750 auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(), 751 global.getSymbol()); 752 auto size = std::get<1>(var.getInterval()); 753 fir::SequenceType::Shape shape(1, size); 754 auto seqTy = fir::SequenceType::get(shape, i8Ty); 755 mlir::Type refTy = builder.getRefType(seqTy); 756 mlir::Value aggregateStore = builder.createConvert(loc, refTy, addr); 757 insertAggregateStore(storeMap, var, aggregateStore); 758 return; 759 } 760 // This is a local aggregate, allocate an anonymous block of memory. 761 auto size = std::get<1>(var.getInterval()); 762 fir::SequenceType::Shape shape(1, size); 763 auto seqTy = fir::SequenceType::get(shape, i8Ty); 764 mlir::Value local = 765 builder.allocateLocal(loc, seqTy, aggName, "", llvm::None, llvm::None, 766 /*target=*/false); 767 insertAggregateStore(storeMap, var, local); 768 } 769 770 /// Cast an alias address (variable part of an equivalence) to fir.ptr so that 771 /// the optimizer is conservative and avoids doing copy elision in assignment 772 /// involving equivalenced variables. 773 /// TODO: Represent the equivalence aliasing constraint in another way to avoid 774 /// pessimizing array assignments involving equivalenced variables. 775 static mlir::Value castAliasToPointer(fir::FirOpBuilder &builder, 776 mlir::Location loc, mlir::Type aliasType, 777 mlir::Value aliasAddr) { 778 return builder.createConvert(loc, fir::PointerType::get(aliasType), 779 aliasAddr); 780 } 781 782 /// Instantiate a member of an equivalence. Compute its address in its 783 /// aggregate storage and lower its attributes. 784 static void instantiateAlias(Fortran::lower::AbstractConverter &converter, 785 const Fortran::lower::pft::Variable &var, 786 Fortran::lower::SymMap &symMap, 787 Fortran::lower::AggregateStoreMap &storeMap) { 788 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 789 assert(var.isAlias()); 790 const Fortran::semantics::Symbol &sym = var.getSymbol(); 791 const mlir::Location loc = genLocation(converter, sym); 792 mlir::IndexType idxTy = builder.getIndexType(); 793 std::size_t aliasOffset = var.getAlias(); 794 mlir::Value store = getAggregateStore(storeMap, var); 795 mlir::IntegerType i8Ty = builder.getIntegerType(8); 796 mlir::Type i8Ptr = builder.getRefType(i8Ty); 797 mlir::Value offset = builder.createIntegerConstant( 798 loc, idxTy, sym.GetUltimate().offset() - aliasOffset); 799 auto ptr = builder.create<fir::CoordinateOp>(loc, i8Ptr, store, 800 mlir::ValueRange{offset}); 801 mlir::Value preAlloc = 802 castAliasToPointer(builder, loc, converter.genType(sym), ptr); 803 Fortran::lower::StatementContext stmtCtx; 804 mapSymbolAttributes(converter, var, symMap, stmtCtx, preAlloc); 805 // Default initialization is possible for equivalence members: see 806 // F2018 19.5.3.4. Note that if several equivalenced entities have 807 // default initialization, they must have the same type, and the standard 808 // allows the storage to be default initialized several times (this has 809 // no consequences other than wasting some execution time). For now, 810 // do not try optimizing this to single default initializations of 811 // the equivalenced storages. Keep lowering simple. 812 if (mustBeDefaultInitializedAtRuntime(var)) 813 defaultInitializeAtRuntime(converter, var, symMap); 814 } 815 816 //===--------------------------------------------------------------===// 817 // COMMON blocks instantiation 818 //===--------------------------------------------------------------===// 819 820 /// Does any member of the common block has an initializer ? 821 static bool 822 commonBlockHasInit(const Fortran::semantics::MutableSymbolVector &cmnBlkMems) { 823 for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) { 824 if (const auto *memDet = 825 mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) 826 if (memDet->init()) 827 return true; 828 } 829 return false; 830 } 831 832 /// Build a tuple type for a common block based on the common block 833 /// members and the common block size. 834 /// This type is only needed to build common block initializers where 835 /// the initial value is the collection of the member initial values. 836 static mlir::TupleType getTypeOfCommonWithInit( 837 Fortran::lower::AbstractConverter &converter, 838 const Fortran::semantics::MutableSymbolVector &cmnBlkMems, 839 std::size_t commonSize) { 840 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 841 llvm::SmallVector<mlir::Type> members; 842 std::size_t counter = 0; 843 for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) { 844 if (const auto *memDet = 845 mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) { 846 if (mem->offset() > counter) { 847 fir::SequenceType::Shape len = { 848 static_cast<fir::SequenceType::Extent>(mem->offset() - counter)}; 849 mlir::IntegerType byteTy = builder.getIntegerType(8); 850 auto memTy = fir::SequenceType::get(len, byteTy); 851 members.push_back(memTy); 852 counter = mem->offset(); 853 } 854 if (memDet->init()) { 855 mlir::Type memTy = converter.genType(*mem); 856 members.push_back(memTy); 857 counter = mem->offset() + mem->size(); 858 } 859 } 860 } 861 if (counter < commonSize) { 862 fir::SequenceType::Shape len = { 863 static_cast<fir::SequenceType::Extent>(commonSize - counter)}; 864 mlir::IntegerType byteTy = builder.getIntegerType(8); 865 auto memTy = fir::SequenceType::get(len, byteTy); 866 members.push_back(memTy); 867 } 868 return mlir::TupleType::get(builder.getContext(), members); 869 } 870 871 /// Common block members may have aliases. They are not in the common block 872 /// member list from the symbol. We need to know about these aliases if they 873 /// have initializer to generate the common initializer. 874 /// This function takes care of adding aliases with initializer to the member 875 /// list. 876 static Fortran::semantics::MutableSymbolVector 877 getCommonMembersWithInitAliases(const Fortran::semantics::Symbol &common) { 878 const auto &commonDetails = 879 common.get<Fortran::semantics::CommonBlockDetails>(); 880 auto members = commonDetails.objects(); 881 882 // The number and size of equivalence and common is expected to be small, so 883 // no effort is given to optimize this loop of complexity equivalenced 884 // common members * common members 885 for (const Fortran::semantics::EquivalenceSet &set : 886 common.owner().equivalenceSets()) 887 for (const Fortran::semantics::EquivalenceObject &obj : set) { 888 if (!obj.symbol.test(Fortran::semantics::Symbol::Flag::CompilerCreated)) { 889 if (const auto &details = 890 obj.symbol 891 .detailsIf<Fortran::semantics::ObjectEntityDetails>()) { 892 const Fortran::semantics::Symbol *com = 893 FindCommonBlockContaining(obj.symbol); 894 if (!details->init() || com != &common) 895 continue; 896 // This is an alias with an init that belongs to the list 897 if (std::find(members.begin(), members.end(), obj.symbol) == 898 members.end()) 899 members.emplace_back(obj.symbol); 900 } 901 } 902 } 903 return members; 904 } 905 906 /// Return the fir::GlobalOp that was created of COMMON block \p common. 907 /// It is an error if the fir::GlobalOp was not created before this is 908 /// called (it cannot be created on the flight because it is not known here 909 /// what mlir type the GlobalOp should have to satisfy all the 910 /// appearances in the program). 911 static fir::GlobalOp 912 getCommonBlockGlobal(Fortran::lower::AbstractConverter &converter, 913 const Fortran::semantics::Symbol &common) { 914 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 915 std::string commonName = Fortran::lower::mangle::mangleName(common); 916 fir::GlobalOp global = builder.getNamedGlobal(commonName); 917 // Common blocks are lowered before any subprograms to deal with common 918 // whose size may not be the same in every subprograms. 919 if (!global) 920 fir::emitFatalError(converter.genLocation(common.name()), 921 "COMMON block was not lowered before its usage"); 922 return global; 923 } 924 925 /// Create the fir::GlobalOp for COMMON block \p common. If \p common has an 926 /// initial value, it is not created yet. Instead, the common block list 927 /// members is returned to later create the initial value in 928 /// finalizeCommonBlockDefinition. 929 static std::optional<std::tuple< 930 fir::GlobalOp, Fortran::semantics::MutableSymbolVector, mlir::Location>> 931 declareCommonBlock(Fortran::lower::AbstractConverter &converter, 932 const Fortran::semantics::Symbol &common, 933 std::size_t commonSize) { 934 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 935 std::string commonName = Fortran::lower::mangle::mangleName(common); 936 fir::GlobalOp global = builder.getNamedGlobal(commonName); 937 if (global) 938 return std::nullopt; 939 Fortran::semantics::MutableSymbolVector cmnBlkMems = 940 getCommonMembersWithInitAliases(common); 941 mlir::Location loc = converter.genLocation(common.name()); 942 mlir::StringAttr linkage = builder.createCommonLinkage(); 943 if (!commonBlockHasInit(cmnBlkMems)) { 944 // A COMMON block sans initializers is initialized to zero. 945 // mlir::Vector types must have a strictly positive size, so at least 946 // temporarily, force a zero size COMMON block to have one byte. 947 const auto sz = 948 static_cast<fir::SequenceType::Extent>(commonSize > 0 ? commonSize : 1); 949 fir::SequenceType::Shape shape = {sz}; 950 mlir::IntegerType i8Ty = builder.getIntegerType(8); 951 auto commonTy = fir::SequenceType::get(shape, i8Ty); 952 auto vecTy = mlir::VectorType::get(sz, i8Ty); 953 mlir::Attribute zero = builder.getIntegerAttr(i8Ty, 0); 954 auto init = mlir::DenseElementsAttr::get(vecTy, llvm::makeArrayRef(zero)); 955 builder.createGlobal(loc, commonTy, commonName, linkage, init); 956 // No need to add any initial value later. 957 return std::nullopt; 958 } 959 // COMMON block with initializer (note that initialized blank common are 960 // accepted as an extension by semantics). Sort members by offset before 961 // generating the type and initializer. 962 std::sort(cmnBlkMems.begin(), cmnBlkMems.end(), 963 [](auto &s1, auto &s2) { return s1->offset() < s2->offset(); }); 964 mlir::TupleType commonTy = 965 getTypeOfCommonWithInit(converter, cmnBlkMems, commonSize); 966 // Create the global object, the initial value will be added later. 967 global = builder.createGlobal(loc, commonTy, commonName); 968 return std::make_tuple(global, std::move(cmnBlkMems), loc); 969 } 970 971 /// Add initial value to a COMMON block fir::GlobalOp \p global given the list 972 /// \p cmnBlkMems of the common block member symbols that contains symbols with 973 /// an initial value. 974 static void finalizeCommonBlockDefinition( 975 mlir::Location loc, Fortran::lower::AbstractConverter &converter, 976 fir::GlobalOp global, 977 const Fortran::semantics::MutableSymbolVector &cmnBlkMems) { 978 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 979 mlir::TupleType commonTy = global.getType().cast<mlir::TupleType>(); 980 auto initFunc = [&](fir::FirOpBuilder &builder) { 981 mlir::IndexType idxTy = builder.getIndexType(); 982 mlir::Value cb = builder.create<fir::UndefOp>(loc, commonTy); 983 unsigned tupIdx = 0; 984 std::size_t offset = 0; 985 LLVM_DEBUG(llvm::dbgs() << "block {\n"); 986 for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) { 987 if (const auto *memDet = 988 mem->detailsIf<Fortran::semantics::ObjectEntityDetails>()) { 989 if (mem->offset() > offset) { 990 ++tupIdx; 991 offset = mem->offset(); 992 } 993 if (memDet->init()) { 994 LLVM_DEBUG(llvm::dbgs() 995 << "offset: " << mem->offset() << " is " << *mem << '\n'); 996 Fortran::lower::StatementContext stmtCtx; 997 auto initExpr = memDet->init().value(); 998 fir::ExtendedValue initVal = 999 Fortran::semantics::IsPointer(*mem) 1000 ? Fortran::lower::genInitialDataTarget( 1001 converter, loc, converter.genType(*mem), initExpr) 1002 : genInitializerExprValue(converter, loc, initExpr, stmtCtx); 1003 mlir::IntegerAttr offVal = builder.getIntegerAttr(idxTy, tupIdx); 1004 mlir::Value castVal = builder.createConvert( 1005 loc, commonTy.getType(tupIdx), fir::getBase(initVal)); 1006 cb = builder.create<fir::InsertValueOp>(loc, commonTy, cb, castVal, 1007 builder.getArrayAttr(offVal)); 1008 ++tupIdx; 1009 offset = mem->offset() + mem->size(); 1010 } 1011 } 1012 } 1013 LLVM_DEBUG(llvm::dbgs() << "}\n"); 1014 builder.create<fir::HasValueOp>(loc, cb); 1015 }; 1016 createGlobalInitialization(builder, global, initFunc); 1017 } 1018 1019 void Fortran::lower::defineCommonBlocks( 1020 Fortran::lower::AbstractConverter &converter, 1021 const Fortran::semantics::CommonBlockList &commonBlocks) { 1022 // Common blocks may depend on another common block address (if they contain 1023 // pointers with initial targets). To cover this case, create all common block 1024 // fir::Global before creating the initial values (if any). 1025 std::vector<std::tuple<fir::GlobalOp, Fortran::semantics::MutableSymbolVector, 1026 mlir::Location>> 1027 delayedInitializations; 1028 for (const auto &[common, size] : commonBlocks) 1029 if (auto delayedInit = declareCommonBlock(converter, common, size)) 1030 delayedInitializations.emplace_back(std::move(*delayedInit)); 1031 for (auto &[global, cmnBlkMems, loc] : delayedInitializations) 1032 finalizeCommonBlockDefinition(loc, converter, global, cmnBlkMems); 1033 } 1034 1035 /// The COMMON block is a global structure. `var` will be at some offset 1036 /// within the COMMON block. Adds the address of `var` (COMMON + offset) to 1037 /// the symbol map. 1038 static void instantiateCommon(Fortran::lower::AbstractConverter &converter, 1039 const Fortran::semantics::Symbol &common, 1040 const Fortran::lower::pft::Variable &var, 1041 Fortran::lower::SymMap &symMap) { 1042 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1043 const Fortran::semantics::Symbol &varSym = var.getSymbol(); 1044 mlir::Location loc = converter.genLocation(varSym.name()); 1045 1046 mlir::Value commonAddr; 1047 if (Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(common)) 1048 commonAddr = symBox.getAddr(); 1049 if (!commonAddr) { 1050 // introduce a local AddrOf and add it to the map 1051 fir::GlobalOp global = getCommonBlockGlobal(converter, common); 1052 commonAddr = builder.create<fir::AddrOfOp>(loc, global.resultType(), 1053 global.getSymbol()); 1054 1055 symMap.addSymbol(common, commonAddr); 1056 } 1057 std::size_t byteOffset = varSym.GetUltimate().offset(); 1058 mlir::IntegerType i8Ty = builder.getIntegerType(8); 1059 mlir::Type i8Ptr = builder.getRefType(i8Ty); 1060 mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(i8Ty)); 1061 mlir::Value base = builder.createConvert(loc, seqTy, commonAddr); 1062 mlir::Value offs = 1063 builder.createIntegerConstant(loc, builder.getIndexType(), byteOffset); 1064 auto varAddr = builder.create<fir::CoordinateOp>(loc, i8Ptr, base, 1065 mlir::ValueRange{offs}); 1066 mlir::Type symType = converter.genType(var.getSymbol()); 1067 mlir::Value local; 1068 if (Fortran::semantics::FindEquivalenceSet(var.getSymbol()) != nullptr) 1069 local = castAliasToPointer(builder, loc, symType, varAddr); 1070 else 1071 local = builder.createConvert(loc, builder.getRefType(symType), varAddr); 1072 Fortran::lower::StatementContext stmtCtx; 1073 mapSymbolAttributes(converter, var, symMap, stmtCtx, local); 1074 } 1075 1076 //===--------------------------------------------------------------===// 1077 // Lower Variables specification expressions and attributes 1078 //===--------------------------------------------------------------===// 1079 1080 /// Helper to decide if a dummy argument must be tracked in an BoxValue. 1081 static bool lowerToBoxValue(const Fortran::semantics::Symbol &sym, 1082 mlir::Value dummyArg) { 1083 // Only dummy arguments coming as fir.box can be tracked in an BoxValue. 1084 if (!dummyArg || !dummyArg.getType().isa<fir::BoxType>()) 1085 return false; 1086 // Non contiguous arrays must be tracked in an BoxValue. 1087 if (sym.Rank() > 0 && !sym.attrs().test(Fortran::semantics::Attr::CONTIGUOUS)) 1088 return true; 1089 // Assumed rank and optional fir.box cannot yet be read while lowering the 1090 // specifications. 1091 if (Fortran::evaluate::IsAssumedRank(sym) || 1092 Fortran::semantics::IsOptional(sym)) 1093 return true; 1094 // Polymorphic entity should be tracked through a fir.box that has the 1095 // dynamic type info. 1096 if (const Fortran::semantics::DeclTypeSpec *type = sym.GetType()) 1097 if (type->IsPolymorphic()) 1098 return true; 1099 return false; 1100 } 1101 1102 /// Compute extent from lower and upper bound. 1103 static mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc, 1104 mlir::Value lb, mlir::Value ub) { 1105 mlir::IndexType idxTy = builder.getIndexType(); 1106 // Let the folder deal with the common `ub - <const> + 1` case. 1107 auto diff = builder.create<mlir::arith::SubIOp>(loc, idxTy, ub, lb); 1108 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); 1109 auto rawExtent = builder.create<mlir::arith::AddIOp>(loc, idxTy, diff, one); 1110 return fir::factory::genMaxWithZero(builder, loc, rawExtent); 1111 } 1112 1113 /// Lower explicit lower bounds into \p result. Does nothing if this is not an 1114 /// array, or if the lower bounds are deferred, or all implicit or one. 1115 static void lowerExplicitLowerBounds( 1116 Fortran::lower::AbstractConverter &converter, mlir::Location loc, 1117 const Fortran::lower::BoxAnalyzer &box, 1118 llvm::SmallVectorImpl<mlir::Value> &result, Fortran::lower::SymMap &symMap, 1119 Fortran::lower::StatementContext &stmtCtx) { 1120 if (!box.isArray() || box.lboundIsAllOnes()) 1121 return; 1122 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1123 mlir::IndexType idxTy = builder.getIndexType(); 1124 if (box.isStaticArray()) { 1125 for (int64_t lb : box.staticLBound()) 1126 result.emplace_back(builder.createIntegerConstant(loc, idxTy, lb)); 1127 return; 1128 } 1129 for (const Fortran::semantics::ShapeSpec *spec : box.dynamicBound()) { 1130 if (auto low = spec->lbound().GetExplicit()) { 1131 auto expr = Fortran::lower::SomeExpr{*low}; 1132 mlir::Value lb = builder.createConvert( 1133 loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx)); 1134 result.emplace_back(lb); 1135 } 1136 } 1137 assert(result.empty() || result.size() == box.dynamicBound().size()); 1138 } 1139 1140 /// Lower explicit extents into \p result if this is an explicit-shape or 1141 /// assumed-size array. Does nothing if this is not an explicit-shape or 1142 /// assumed-size array. 1143 static void 1144 lowerExplicitExtents(Fortran::lower::AbstractConverter &converter, 1145 mlir::Location loc, const Fortran::lower::BoxAnalyzer &box, 1146 llvm::SmallVectorImpl<mlir::Value> &lowerBounds, 1147 llvm::SmallVectorImpl<mlir::Value> &result, 1148 Fortran::lower::SymMap &symMap, 1149 Fortran::lower::StatementContext &stmtCtx) { 1150 if (!box.isArray()) 1151 return; 1152 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1153 mlir::IndexType idxTy = builder.getIndexType(); 1154 if (box.isStaticArray()) { 1155 for (int64_t extent : box.staticShape()) 1156 result.emplace_back(builder.createIntegerConstant(loc, idxTy, extent)); 1157 return; 1158 } 1159 for (const auto &spec : llvm::enumerate(box.dynamicBound())) { 1160 if (auto up = spec.value()->ubound().GetExplicit()) { 1161 auto expr = Fortran::lower::SomeExpr{*up}; 1162 mlir::Value ub = builder.createConvert( 1163 loc, idxTy, genScalarValue(converter, loc, expr, symMap, stmtCtx)); 1164 if (lowerBounds.empty()) 1165 result.emplace_back(fir::factory::genMaxWithZero(builder, loc, ub)); 1166 else 1167 result.emplace_back( 1168 computeExtent(builder, loc, lowerBounds[spec.index()], ub)); 1169 } else if (spec.value()->ubound().isStar()) { 1170 // Assumed extent is undefined. Must be provided by user's code. 1171 result.emplace_back(builder.create<fir::UndefOp>(loc, idxTy)); 1172 } 1173 } 1174 assert(result.empty() || result.size() == box.dynamicBound().size()); 1175 } 1176 1177 /// Lower explicit character length if any. Return empty mlir::Value if no 1178 /// explicit length. 1179 static mlir::Value 1180 lowerExplicitCharLen(Fortran::lower::AbstractConverter &converter, 1181 mlir::Location loc, const Fortran::lower::BoxAnalyzer &box, 1182 Fortran::lower::SymMap &symMap, 1183 Fortran::lower::StatementContext &stmtCtx) { 1184 if (!box.isChar()) 1185 return mlir::Value{}; 1186 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1187 mlir::Type lenTy = builder.getCharacterLengthType(); 1188 if (llvm::Optional<int64_t> len = box.getCharLenConst()) 1189 return builder.createIntegerConstant(loc, lenTy, *len); 1190 if (llvm::Optional<Fortran::lower::SomeExpr> lenExpr = box.getCharLenExpr()) 1191 // If the length expression is negative, the length is zero. See F2018 1192 // 7.4.4.2 point 5. 1193 return fir::factory::genMaxWithZero( 1194 builder, loc, 1195 genScalarValue(converter, loc, *lenExpr, symMap, stmtCtx)); 1196 return mlir::Value{}; 1197 } 1198 1199 /// Treat negative values as undefined. Assumed size arrays will return -1 from 1200 /// the front end for example. Using negative values can produce hard to find 1201 /// bugs much further along in the compilation. 1202 static mlir::Value genExtentValue(fir::FirOpBuilder &builder, 1203 mlir::Location loc, mlir::Type idxTy, 1204 long frontEndExtent) { 1205 if (frontEndExtent >= 0) 1206 return builder.createIntegerConstant(loc, idxTy, frontEndExtent); 1207 return builder.create<fir::UndefOp>(loc, idxTy); 1208 } 1209 1210 /// If a symbol is an array, it may have been declared with unknown extent 1211 /// parameters (e.g., `*`), but if it has an initial value then the actual size 1212 /// may be available from the initial array value's type. 1213 inline static llvm::SmallVector<std::int64_t> 1214 recoverShapeVector(llvm::ArrayRef<std::int64_t> shapeVec, mlir::Value initVal) { 1215 llvm::SmallVector<std::int64_t> result; 1216 if (initVal) { 1217 if (auto seqTy = fir::unwrapUntilSeqType(initVal.getType())) { 1218 for (auto [fst, snd] : llvm::zip(shapeVec, seqTy.getShape())) 1219 result.push_back(fst == fir::SequenceType::getUnknownExtent() ? snd 1220 : fst); 1221 return result; 1222 } 1223 } 1224 result.assign(shapeVec.begin(), shapeVec.end()); 1225 return result; 1226 } 1227 1228 /// Lower specification expressions and attributes of variable \p var and 1229 /// add it to the symbol map. For a global or an alias, the address must be 1230 /// pre-computed and provided in \p preAlloc. A dummy argument for the current 1231 /// entry point has already been mapped to an mlir block argument in 1232 /// mapDummiesAndResults. Its mapping may be updated here. 1233 void Fortran::lower::mapSymbolAttributes( 1234 AbstractConverter &converter, const Fortran::lower::pft::Variable &var, 1235 Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, 1236 mlir::Value preAlloc) { 1237 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1238 const Fortran::semantics::Symbol &sym = var.getSymbol(); 1239 const mlir::Location loc = genLocation(converter, sym); 1240 mlir::IndexType idxTy = builder.getIndexType(); 1241 const bool isDeclaredDummy = Fortran::semantics::IsDummy(sym); 1242 // An active dummy from the current entry point. 1243 const bool isDummy = isDeclaredDummy && symMap.lookupSymbol(sym).getAddr(); 1244 // An unused dummy from another entry point. 1245 const bool isUnusedEntryDummy = isDeclaredDummy && !isDummy; 1246 const bool isResult = Fortran::semantics::IsFunctionResult(sym); 1247 const bool replace = isDummy || isResult; 1248 fir::factory::CharacterExprHelper charHelp{builder, loc}; 1249 1250 if (Fortran::semantics::IsProcedure(sym)) { 1251 if (isUnusedEntryDummy) { 1252 // Additional discussion below. 1253 mlir::Type dummyProcType = 1254 Fortran::lower::getDummyProcedureType(sym, converter); 1255 mlir::Value undefOp = builder.create<fir::UndefOp>(loc, dummyProcType); 1256 symMap.addSymbol(sym, undefOp); 1257 } 1258 if (Fortran::semantics::IsPointer(sym)) 1259 TODO(loc, "procedure pointers"); 1260 return; 1261 } 1262 1263 Fortran::lower::BoxAnalyzer ba; 1264 ba.analyze(sym); 1265 1266 // First deal with pointers and allocatables, because their handling here 1267 // is the same regardless of their rank. 1268 if (Fortran::semantics::IsAllocatableOrPointer(sym)) { 1269 // Get address of fir.box describing the entity. 1270 // global 1271 mlir::Value boxAlloc = preAlloc; 1272 // dummy or passed result 1273 if (!boxAlloc) 1274 if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym)) 1275 boxAlloc = symbox.getAddr(); 1276 // local 1277 if (!boxAlloc) 1278 boxAlloc = createNewLocal(converter, loc, var, preAlloc); 1279 // Lower non deferred parameters. 1280 llvm::SmallVector<mlir::Value> nonDeferredLenParams; 1281 if (ba.isChar()) { 1282 if (mlir::Value len = 1283 lowerExplicitCharLen(converter, loc, ba, symMap, stmtCtx)) 1284 nonDeferredLenParams.push_back(len); 1285 else if (Fortran::semantics::IsAssumedLengthCharacter(sym)) 1286 TODO(loc, "assumed length character allocatable"); 1287 } else if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) { 1288 if (const Fortran::semantics::DerivedTypeSpec *derived = 1289 declTy->AsDerived()) 1290 if (Fortran::semantics::CountLenParameters(*derived) != 0) 1291 TODO(loc, 1292 "derived type allocatable or pointer with length parameters"); 1293 } 1294 fir::MutableBoxValue box = Fortran::lower::createMutableBox( 1295 converter, loc, var, boxAlloc, nonDeferredLenParams); 1296 symMap.addAllocatableOrPointer(var.getSymbol(), box, replace); 1297 return; 1298 } 1299 1300 if (isDummy) { 1301 mlir::Value dummyArg = symMap.lookupSymbol(sym).getAddr(); 1302 if (lowerToBoxValue(sym, dummyArg)) { 1303 llvm::SmallVector<mlir::Value> lbounds; 1304 llvm::SmallVector<mlir::Value> explicitExtents; 1305 llvm::SmallVector<mlir::Value> explicitParams; 1306 // Lower lower bounds, explicit type parameters and explicit 1307 // extents if any. 1308 if (ba.isChar()) 1309 if (mlir::Value len = 1310 lowerExplicitCharLen(converter, loc, ba, symMap, stmtCtx)) 1311 explicitParams.push_back(len); 1312 // TODO: derived type length parameters. 1313 lowerExplicitLowerBounds(converter, loc, ba, lbounds, symMap, stmtCtx); 1314 lowerExplicitExtents(converter, loc, ba, lbounds, explicitExtents, symMap, 1315 stmtCtx); 1316 symMap.addBoxSymbol(sym, dummyArg, lbounds, explicitParams, 1317 explicitExtents, replace); 1318 return; 1319 } 1320 } 1321 1322 // A dummy from another entry point that is not declared in the current 1323 // entry point requires a skeleton definition. Most such "unused" dummies 1324 // will not survive into final generated code, but some will. It is illegal 1325 // to reference one at run time if it does. Such a dummy is mapped to a 1326 // value in one of three ways: 1327 // 1328 // - Generate a fir::UndefOp value. This is lightweight, easy to clean up, 1329 // and often valid, but it may fail for a dummy with dynamic bounds, 1330 // or a dummy used to define another dummy. Information to distinguish 1331 // valid cases is not generally available here, with the exception of 1332 // dummy procedures. See the first function exit above. 1333 // 1334 // - Allocate an uninitialized stack slot. This is an intermediate-weight 1335 // solution that is harder to clean up. It is often valid, but may fail 1336 // for an object with dynamic bounds. This option is "automatically" 1337 // used by default for cases that do not use one of the other options. 1338 // 1339 // - Allocate a heap box/descriptor, initialized to zero. This always 1340 // works, but is more heavyweight and harder to clean up. It is used 1341 // for dynamic objects via calls to genUnusedEntryPointBox. 1342 1343 auto genUnusedEntryPointBox = [&]() { 1344 if (isUnusedEntryDummy) { 1345 assert(!Fortran::semantics::IsAllocatableOrPointer(sym) && 1346 "handled above"); 1347 // The box is read right away because lowering code does not expect 1348 // a non pointer/allocatable symbol to be mapped to a MutableBox. 1349 symMap.addSymbol(sym, fir::factory::genMutableBoxRead( 1350 builder, loc, 1351 fir::factory::createTempMutableBox( 1352 builder, loc, converter.genType(var)))); 1353 return true; 1354 } 1355 return false; 1356 }; 1357 1358 // Helper to generate scalars for the symbol properties. 1359 auto genValue = [&](const Fortran::lower::SomeExpr &expr) { 1360 return genScalarValue(converter, loc, expr, symMap, stmtCtx); 1361 }; 1362 1363 // For symbols reaching this point, all properties are constant and can be 1364 // read/computed already into ssa values. 1365 1366 // The origin must be \vec{1}. 1367 auto populateShape = [&](auto &shapes, const auto &bounds, mlir::Value box) { 1368 for (auto iter : llvm::enumerate(bounds)) { 1369 auto *spec = iter.value(); 1370 assert(spec->lbound().GetExplicit() && 1371 "lbound must be explicit with constant value 1"); 1372 if (auto high = spec->ubound().GetExplicit()) { 1373 Fortran::lower::SomeExpr highEx{*high}; 1374 mlir::Value ub = genValue(highEx); 1375 ub = builder.createConvert(loc, idxTy, ub); 1376 shapes.emplace_back(fir::factory::genMaxWithZero(builder, loc, ub)); 1377 } else if (spec->ubound().isColon()) { 1378 assert(box && "assumed bounds require a descriptor"); 1379 mlir::Value dim = 1380 builder.createIntegerConstant(loc, idxTy, iter.index()); 1381 auto dimInfo = 1382 builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim); 1383 shapes.emplace_back(dimInfo.getResult(1)); 1384 } else if (spec->ubound().isStar()) { 1385 shapes.emplace_back(builder.create<fir::UndefOp>(loc, idxTy)); 1386 } else { 1387 llvm::report_fatal_error("unknown bound category"); 1388 } 1389 } 1390 }; 1391 1392 // The origin is not \vec{1}. 1393 auto populateLBoundsExtents = [&](auto &lbounds, auto &extents, 1394 const auto &bounds, mlir::Value box) { 1395 for (auto iter : llvm::enumerate(bounds)) { 1396 auto *spec = iter.value(); 1397 fir::BoxDimsOp dimInfo; 1398 mlir::Value ub, lb; 1399 if (spec->lbound().isColon() || spec->ubound().isColon()) { 1400 // This is an assumed shape because allocatables and pointers extents 1401 // are not constant in the scope and are not read here. 1402 assert(box && "deferred bounds require a descriptor"); 1403 mlir::Value dim = 1404 builder.createIntegerConstant(loc, idxTy, iter.index()); 1405 dimInfo = 1406 builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dim); 1407 extents.emplace_back(dimInfo.getResult(1)); 1408 if (auto low = spec->lbound().GetExplicit()) { 1409 auto expr = Fortran::lower::SomeExpr{*low}; 1410 mlir::Value lb = builder.createConvert(loc, idxTy, genValue(expr)); 1411 lbounds.emplace_back(lb); 1412 } else { 1413 // Implicit lower bound is 1 (Fortran 2018 section 8.5.8.3 point 3.) 1414 lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, 1)); 1415 } 1416 } else { 1417 if (auto low = spec->lbound().GetExplicit()) { 1418 auto expr = Fortran::lower::SomeExpr{*low}; 1419 lb = builder.createConvert(loc, idxTy, genValue(expr)); 1420 } else { 1421 TODO(loc, "support for assumed rank entities"); 1422 } 1423 lbounds.emplace_back(lb); 1424 1425 if (auto high = spec->ubound().GetExplicit()) { 1426 auto expr = Fortran::lower::SomeExpr{*high}; 1427 ub = builder.createConvert(loc, idxTy, genValue(expr)); 1428 extents.emplace_back(computeExtent(builder, loc, lb, ub)); 1429 } else { 1430 // An assumed size array. The extent is not computed. 1431 assert(spec->ubound().isStar() && "expected assumed size"); 1432 extents.emplace_back(builder.create<fir::UndefOp>(loc, idxTy)); 1433 } 1434 } 1435 } 1436 }; 1437 1438 // Lower length expression for non deferred and non dummy assumed length 1439 // characters. 1440 auto genExplicitCharLen = 1441 [&](llvm::Optional<Fortran::lower::SomeExpr> charLen) -> mlir::Value { 1442 if (!charLen) 1443 fir::emitFatalError(loc, "expected explicit character length"); 1444 mlir::Value rawLen = genValue(*charLen); 1445 // If the length expression is negative, the length is zero. See 1446 // F2018 7.4.4.2 point 5. 1447 return fir::factory::genMaxWithZero(builder, loc, rawLen); 1448 }; 1449 1450 ba.match( 1451 //===--------------------------------------------------------------===// 1452 // Trivial case. 1453 //===--------------------------------------------------------------===// 1454 [&](const Fortran::lower::details::ScalarSym &) { 1455 if (isDummy) { 1456 // This is an argument. 1457 if (!symMap.lookupSymbol(sym)) 1458 mlir::emitError(loc, "symbol \"") 1459 << toStringRef(sym.name()) << "\" must already be in map"; 1460 return; 1461 } else if (isResult) { 1462 // Some Fortran results may be passed by argument (e.g. derived 1463 // types) 1464 if (symMap.lookupSymbol(sym)) 1465 return; 1466 } 1467 // Otherwise, it's a local variable or function result. 1468 mlir::Value local = createNewLocal(converter, loc, var, preAlloc); 1469 symMap.addSymbol(sym, local); 1470 }, 1471 1472 //===--------------------------------------------------------------===// 1473 // The non-trivial cases are when we have an argument or local that has 1474 // a repetition value. Arguments might be passed as simple pointers and 1475 // need to be cast to a multi-dimensional array with constant bounds 1476 // (possibly with a missing column), bounds computed in the callee 1477 // (here), or with bounds from the caller (boxed somewhere else). Locals 1478 // have the same properties except they are never boxed arguments from 1479 // the caller and never having a missing column size. 1480 //===--------------------------------------------------------------===// 1481 1482 [&](const Fortran::lower::details::ScalarStaticChar &x) { 1483 // type is a CHARACTER, determine the LEN value 1484 auto charLen = x.charLen(); 1485 if (replace) { 1486 Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym); 1487 std::pair<mlir::Value, mlir::Value> unboxchar = 1488 charHelp.createUnboxChar(symBox.getAddr()); 1489 mlir::Value boxAddr = unboxchar.first; 1490 // Set/override LEN with a constant 1491 mlir::Value len = builder.createIntegerConstant(loc, idxTy, charLen); 1492 symMap.addCharSymbol(sym, boxAddr, len, true); 1493 return; 1494 } 1495 mlir::Value len = builder.createIntegerConstant(loc, idxTy, charLen); 1496 if (preAlloc) { 1497 symMap.addCharSymbol(sym, preAlloc, len); 1498 return; 1499 } 1500 mlir::Value local = createNewLocal(converter, loc, var, preAlloc); 1501 symMap.addCharSymbol(sym, local, len); 1502 }, 1503 1504 //===--------------------------------------------------------------===// 1505 1506 [&](const Fortran::lower::details::ScalarDynamicChar &x) { 1507 if (genUnusedEntryPointBox()) 1508 return; 1509 // type is a CHARACTER, determine the LEN value 1510 auto charLen = x.charLen(); 1511 if (replace) { 1512 Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym); 1513 mlir::Value boxAddr = symBox.getAddr(); 1514 mlir::Value len; 1515 mlir::Type addrTy = boxAddr.getType(); 1516 if (addrTy.isa<fir::BoxCharType>() || addrTy.isa<fir::BoxType>()) 1517 std::tie(boxAddr, len) = charHelp.createUnboxChar(symBox.getAddr()); 1518 // Override LEN with an expression 1519 if (charLen) 1520 len = genExplicitCharLen(charLen); 1521 symMap.addCharSymbol(sym, boxAddr, len, true); 1522 return; 1523 } 1524 // local CHARACTER variable 1525 mlir::Value len = genExplicitCharLen(charLen); 1526 if (preAlloc) { 1527 symMap.addCharSymbol(sym, preAlloc, len); 1528 return; 1529 } 1530 llvm::SmallVector<mlir::Value> lengths = {len}; 1531 mlir::Value local = 1532 createNewLocal(converter, loc, var, preAlloc, llvm::None, lengths); 1533 symMap.addCharSymbol(sym, local, len); 1534 }, 1535 1536 //===--------------------------------------------------------------===// 1537 1538 [&](const Fortran::lower::details::StaticArray &x) { 1539 // object shape is constant, not a character 1540 mlir::Type castTy = builder.getRefType(converter.genType(var)); 1541 mlir::Value addr = symMap.lookupSymbol(sym).getAddr(); 1542 if (addr) 1543 addr = builder.createConvert(loc, castTy, addr); 1544 if (x.lboundAllOnes()) { 1545 // if lower bounds are all ones, build simple shaped object 1546 llvm::SmallVector<mlir::Value> shape; 1547 for (int64_t i : recoverShapeVector(x.shapes, preAlloc)) 1548 shape.push_back(genExtentValue(builder, loc, idxTy, i)); 1549 mlir::Value local = 1550 isDummy ? addr : createNewLocal(converter, loc, var, preAlloc); 1551 symMap.addSymbolWithShape(sym, local, shape, isDummy); 1552 return; 1553 } 1554 // If object is an array process the lower bound and extent values by 1555 // constructing constants and populating the lbounds and extents. 1556 llvm::SmallVector<mlir::Value> extents; 1557 llvm::SmallVector<mlir::Value> lbounds; 1558 for (auto [fst, snd] : 1559 llvm::zip(x.lbounds, recoverShapeVector(x.shapes, preAlloc))) { 1560 lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, fst)); 1561 extents.emplace_back(genExtentValue(builder, loc, idxTy, snd)); 1562 } 1563 mlir::Value local = 1564 isDummy ? addr 1565 : createNewLocal(converter, loc, var, preAlloc, extents); 1566 // Must be a dummy argument, have an explicit shape, or be a PARAMETER. 1567 assert(isDummy || Fortran::lower::isExplicitShape(sym) || 1568 Fortran::semantics::IsNamedConstant(sym)); 1569 symMap.addSymbolWithBounds(sym, local, extents, lbounds, isDummy); 1570 }, 1571 1572 //===--------------------------------------------------------------===// 1573 1574 [&](const Fortran::lower::details::DynamicArray &x) { 1575 if (genUnusedEntryPointBox()) 1576 return; 1577 // cast to the known constant parts from the declaration 1578 mlir::Type varType = converter.genType(var); 1579 mlir::Value addr = symMap.lookupSymbol(sym).getAddr(); 1580 mlir::Value argBox; 1581 mlir::Type castTy = builder.getRefType(varType); 1582 if (addr) { 1583 if (auto boxTy = addr.getType().dyn_cast<fir::BoxType>()) { 1584 argBox = addr; 1585 mlir::Type refTy = builder.getRefType(boxTy.getEleTy()); 1586 addr = builder.create<fir::BoxAddrOp>(loc, refTy, argBox); 1587 } 1588 addr = builder.createConvert(loc, castTy, addr); 1589 } 1590 if (x.lboundAllOnes()) { 1591 // if lower bounds are all ones, build simple shaped object 1592 llvm::SmallVector<mlir::Value> shapes; 1593 populateShape(shapes, x.bounds, argBox); 1594 if (isDummy) { 1595 symMap.addSymbolWithShape(sym, addr, shapes, true); 1596 return; 1597 } 1598 // local array with computed bounds 1599 assert(Fortran::lower::isExplicitShape(sym) || 1600 Fortran::semantics::IsAllocatableOrPointer(sym)); 1601 mlir::Value local = 1602 createNewLocal(converter, loc, var, preAlloc, shapes); 1603 symMap.addSymbolWithShape(sym, local, shapes); 1604 return; 1605 } 1606 // if object is an array process the lower bound and extent values 1607 llvm::SmallVector<mlir::Value> extents; 1608 llvm::SmallVector<mlir::Value> lbounds; 1609 populateLBoundsExtents(lbounds, extents, x.bounds, argBox); 1610 if (isDummy) { 1611 symMap.addSymbolWithBounds(sym, addr, extents, lbounds, true); 1612 return; 1613 } 1614 // local array with computed bounds 1615 assert(Fortran::lower::isExplicitShape(sym)); 1616 mlir::Value local = 1617 createNewLocal(converter, loc, var, preAlloc, extents); 1618 symMap.addSymbolWithBounds(sym, local, extents, lbounds); 1619 }, 1620 1621 //===--------------------------------------------------------------===// 1622 1623 [&](const Fortran::lower::details::StaticArrayStaticChar &x) { 1624 // if element type is a CHARACTER, determine the LEN value 1625 auto charLen = x.charLen(); 1626 mlir::Value addr; 1627 mlir::Value len; 1628 if (isDummy) { 1629 Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym); 1630 std::pair<mlir::Value, mlir::Value> unboxchar = 1631 charHelp.createUnboxChar(symBox.getAddr()); 1632 addr = unboxchar.first; 1633 // Set/override LEN with a constant 1634 len = builder.createIntegerConstant(loc, idxTy, charLen); 1635 } else { 1636 // local CHARACTER variable 1637 len = builder.createIntegerConstant(loc, idxTy, charLen); 1638 } 1639 1640 // object shape is constant 1641 mlir::Type castTy = builder.getRefType(converter.genType(var)); 1642 if (addr) 1643 addr = builder.createConvert(loc, castTy, addr); 1644 1645 if (x.lboundAllOnes()) { 1646 // if lower bounds are all ones, build simple shaped object 1647 llvm::SmallVector<mlir::Value> shape; 1648 for (int64_t i : recoverShapeVector(x.shapes, preAlloc)) 1649 shape.push_back(genExtentValue(builder, loc, idxTy, i)); 1650 mlir::Value local = 1651 isDummy ? addr : createNewLocal(converter, loc, var, preAlloc); 1652 symMap.addCharSymbolWithShape(sym, local, len, shape, isDummy); 1653 return; 1654 } 1655 1656 // if object is an array process the lower bound and extent values 1657 llvm::SmallVector<mlir::Value> extents; 1658 llvm::SmallVector<mlir::Value> lbounds; 1659 // construct constants and populate `bounds` 1660 for (auto [fst, snd] : 1661 llvm::zip(x.lbounds, recoverShapeVector(x.shapes, preAlloc))) { 1662 lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, fst)); 1663 extents.emplace_back(genExtentValue(builder, loc, idxTy, snd)); 1664 } 1665 1666 if (isDummy) { 1667 symMap.addCharSymbolWithBounds(sym, addr, len, extents, lbounds, 1668 true); 1669 return; 1670 } 1671 // local CHARACTER array with computed bounds 1672 assert(Fortran::lower::isExplicitShape(sym)); 1673 mlir::Value local = 1674 createNewLocal(converter, loc, var, preAlloc, extents); 1675 symMap.addCharSymbolWithBounds(sym, local, len, extents, lbounds); 1676 }, 1677 1678 //===--------------------------------------------------------------===// 1679 1680 [&](const Fortran::lower::details::StaticArrayDynamicChar &x) { 1681 if (genUnusedEntryPointBox()) 1682 return; 1683 mlir::Value addr; 1684 mlir::Value len; 1685 [[maybe_unused]] bool mustBeDummy = false; 1686 auto charLen = x.charLen(); 1687 // if element type is a CHARACTER, determine the LEN value 1688 if (isDummy) { 1689 Fortran::lower::SymbolBox symBox = symMap.lookupSymbol(sym); 1690 std::pair<mlir::Value, mlir::Value> unboxchar = 1691 charHelp.createUnboxChar(symBox.getAddr()); 1692 addr = unboxchar.first; 1693 if (charLen) { 1694 // Set/override LEN with an expression 1695 len = genExplicitCharLen(charLen); 1696 } else { 1697 // LEN is from the boxchar 1698 len = unboxchar.second; 1699 mustBeDummy = true; 1700 } 1701 } else { 1702 // local CHARACTER variable 1703 len = genExplicitCharLen(charLen); 1704 } 1705 llvm::SmallVector<mlir::Value> lengths = {len}; 1706 1707 // cast to the known constant parts from the declaration 1708 mlir::Type castTy = builder.getRefType(converter.genType(var)); 1709 if (addr) 1710 addr = builder.createConvert(loc, castTy, addr); 1711 1712 if (x.lboundAllOnes()) { 1713 // if lower bounds are all ones, build simple shaped object 1714 llvm::SmallVector<mlir::Value> shape; 1715 for (int64_t i : recoverShapeVector(x.shapes, preAlloc)) 1716 shape.push_back(genExtentValue(builder, loc, idxTy, i)); 1717 if (isDummy) { 1718 symMap.addCharSymbolWithShape(sym, addr, len, shape, true); 1719 return; 1720 } 1721 // local CHARACTER array with constant size 1722 mlir::Value local = createNewLocal(converter, loc, var, preAlloc, 1723 llvm::None, lengths); 1724 symMap.addCharSymbolWithShape(sym, local, len, shape); 1725 return; 1726 } 1727 1728 // if object is an array process the lower bound and extent values 1729 llvm::SmallVector<mlir::Value> extents; 1730 llvm::SmallVector<mlir::Value> lbounds; 1731 1732 // construct constants and populate `bounds` 1733 for (auto [fst, snd] : 1734 llvm::zip(x.lbounds, recoverShapeVector(x.shapes, preAlloc))) { 1735 lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, fst)); 1736 extents.emplace_back(genExtentValue(builder, loc, idxTy, snd)); 1737 } 1738 if (isDummy) { 1739 symMap.addCharSymbolWithBounds(sym, addr, len, extents, lbounds, 1740 true); 1741 return; 1742 } 1743 // local CHARACTER array with computed bounds 1744 assert((!mustBeDummy) && (Fortran::lower::isExplicitShape(sym))); 1745 mlir::Value local = 1746 createNewLocal(converter, loc, var, preAlloc, llvm::None, lengths); 1747 symMap.addCharSymbolWithBounds(sym, local, len, extents, lbounds); 1748 }, 1749 1750 //===--------------------------------------------------------------===// 1751 1752 [&](const Fortran::lower::details::DynamicArrayStaticChar &x) { 1753 if (genUnusedEntryPointBox()) 1754 return; 1755 mlir::Value addr; 1756 mlir::Value len; 1757 mlir::Value argBox; 1758 auto charLen = x.charLen(); 1759 // if element type is a CHARACTER, determine the LEN value 1760 if (isDummy) { 1761 mlir::Value actualArg = symMap.lookupSymbol(sym).getAddr(); 1762 if (auto boxTy = actualArg.getType().dyn_cast<fir::BoxType>()) { 1763 argBox = actualArg; 1764 mlir::Type refTy = builder.getRefType(boxTy.getEleTy()); 1765 addr = builder.create<fir::BoxAddrOp>(loc, refTy, argBox); 1766 } else { 1767 addr = charHelp.createUnboxChar(actualArg).first; 1768 } 1769 // Set/override LEN with a constant 1770 len = builder.createIntegerConstant(loc, idxTy, charLen); 1771 } else { 1772 // local CHARACTER variable 1773 len = builder.createIntegerConstant(loc, idxTy, charLen); 1774 } 1775 1776 // cast to the known constant parts from the declaration 1777 mlir::Type castTy = builder.getRefType(converter.genType(var)); 1778 if (addr) 1779 addr = builder.createConvert(loc, castTy, addr); 1780 if (x.lboundAllOnes()) { 1781 // if lower bounds are all ones, build simple shaped object 1782 llvm::SmallVector<mlir::Value> shape; 1783 populateShape(shape, x.bounds, argBox); 1784 if (isDummy) { 1785 symMap.addCharSymbolWithShape(sym, addr, len, shape, true); 1786 return; 1787 } 1788 // local CHARACTER array 1789 mlir::Value local = 1790 createNewLocal(converter, loc, var, preAlloc, shape); 1791 symMap.addCharSymbolWithShape(sym, local, len, shape); 1792 return; 1793 } 1794 // if object is an array process the lower bound and extent values 1795 llvm::SmallVector<mlir::Value> extents; 1796 llvm::SmallVector<mlir::Value> lbounds; 1797 populateLBoundsExtents(lbounds, extents, x.bounds, argBox); 1798 if (isDummy) { 1799 symMap.addCharSymbolWithBounds(sym, addr, len, extents, lbounds, 1800 true); 1801 return; 1802 } 1803 // local CHARACTER array with computed bounds 1804 assert(Fortran::lower::isExplicitShape(sym)); 1805 mlir::Value local = 1806 createNewLocal(converter, loc, var, preAlloc, extents); 1807 symMap.addCharSymbolWithBounds(sym, local, len, extents, lbounds); 1808 }, 1809 1810 //===--------------------------------------------------------------===// 1811 1812 [&](const Fortran::lower::details::DynamicArrayDynamicChar &x) { 1813 if (genUnusedEntryPointBox()) 1814 return; 1815 mlir::Value addr; 1816 mlir::Value len; 1817 mlir::Value argBox; 1818 auto charLen = x.charLen(); 1819 // if element type is a CHARACTER, determine the LEN value 1820 if (isDummy) { 1821 mlir::Value actualArg = symMap.lookupSymbol(sym).getAddr(); 1822 if (auto boxTy = actualArg.getType().dyn_cast<fir::BoxType>()) { 1823 argBox = actualArg; 1824 mlir::Type refTy = builder.getRefType(boxTy.getEleTy()); 1825 addr = builder.create<fir::BoxAddrOp>(loc, refTy, argBox); 1826 if (charLen) 1827 // Set/override LEN with an expression. 1828 len = genExplicitCharLen(charLen); 1829 else 1830 // Get the length from the actual arguments. 1831 len = charHelp.readLengthFromBox(argBox); 1832 } else { 1833 std::pair<mlir::Value, mlir::Value> unboxchar = 1834 charHelp.createUnboxChar(actualArg); 1835 addr = unboxchar.first; 1836 if (charLen) { 1837 // Set/override LEN with an expression 1838 len = genExplicitCharLen(charLen); 1839 } else { 1840 // Get the length from the actual arguments. 1841 len = unboxchar.second; 1842 } 1843 } 1844 } else { 1845 // local CHARACTER variable 1846 len = genExplicitCharLen(charLen); 1847 } 1848 llvm::SmallVector<mlir::Value> lengths = {len}; 1849 1850 // cast to the known constant parts from the declaration 1851 mlir::Type castTy = builder.getRefType(converter.genType(var)); 1852 if (addr) 1853 addr = builder.createConvert(loc, castTy, addr); 1854 if (x.lboundAllOnes()) { 1855 // if lower bounds are all ones, build simple shaped object 1856 llvm::SmallVector<mlir::Value> shape; 1857 populateShape(shape, x.bounds, argBox); 1858 if (isDummy) { 1859 symMap.addCharSymbolWithShape(sym, addr, len, shape, true); 1860 return; 1861 } 1862 // local CHARACTER array 1863 mlir::Value local = 1864 createNewLocal(converter, loc, var, preAlloc, shape, lengths); 1865 symMap.addCharSymbolWithShape(sym, local, len, shape); 1866 return; 1867 } 1868 // Process the lower bound and extent values. 1869 llvm::SmallVector<mlir::Value> extents; 1870 llvm::SmallVector<mlir::Value> lbounds; 1871 populateLBoundsExtents(lbounds, extents, x.bounds, argBox); 1872 if (isDummy) { 1873 symMap.addCharSymbolWithBounds(sym, addr, len, extents, lbounds, 1874 true); 1875 return; 1876 } 1877 // local CHARACTER array with computed bounds 1878 assert(Fortran::lower::isExplicitShape(sym)); 1879 mlir::Value local = 1880 createNewLocal(converter, loc, var, preAlloc, extents, lengths); 1881 symMap.addCharSymbolWithBounds(sym, local, len, extents, lbounds); 1882 }, 1883 1884 //===--------------------------------------------------------------===// 1885 1886 [&](const Fortran::lower::BoxAnalyzer::None &) { 1887 mlir::emitError(loc, "symbol analysis failed on ") 1888 << toStringRef(sym.name()); 1889 }); 1890 } 1891 1892 void Fortran::lower::defineModuleVariable( 1893 AbstractConverter &converter, const Fortran::lower::pft::Variable &var) { 1894 // Use empty linkage for module variables, which makes them available 1895 // for use in another unit. 1896 mlir::StringAttr linkage = 1897 getLinkageAttribute(converter.getFirOpBuilder(), var); 1898 if (!var.isGlobal()) 1899 fir::emitFatalError(converter.getCurrentLocation(), 1900 "attempting to lower module variable as local"); 1901 // Define aggregate storages for equivalenced objects. 1902 if (var.isAggregateStore()) { 1903 const Fortran::lower::pft::Variable::AggregateStore &aggregate = 1904 var.getAggregateStore(); 1905 std::string aggName = mangleGlobalAggregateStore(aggregate); 1906 defineGlobalAggregateStore(converter, aggregate, aggName, linkage); 1907 return; 1908 } 1909 const Fortran::semantics::Symbol &sym = var.getSymbol(); 1910 if (const Fortran::semantics::Symbol *common = 1911 Fortran::semantics::FindCommonBlockContaining(var.getSymbol())) { 1912 // Nothing to do, common block are generated before everything. Ensure 1913 // this was done by calling getCommonBlockGlobal. 1914 getCommonBlockGlobal(converter, *common); 1915 } else if (var.isAlias()) { 1916 // Do nothing. Mapping will be done on user side. 1917 } else { 1918 std::string globalName = Fortran::lower::mangle::mangleName(sym); 1919 defineGlobal(converter, var, globalName, linkage); 1920 } 1921 } 1922 1923 void Fortran::lower::instantiateVariable(AbstractConverter &converter, 1924 const pft::Variable &var, 1925 Fortran::lower::SymMap &symMap, 1926 AggregateStoreMap &storeMap) { 1927 if (var.isAggregateStore()) { 1928 instantiateAggregateStore(converter, var, storeMap); 1929 } else if (const Fortran::semantics::Symbol *common = 1930 Fortran::semantics::FindCommonBlockContaining( 1931 var.getSymbol().GetUltimate())) { 1932 instantiateCommon(converter, *common, var, symMap); 1933 } else if (var.isAlias()) { 1934 instantiateAlias(converter, var, symMap, storeMap); 1935 } else if (var.isGlobal()) { 1936 instantiateGlobal(converter, var, symMap); 1937 } else { 1938 instantiateLocal(converter, var, symMap); 1939 } 1940 } 1941 1942 void Fortran::lower::mapCallInterfaceSymbols( 1943 AbstractConverter &converter, const Fortran::lower::CallerInterface &caller, 1944 SymMap &symMap) { 1945 Fortran::lower::AggregateStoreMap storeMap; 1946 const Fortran::semantics::Symbol &result = caller.getResultSymbol(); 1947 for (Fortran::lower::pft::Variable var : 1948 Fortran::lower::pft::buildFuncResultDependencyList(result)) { 1949 if (var.isAggregateStore()) { 1950 instantiateVariable(converter, var, symMap, storeMap); 1951 } else { 1952 const Fortran::semantics::Symbol &sym = var.getSymbol(); 1953 const auto *hostDetails = 1954 sym.detailsIf<Fortran::semantics::HostAssocDetails>(); 1955 if (hostDetails && !var.isModuleVariable()) { 1956 // The callee is an internal procedure `A` whose result properties 1957 // depend on host variables. The caller may be the host, or another 1958 // internal procedure `B` contained in the same host. In the first 1959 // case, the host symbol is obviously mapped, in the second case, it 1960 // must also be mapped because 1961 // HostAssociations::internalProcedureBindings that was called when 1962 // lowering `B` will have mapped all host symbols of captured variables 1963 // to the tuple argument containing the composite of all host associated 1964 // variables, whether or not the host symbol is actually referred to in 1965 // `B`. Hence it is possible to simply lookup the variable associated to 1966 // the host symbol without having to go back to the tuple argument. 1967 Fortran::lower::SymbolBox hostValue = 1968 symMap.lookupSymbol(hostDetails->symbol()); 1969 assert(hostValue && "callee host symbol must be mapped on caller side"); 1970 symMap.addSymbol(sym, hostValue.toExtendedValue()); 1971 // The SymbolBox associated to the host symbols is complete, skip 1972 // instantiateVariable that would try to allocate a new storage. 1973 continue; 1974 } 1975 if (Fortran::semantics::IsDummy(sym) && sym.owner() == result.owner()) { 1976 // Get the argument for the dummy argument symbols of the current call. 1977 symMap.addSymbol(sym, caller.getArgumentValue(sym)); 1978 // All the properties of the dummy variable may not come from the actual 1979 // argument, let instantiateVariable handle this. 1980 } 1981 // If this is neither a host associated or dummy symbol, it must be a 1982 // module or common block variable to satisfy specification expression 1983 // requirements in 10.1.11, instantiateVariable will get its address and 1984 // properties. 1985 instantiateVariable(converter, var, symMap, storeMap); 1986 } 1987 } 1988 } 1989 1990 void Fortran::lower::createRuntimeTypeInfoGlobal( 1991 Fortran::lower::AbstractConverter &converter, mlir::Location loc, 1992 const Fortran::semantics::Symbol &typeInfoSym) { 1993 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 1994 std::string globalName = Fortran::lower::mangle::mangleName(typeInfoSym); 1995 auto var = Fortran::lower::pft::Variable(typeInfoSym, /*global=*/true); 1996 mlir::StringAttr linkage = getLinkageAttribute(builder, var); 1997 defineGlobal(converter, var, globalName, linkage); 1998 } 1999