1 //===-- Bridge.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/Bridge.h" 14 #include "flang/Evaluate/tools.h" 15 #include "flang/Lower/Allocatable.h" 16 #include "flang/Lower/CallInterface.h" 17 #include "flang/Lower/ConvertExpr.h" 18 #include "flang/Lower/ConvertType.h" 19 #include "flang/Lower/ConvertVariable.h" 20 #include "flang/Lower/IO.h" 21 #include "flang/Lower/IterationSpace.h" 22 #include "flang/Lower/Mangler.h" 23 #include "flang/Lower/OpenMP.h" 24 #include "flang/Lower/PFTBuilder.h" 25 #include "flang/Lower/Runtime.h" 26 #include "flang/Lower/StatementContext.h" 27 #include "flang/Lower/SymbolMap.h" 28 #include "flang/Lower/Todo.h" 29 #include "flang/Optimizer/Builder/BoxValue.h" 30 #include "flang/Optimizer/Builder/Character.h" 31 #include "flang/Optimizer/Builder/MutableBox.h" 32 #include "flang/Optimizer/Builder/Runtime/Character.h" 33 #include "flang/Optimizer/Builder/Runtime/Ragged.h" 34 #include "flang/Optimizer/Dialect/FIRAttr.h" 35 #include "flang/Optimizer/Support/FIRContext.h" 36 #include "flang/Optimizer/Support/InternalNames.h" 37 #include "flang/Runtime/iostat.h" 38 #include "flang/Semantics/tools.h" 39 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" 40 #include "mlir/IR/PatternMatch.h" 41 #include "mlir/Transforms/RegionUtils.h" 42 #include "llvm/Support/CommandLine.h" 43 #include "llvm/Support/Debug.h" 44 45 #define DEBUG_TYPE "flang-lower-bridge" 46 47 using namespace mlir; 48 49 static llvm::cl::opt<bool> dumpBeforeFir( 50 "fdebug-dump-pre-fir", llvm::cl::init(false), 51 llvm::cl::desc("dump the Pre-FIR tree prior to FIR generation")); 52 53 namespace { 54 /// Helper class to generate the runtime type info global data. This data 55 /// is required to describe the derived type to the runtime so that it can 56 /// operate over it. It must be ensured this data will be generated for every 57 /// derived type lowered in the current translated unit. However, this data 58 /// cannot be generated before FuncOp have been created for functions since the 59 /// initializers may take their address (e.g for type bound procedures). This 60 /// class allows registering all the required runtime type info while it is not 61 /// possible to create globals, and to generate this data after function 62 /// lowering. 63 class RuntimeTypeInfoConverter { 64 /// Store the location and symbols of derived type info to be generated. 65 /// The location of the derived type instantiation is also stored because 66 /// runtime type descriptor symbol are compiler generated and cannot be mapped 67 /// to user code on their own. 68 struct TypeInfoSymbol { 69 Fortran::semantics::SymbolRef symbol; 70 mlir::Location loc; 71 }; 72 73 public: 74 void registerTypeInfoSymbol(Fortran::lower::AbstractConverter &converter, 75 mlir::Location loc, 76 Fortran::semantics::SymbolRef typeInfoSym) { 77 if (seen.contains(typeInfoSym)) 78 return; 79 seen.insert(typeInfoSym); 80 if (!skipRegistration) { 81 registeredTypeInfoSymbols.emplace_back(TypeInfoSymbol{typeInfoSym, loc}); 82 return; 83 } 84 // Once the registration is closed, symbols cannot be added to the 85 // registeredTypeInfoSymbols list because it may be iterated over. 86 // However, after registration is closed, it is safe to directly generate 87 // the globals because all FuncOps whose addresses may be required by the 88 // initializers have been generated. 89 Fortran::lower::createRuntimeTypeInfoGlobal(converter, loc, 90 typeInfoSym.get()); 91 } 92 93 void createTypeInfoGlobals(Fortran::lower::AbstractConverter &converter) { 94 skipRegistration = true; 95 for (const TypeInfoSymbol &info : registeredTypeInfoSymbols) 96 Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.loc, 97 info.symbol.get()); 98 registeredTypeInfoSymbols.clear(); 99 } 100 101 private: 102 /// Store the runtime type descriptors that will be required for the 103 /// derived type that have been converted to FIR derived types. 104 llvm::SmallVector<TypeInfoSymbol> registeredTypeInfoSymbols; 105 /// Create derived type runtime info global immediately without storing the 106 /// symbol in registeredTypeInfoSymbols. 107 bool skipRegistration = false; 108 /// Track symbols symbols processed during and after the registration 109 /// to avoid infinite loops between type conversions and global variable 110 /// creation. 111 llvm::SmallSetVector<Fortran::semantics::SymbolRef, 64> seen; 112 }; 113 } // namespace 114 115 //===----------------------------------------------------------------------===// 116 // FirConverter 117 //===----------------------------------------------------------------------===// 118 119 namespace { 120 121 /// Traverse the pre-FIR tree (PFT) to generate the FIR dialect of MLIR. 122 class FirConverter : public Fortran::lower::AbstractConverter { 123 public: 124 explicit FirConverter(Fortran::lower::LoweringBridge &bridge) 125 : bridge{bridge}, foldingContext{bridge.createFoldingContext()} {} 126 virtual ~FirConverter() = default; 127 128 /// Convert the PFT to FIR. 129 void run(Fortran::lower::pft::Program &pft) { 130 // Preliminary translation pass. 131 // - Declare all functions that have definitions so that definition 132 // signatures prevail over call site signatures. 133 // - Define module variables and OpenMP/OpenACC declarative construct so 134 // that they are available before lowering any function that may use 135 // them. 136 // - Translate block data programs so that common block definitions with 137 // data initializations take precedence over other definitions. 138 for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) { 139 std::visit( 140 Fortran::common::visitors{ 141 [&](Fortran::lower::pft::FunctionLikeUnit &f) { 142 declareFunction(f); 143 }, 144 [&](Fortran::lower::pft::ModuleLikeUnit &m) { 145 lowerModuleDeclScope(m); 146 for (Fortran::lower::pft::FunctionLikeUnit &f : 147 m.nestedFunctions) 148 declareFunction(f); 149 }, 150 [&](Fortran::lower::pft::BlockDataUnit &b) { lowerBlockData(b); }, 151 [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {}, 152 }, 153 u); 154 } 155 156 // Primary translation pass. 157 for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) { 158 std::visit( 159 Fortran::common::visitors{ 160 [&](Fortran::lower::pft::FunctionLikeUnit &f) { lowerFunc(f); }, 161 [&](Fortran::lower::pft::ModuleLikeUnit &m) { lowerMod(m); }, 162 [&](Fortran::lower::pft::BlockDataUnit &b) {}, 163 [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {}, 164 }, 165 u); 166 } 167 168 /// Once all the code has been translated, create runtime type info 169 /// global data structure for the derived types that have been 170 /// processed. 171 createGlobalOutsideOfFunctionLowering( 172 [&]() { runtimeTypeInfoConverter.createTypeInfoGlobals(*this); }); 173 } 174 175 /// Declare a function. 176 void declareFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { 177 setCurrentPosition(funit.getStartingSourceLoc()); 178 for (int entryIndex = 0, last = funit.entryPointList.size(); 179 entryIndex < last; ++entryIndex) { 180 funit.setActiveEntry(entryIndex); 181 // Calling CalleeInterface ctor will build a declaration mlir::FuncOp with 182 // no other side effects. 183 // TODO: when doing some compiler profiling on real apps, it may be worth 184 // to check it's better to save the CalleeInterface instead of recomputing 185 // it later when lowering the body. CalleeInterface ctor should be linear 186 // with the number of arguments, so it is not awful to do it that way for 187 // now, but the linear coefficient might be non negligible. Until 188 // measured, stick to the solution that impacts the code less. 189 Fortran::lower::CalleeInterface{funit, *this}; 190 } 191 funit.setActiveEntry(0); 192 193 // Compute the set of host associated entities from the nested functions. 194 llvm::SetVector<const Fortran::semantics::Symbol *> escapeHost; 195 for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions) 196 collectHostAssociatedVariables(f, escapeHost); 197 funit.setHostAssociatedSymbols(escapeHost); 198 199 // Declare internal procedures 200 for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions) 201 declareFunction(f); 202 } 203 204 /// Collects the canonical list of all host associated symbols. These bindings 205 /// must be aggregated into a tuple which can then be added to each of the 206 /// internal procedure declarations and passed at each call site. 207 void collectHostAssociatedVariables( 208 Fortran::lower::pft::FunctionLikeUnit &funit, 209 llvm::SetVector<const Fortran::semantics::Symbol *> &escapees) { 210 const Fortran::semantics::Scope *internalScope = 211 funit.getSubprogramSymbol().scope(); 212 assert(internalScope && "internal procedures symbol must create a scope"); 213 auto addToListIfEscapee = [&](const Fortran::semantics::Symbol &sym) { 214 const Fortran::semantics::Symbol &ultimate = sym.GetUltimate(); 215 const auto *namelistDetails = 216 ultimate.detailsIf<Fortran::semantics::NamelistDetails>(); 217 if (ultimate.has<Fortran::semantics::ObjectEntityDetails>() || 218 Fortran::semantics::IsProcedurePointer(ultimate) || 219 Fortran::semantics::IsDummy(sym) || namelistDetails) { 220 const Fortran::semantics::Scope &ultimateScope = ultimate.owner(); 221 if (ultimateScope.kind() == 222 Fortran::semantics::Scope::Kind::MainProgram || 223 ultimateScope.kind() == Fortran::semantics::Scope::Kind::Subprogram) 224 if (ultimateScope != *internalScope && 225 ultimateScope.Contains(*internalScope)) { 226 if (namelistDetails) { 227 // So far, namelist symbols are processed on the fly in IO and 228 // the related namelist data structure is not added to the symbol 229 // map, so it cannot be passed to the internal procedures. 230 // Instead, all the symbols of the host namelist used in the 231 // internal procedure must be considered as host associated so 232 // that IO lowering can find them when needed. 233 for (const auto &namelistObject : namelistDetails->objects()) 234 escapees.insert(&*namelistObject); 235 } else { 236 escapees.insert(&ultimate); 237 } 238 } 239 } 240 }; 241 Fortran::lower::pft::visitAllSymbols(funit, addToListIfEscapee); 242 } 243 244 //===--------------------------------------------------------------------===// 245 // AbstractConverter overrides 246 //===--------------------------------------------------------------------===// 247 248 mlir::Value getSymbolAddress(Fortran::lower::SymbolRef sym) override final { 249 return lookupSymbol(sym).getAddr(); 250 } 251 252 mlir::Value impliedDoBinding(llvm::StringRef name) override final { 253 mlir::Value val = localSymbols.lookupImpliedDo(name); 254 if (!val) 255 fir::emitFatalError(toLocation(), "ac-do-variable has no binding"); 256 return val; 257 } 258 259 void copySymbolBinding(Fortran::lower::SymbolRef src, 260 Fortran::lower::SymbolRef target) override final { 261 localSymbols.addSymbol(target, lookupSymbol(src).toExtendedValue()); 262 } 263 264 /// Add the symbol binding to the inner-most level of the symbol map and 265 /// return true if it is not already present. Otherwise, return false. 266 bool bindIfNewSymbol(Fortran::lower::SymbolRef sym, 267 const fir::ExtendedValue &exval) { 268 if (shallowLookupSymbol(sym)) 269 return false; 270 bindSymbol(sym, exval); 271 return true; 272 } 273 274 void bindSymbol(Fortran::lower::SymbolRef sym, 275 const fir::ExtendedValue &exval) override final { 276 localSymbols.addSymbol(sym, exval, /*forced=*/true); 277 } 278 279 bool lookupLabelSet(Fortran::lower::SymbolRef sym, 280 Fortran::lower::pft::LabelSet &labelSet) override final { 281 Fortran::lower::pft::FunctionLikeUnit &owningProc = 282 *getEval().getOwningProcedure(); 283 auto iter = owningProc.assignSymbolLabelMap.find(sym); 284 if (iter == owningProc.assignSymbolLabelMap.end()) 285 return false; 286 labelSet = iter->second; 287 return true; 288 } 289 290 Fortran::lower::pft::Evaluation * 291 lookupLabel(Fortran::lower::pft::Label label) override final { 292 Fortran::lower::pft::FunctionLikeUnit &owningProc = 293 *getEval().getOwningProcedure(); 294 auto iter = owningProc.labelEvaluationMap.find(label); 295 if (iter == owningProc.labelEvaluationMap.end()) 296 return nullptr; 297 return iter->second; 298 } 299 300 fir::ExtendedValue genExprAddr(const Fortran::lower::SomeExpr &expr, 301 Fortran::lower::StatementContext &context, 302 mlir::Location *loc = nullptr) override final { 303 return createSomeExtendedAddress(loc ? *loc : toLocation(), *this, expr, 304 localSymbols, context); 305 } 306 fir::ExtendedValue 307 genExprValue(const Fortran::lower::SomeExpr &expr, 308 Fortran::lower::StatementContext &context, 309 mlir::Location *loc = nullptr) override final { 310 return createSomeExtendedExpression(loc ? *loc : toLocation(), *this, expr, 311 localSymbols, context); 312 } 313 fir::MutableBoxValue 314 genExprMutableBox(mlir::Location loc, 315 const Fortran::lower::SomeExpr &expr) override final { 316 return Fortran::lower::createMutableBox(loc, *this, expr, localSymbols); 317 } 318 fir::ExtendedValue genExprBox(const Fortran::lower::SomeExpr &expr, 319 Fortran::lower::StatementContext &context, 320 mlir::Location loc) override final { 321 return Fortran::lower::createBoxValue(loc, *this, expr, localSymbols, 322 context); 323 } 324 325 Fortran::evaluate::FoldingContext &getFoldingContext() override final { 326 return foldingContext; 327 } 328 329 mlir::Type genType(const Fortran::lower::SomeExpr &expr) override final { 330 return Fortran::lower::translateSomeExprToFIRType(*this, expr); 331 } 332 mlir::Type genType(Fortran::lower::SymbolRef sym) override final { 333 return Fortran::lower::translateSymbolToFIRType(*this, sym); 334 } 335 mlir::Type 336 genType(Fortran::common::TypeCategory tc, int kind, 337 llvm::ArrayRef<std::int64_t> lenParameters) override final { 338 return Fortran::lower::getFIRType(&getMLIRContext(), tc, kind, 339 lenParameters); 340 } 341 mlir::Type 342 genType(const Fortran::semantics::DerivedTypeSpec &tySpec) override final { 343 return Fortran::lower::translateDerivedTypeToFIRType(*this, tySpec); 344 } 345 mlir::Type genType(Fortran::common::TypeCategory tc) override final { 346 TODO_NOLOC("Not implemented genType TypeCategory. Needed for more complex " 347 "expression lowering"); 348 } 349 mlir::Type genType(const Fortran::lower::pft::Variable &var) override final { 350 return Fortran::lower::translateVariableToFIRType(*this, var); 351 } 352 353 void setCurrentPosition(const Fortran::parser::CharBlock &position) { 354 if (position != Fortran::parser::CharBlock{}) 355 currentPosition = position; 356 } 357 358 //===--------------------------------------------------------------------===// 359 // Utility methods 360 //===--------------------------------------------------------------------===// 361 362 /// Convert a parser CharBlock to a Location 363 mlir::Location toLocation(const Fortran::parser::CharBlock &cb) { 364 return genLocation(cb); 365 } 366 367 mlir::Location toLocation() { return toLocation(currentPosition); } 368 void setCurrentEval(Fortran::lower::pft::Evaluation &eval) { 369 evalPtr = &eval; 370 } 371 Fortran::lower::pft::Evaluation &getEval() { 372 assert(evalPtr && "current evaluation not set"); 373 return *evalPtr; 374 } 375 376 mlir::Location getCurrentLocation() override final { return toLocation(); } 377 378 /// Generate a dummy location. 379 mlir::Location genUnknownLocation() override final { 380 // Note: builder may not be instantiated yet 381 return mlir::UnknownLoc::get(&getMLIRContext()); 382 } 383 384 /// Generate a `Location` from the `CharBlock`. 385 mlir::Location 386 genLocation(const Fortran::parser::CharBlock &block) override final { 387 if (const Fortran::parser::AllCookedSources *cooked = 388 bridge.getCookedSource()) { 389 if (std::optional<std::pair<Fortran::parser::SourcePosition, 390 Fortran::parser::SourcePosition>> 391 loc = cooked->GetSourcePositionRange(block)) { 392 // loc is a pair (begin, end); use the beginning position 393 Fortran::parser::SourcePosition &filePos = loc->first; 394 return mlir::FileLineColLoc::get(&getMLIRContext(), filePos.file.path(), 395 filePos.line, filePos.column); 396 } 397 } 398 return genUnknownLocation(); 399 } 400 401 fir::FirOpBuilder &getFirOpBuilder() override final { return *builder; } 402 403 mlir::ModuleOp &getModuleOp() override final { return bridge.getModule(); } 404 405 mlir::MLIRContext &getMLIRContext() override final { 406 return bridge.getMLIRContext(); 407 } 408 std::string 409 mangleName(const Fortran::semantics::Symbol &symbol) override final { 410 return Fortran::lower::mangle::mangleName(symbol); 411 } 412 413 const fir::KindMapping &getKindMap() override final { 414 return bridge.getKindMap(); 415 } 416 417 /// Return the predicate: "current block does not have a terminator branch". 418 bool blockIsUnterminated() { 419 mlir::Block *currentBlock = builder->getBlock(); 420 return currentBlock->empty() || 421 !currentBlock->back().hasTrait<mlir::OpTrait::IsTerminator>(); 422 } 423 424 /// Unconditionally switch code insertion to a new block. 425 void startBlock(mlir::Block *newBlock) { 426 assert(newBlock && "missing block"); 427 // Default termination for the current block is a fallthrough branch to 428 // the new block. 429 if (blockIsUnterminated()) 430 genFIRBranch(newBlock); 431 // Some blocks may be re/started more than once, and might not be empty. 432 // If the new block already has (only) a terminator, set the insertion 433 // point to the start of the block. Otherwise set it to the end. 434 // Note that setting the insertion point causes the subsequent function 435 // call to check the existence of terminator in the newBlock. 436 builder->setInsertionPointToStart(newBlock); 437 if (blockIsUnterminated()) 438 builder->setInsertionPointToEnd(newBlock); 439 } 440 441 /// Conditionally switch code insertion to a new block. 442 void maybeStartBlock(mlir::Block *newBlock) { 443 if (newBlock) 444 startBlock(newBlock); 445 } 446 447 /// Emit return and cleanup after the function has been translated. 448 void endNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { 449 setCurrentPosition(Fortran::lower::pft::stmtSourceLoc(funit.endStmt)); 450 if (funit.isMainProgram()) 451 genExitRoutine(); 452 else 453 genFIRProcedureExit(funit, funit.getSubprogramSymbol()); 454 funit.finalBlock = nullptr; 455 LLVM_DEBUG(llvm::dbgs() << "*** Lowering result:\n\n" 456 << *builder->getFunction() << '\n'); 457 // FIXME: Simplification should happen in a normal pass, not here. 458 mlir::IRRewriter rewriter(*builder); 459 (void)mlir::simplifyRegions(rewriter, 460 {builder->getRegion()}); // remove dead code 461 delete builder; 462 builder = nullptr; 463 hostAssocTuple = mlir::Value{}; 464 localSymbols.clear(); 465 } 466 467 /// Helper to generate GlobalOps when the builder is not positioned in any 468 /// region block. This is required because the FirOpBuilder assumes it is 469 /// always positioned inside a region block when creating globals, the easiest 470 /// way comply is to create a dummy function and to throw it afterwards. 471 void createGlobalOutsideOfFunctionLowering( 472 const std::function<void()> &createGlobals) { 473 // FIXME: get rid of the bogus function context and instantiate the 474 // globals directly into the module. 475 MLIRContext *context = &getMLIRContext(); 476 mlir::FuncOp func = fir::FirOpBuilder::createFunction( 477 mlir::UnknownLoc::get(context), getModuleOp(), 478 fir::NameUniquer::doGenerated("Sham"), 479 mlir::FunctionType::get(context, llvm::None, llvm::None)); 480 func.addEntryBlock(); 481 builder = new fir::FirOpBuilder(func, bridge.getKindMap()); 482 createGlobals(); 483 if (mlir::Region *region = func.getCallableRegion()) 484 region->dropAllReferences(); 485 func.erase(); 486 delete builder; 487 builder = nullptr; 488 localSymbols.clear(); 489 } 490 /// Instantiate the data from a BLOCK DATA unit. 491 void lowerBlockData(Fortran::lower::pft::BlockDataUnit &bdunit) { 492 createGlobalOutsideOfFunctionLowering([&]() { 493 Fortran::lower::AggregateStoreMap fakeMap; 494 for (const auto &[_, sym] : bdunit.symTab) { 495 if (sym->has<Fortran::semantics::ObjectEntityDetails>()) { 496 Fortran::lower::pft::Variable var(*sym, true); 497 instantiateVar(var, fakeMap); 498 } 499 } 500 }); 501 } 502 503 /// Map mlir function block arguments to the corresponding Fortran dummy 504 /// variables. When the result is passed as a hidden argument, the Fortran 505 /// result is also mapped. The symbol map is used to hold this mapping. 506 void mapDummiesAndResults(Fortran::lower::pft::FunctionLikeUnit &funit, 507 const Fortran::lower::CalleeInterface &callee) { 508 assert(builder && "require a builder object at this point"); 509 using PassBy = Fortran::lower::CalleeInterface::PassEntityBy; 510 auto mapPassedEntity = [&](const auto arg) -> void { 511 if (arg.passBy == PassBy::AddressAndLength) { 512 // TODO: now that fir call has some attributes regarding character 513 // return, PassBy::AddressAndLength should be retired. 514 mlir::Location loc = toLocation(); 515 fir::factory::CharacterExprHelper charHelp{*builder, loc}; 516 mlir::Value box = 517 charHelp.createEmboxChar(arg.firArgument, arg.firLength); 518 addSymbol(arg.entity->get(), box); 519 } else { 520 if (arg.entity.has_value()) { 521 addSymbol(arg.entity->get(), arg.firArgument); 522 } else { 523 assert(funit.parentHasHostAssoc()); 524 funit.parentHostAssoc().internalProcedureBindings(*this, 525 localSymbols); 526 } 527 } 528 }; 529 for (const Fortran::lower::CalleeInterface::PassedEntity &arg : 530 callee.getPassedArguments()) 531 mapPassedEntity(arg); 532 533 // Allocate local skeleton instances of dummies from other entry points. 534 // Most of these locals will not survive into final generated code, but 535 // some will. It is illegal to reference them at run time if they do. 536 for (const Fortran::semantics::Symbol *arg : 537 funit.nonUniversalDummyArguments) { 538 if (lookupSymbol(*arg)) 539 continue; 540 mlir::Type type = genType(*arg); 541 // TODO: Account for VALUE arguments (and possibly other variants). 542 type = builder->getRefType(type); 543 addSymbol(*arg, builder->create<fir::UndefOp>(toLocation(), type)); 544 } 545 if (std::optional<Fortran::lower::CalleeInterface::PassedEntity> 546 passedResult = callee.getPassedResult()) { 547 mapPassedEntity(*passedResult); 548 // FIXME: need to make sure things are OK here. addSymbol may not be OK 549 if (funit.primaryResult && 550 passedResult->entity->get() != *funit.primaryResult) 551 addSymbol(*funit.primaryResult, 552 getSymbolAddress(passedResult->entity->get())); 553 } 554 } 555 556 /// Instantiate variable \p var and add it to the symbol map. 557 /// See ConvertVariable.cpp. 558 void instantiateVar(const Fortran::lower::pft::Variable &var, 559 Fortran::lower::AggregateStoreMap &storeMap) { 560 Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap); 561 } 562 563 /// Prepare to translate a new function 564 void startNewFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { 565 assert(!builder && "expected nullptr"); 566 Fortran::lower::CalleeInterface callee(funit, *this); 567 mlir::FuncOp func = callee.addEntryBlockAndMapArguments(); 568 func.setVisibility(mlir::SymbolTable::Visibility::Public); 569 builder = new fir::FirOpBuilder(func, bridge.getKindMap()); 570 assert(builder && "FirOpBuilder did not instantiate"); 571 builder->setInsertionPointToStart(&func.front()); 572 573 mapDummiesAndResults(funit, callee); 574 575 // Note: not storing Variable references because getOrderedSymbolTable 576 // below returns a temporary. 577 llvm::SmallVector<Fortran::lower::pft::Variable> deferredFuncResultList; 578 579 // Backup actual argument for entry character results 580 // with different lengths. It needs to be added to the non 581 // primary results symbol before mapSymbolAttributes is called. 582 Fortran::lower::SymbolBox resultArg; 583 if (std::optional<Fortran::lower::CalleeInterface::PassedEntity> 584 passedResult = callee.getPassedResult()) 585 resultArg = lookupSymbol(passedResult->entity->get()); 586 587 Fortran::lower::AggregateStoreMap storeMap; 588 // The front-end is currently not adding module variables referenced 589 // in a module procedure as host associated. As a result we need to 590 // instantiate all module variables here if this is a module procedure. 591 // It is likely that the front-end behavior should change here. 592 // This also applies to internal procedures inside module procedures. 593 if (auto *module = Fortran::lower::pft::getAncestor< 594 Fortran::lower::pft::ModuleLikeUnit>(funit)) 595 for (const Fortran::lower::pft::Variable &var : 596 module->getOrderedSymbolTable()) 597 instantiateVar(var, storeMap); 598 599 mlir::Value primaryFuncResultStorage; 600 for (const Fortran::lower::pft::Variable &var : 601 funit.getOrderedSymbolTable()) { 602 // Always instantiate aggregate storage blocks. 603 if (var.isAggregateStore()) { 604 instantiateVar(var, storeMap); 605 continue; 606 } 607 const Fortran::semantics::Symbol &sym = var.getSymbol(); 608 if (funit.parentHasHostAssoc()) { 609 // Never instantitate host associated variables, as they are already 610 // instantiated from an argument tuple. Instead, just bind the symbol to 611 // the reference to the host variable, which must be in the map. 612 const Fortran::semantics::Symbol &ultimate = sym.GetUltimate(); 613 if (funit.parentHostAssoc().isAssociated(ultimate)) { 614 Fortran::lower::SymbolBox hostBox = 615 localSymbols.lookupSymbol(ultimate); 616 assert(hostBox && "host association is not in map"); 617 localSymbols.addSymbol(sym, hostBox.toExtendedValue()); 618 continue; 619 } 620 } 621 if (!sym.IsFuncResult() || !funit.primaryResult) { 622 instantiateVar(var, storeMap); 623 } else if (&sym == funit.primaryResult) { 624 instantiateVar(var, storeMap); 625 primaryFuncResultStorage = getSymbolAddress(sym); 626 } else { 627 deferredFuncResultList.push_back(var); 628 } 629 } 630 631 // If this is a host procedure with host associations, then create the tuple 632 // of pointers for passing to the internal procedures. 633 if (!funit.getHostAssoc().empty()) 634 funit.getHostAssoc().hostProcedureBindings(*this, localSymbols); 635 636 /// TODO: should use same mechanism as equivalence? 637 /// One blocking point is character entry returns that need special handling 638 /// since they are not locally allocated but come as argument. CHARACTER(*) 639 /// is not something that fit wells with equivalence lowering. 640 for (const Fortran::lower::pft::Variable &altResult : 641 deferredFuncResultList) { 642 if (std::optional<Fortran::lower::CalleeInterface::PassedEntity> 643 passedResult = callee.getPassedResult()) 644 addSymbol(altResult.getSymbol(), resultArg.getAddr()); 645 Fortran::lower::StatementContext stmtCtx; 646 Fortran::lower::mapSymbolAttributes(*this, altResult, localSymbols, 647 stmtCtx, primaryFuncResultStorage); 648 } 649 650 // Create most function blocks in advance. 651 createEmptyGlobalBlocks(funit.evaluationList); 652 653 // Reinstate entry block as the current insertion point. 654 builder->setInsertionPointToEnd(&func.front()); 655 656 if (callee.hasAlternateReturns()) { 657 // Create a local temp to hold the alternate return index. 658 // Give it an integer index type and the subroutine name (for dumps). 659 // Attach it to the subroutine symbol in the localSymbols map. 660 // Initialize it to zero, the "fallthrough" alternate return value. 661 const Fortran::semantics::Symbol &symbol = funit.getSubprogramSymbol(); 662 mlir::Location loc = toLocation(); 663 mlir::Type idxTy = builder->getIndexType(); 664 mlir::Value altResult = 665 builder->createTemporary(loc, idxTy, toStringRef(symbol.name())); 666 addSymbol(symbol, altResult); 667 mlir::Value zero = builder->createIntegerConstant(loc, idxTy, 0); 668 builder->create<fir::StoreOp>(loc, zero, altResult); 669 } 670 671 if (Fortran::lower::pft::Evaluation *alternateEntryEval = 672 funit.getEntryEval()) 673 genFIRBranch(alternateEntryEval->lexicalSuccessor->block); 674 } 675 676 /// Create global blocks for the current function. This eliminates the 677 /// distinction between forward and backward targets when generating 678 /// branches. A block is "global" if it can be the target of a GOTO or 679 /// other source code branch. A block that can only be targeted by a 680 /// compiler generated branch is "local". For example, a DO loop preheader 681 /// block containing loop initialization code is global. A loop header 682 /// block, which is the target of the loop back edge, is local. Blocks 683 /// belong to a region. Any block within a nested region must be replaced 684 /// with a block belonging to that region. Branches may not cross region 685 /// boundaries. 686 void createEmptyGlobalBlocks( 687 std::list<Fortran::lower::pft::Evaluation> &evaluationList) { 688 mlir::Region *region = &builder->getRegion(); 689 for (Fortran::lower::pft::Evaluation &eval : evaluationList) { 690 if (eval.isNewBlock) 691 eval.block = builder->createBlock(region); 692 if (eval.isConstruct() || eval.isDirective()) { 693 if (eval.lowerAsUnstructured()) { 694 createEmptyGlobalBlocks(eval.getNestedEvaluations()); 695 } else if (eval.hasNestedEvaluations()) { 696 // A structured construct that is a target starts a new block. 697 Fortran::lower::pft::Evaluation &constructStmt = 698 eval.getFirstNestedEvaluation(); 699 if (constructStmt.isNewBlock) 700 constructStmt.block = builder->createBlock(region); 701 } 702 } 703 } 704 } 705 706 /// Lower a procedure (nest). 707 void lowerFunc(Fortran::lower::pft::FunctionLikeUnit &funit) { 708 if (!funit.isMainProgram()) { 709 const Fortran::semantics::Symbol &procSymbol = 710 funit.getSubprogramSymbol(); 711 if (procSymbol.owner().IsSubmodule()) { 712 TODO(toLocation(), "support submodules"); 713 return; 714 } 715 } 716 setCurrentPosition(funit.getStartingSourceLoc()); 717 for (int entryIndex = 0, last = funit.entryPointList.size(); 718 entryIndex < last; ++entryIndex) { 719 funit.setActiveEntry(entryIndex); 720 startNewFunction(funit); // the entry point for lowering this procedure 721 for (Fortran::lower::pft::Evaluation &eval : funit.evaluationList) 722 genFIR(eval); 723 endNewFunction(funit); 724 } 725 funit.setActiveEntry(0); 726 for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions) 727 lowerFunc(f); // internal procedure 728 } 729 730 /// Lower module variable definitions to fir::globalOp and OpenMP/OpenACC 731 /// declarative construct. 732 void lowerModuleDeclScope(Fortran::lower::pft::ModuleLikeUnit &mod) { 733 setCurrentPosition(mod.getStartingSourceLoc()); 734 createGlobalOutsideOfFunctionLowering([&]() { 735 for (const Fortran::lower::pft::Variable &var : 736 mod.getOrderedSymbolTable()) { 737 // Only define the variables owned by this module. 738 const Fortran::semantics::Scope *owningScope = var.getOwningScope(); 739 if (!owningScope || mod.getScope() == *owningScope) 740 Fortran::lower::defineModuleVariable(*this, var); 741 } 742 for (auto &eval : mod.evaluationList) 743 genFIR(eval); 744 }); 745 } 746 747 /// Lower functions contained in a module. 748 void lowerMod(Fortran::lower::pft::ModuleLikeUnit &mod) { 749 for (Fortran::lower::pft::FunctionLikeUnit &f : mod.nestedFunctions) 750 lowerFunc(f); 751 } 752 753 mlir::Value hostAssocTupleValue() override final { return hostAssocTuple; } 754 755 /// Record a binding for the ssa-value of the tuple for this function. 756 void bindHostAssocTuple(mlir::Value val) override final { 757 assert(!hostAssocTuple && val); 758 hostAssocTuple = val; 759 } 760 761 void registerRuntimeTypeInfo( 762 mlir::Location loc, 763 Fortran::lower::SymbolRef typeInfoSym) override final { 764 runtimeTypeInfoConverter.registerTypeInfoSymbol(*this, loc, typeInfoSym); 765 } 766 767 private: 768 FirConverter() = delete; 769 FirConverter(const FirConverter &) = delete; 770 FirConverter &operator=(const FirConverter &) = delete; 771 772 //===--------------------------------------------------------------------===// 773 // Helper member functions 774 //===--------------------------------------------------------------------===// 775 776 mlir::Value createFIRExpr(mlir::Location loc, 777 const Fortran::lower::SomeExpr *expr, 778 Fortran::lower::StatementContext &stmtCtx) { 779 return fir::getBase(genExprValue(*expr, stmtCtx, &loc)); 780 } 781 782 /// Find the symbol in the local map or return null. 783 Fortran::lower::SymbolBox 784 lookupSymbol(const Fortran::semantics::Symbol &sym) { 785 if (Fortran::lower::SymbolBox v = localSymbols.lookupSymbol(sym)) 786 return v; 787 return {}; 788 } 789 790 /// Find the symbol in the inner-most level of the local map or return null. 791 Fortran::lower::SymbolBox 792 shallowLookupSymbol(const Fortran::semantics::Symbol &sym) { 793 if (Fortran::lower::SymbolBox v = localSymbols.shallowLookupSymbol(sym)) 794 return v; 795 return {}; 796 } 797 798 /// Add the symbol to the local map and return `true`. If the symbol is 799 /// already in the map and \p forced is `false`, the map is not updated. 800 /// Instead the value `false` is returned. 801 bool addSymbol(const Fortran::semantics::SymbolRef sym, mlir::Value val, 802 bool forced = false) { 803 if (!forced && lookupSymbol(sym)) 804 return false; 805 localSymbols.addSymbol(sym, val, forced); 806 return true; 807 } 808 809 bool isNumericScalarCategory(Fortran::common::TypeCategory cat) { 810 return cat == Fortran::common::TypeCategory::Integer || 811 cat == Fortran::common::TypeCategory::Real || 812 cat == Fortran::common::TypeCategory::Complex || 813 cat == Fortran::common::TypeCategory::Logical; 814 } 815 static bool isLogicalCategory(Fortran::common::TypeCategory cat) { 816 return cat == Fortran::common::TypeCategory::Logical; 817 } 818 bool isCharacterCategory(Fortran::common::TypeCategory cat) { 819 return cat == Fortran::common::TypeCategory::Character; 820 } 821 bool isDerivedCategory(Fortran::common::TypeCategory cat) { 822 return cat == Fortran::common::TypeCategory::Derived; 823 } 824 825 /// Insert a new block before \p block. Leave the insertion point unchanged. 826 mlir::Block *insertBlock(mlir::Block *block) { 827 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint(); 828 mlir::Block *newBlock = builder->createBlock(block); 829 builder->restoreInsertionPoint(insertPt); 830 return newBlock; 831 } 832 833 mlir::Block *blockOfLabel(Fortran::lower::pft::Evaluation &eval, 834 Fortran::parser::Label label) { 835 const Fortran::lower::pft::LabelEvalMap &labelEvaluationMap = 836 eval.getOwningProcedure()->labelEvaluationMap; 837 const auto iter = labelEvaluationMap.find(label); 838 assert(iter != labelEvaluationMap.end() && "label missing from map"); 839 mlir::Block *block = iter->second->block; 840 assert(block && "missing labeled evaluation block"); 841 return block; 842 } 843 844 void genFIRBranch(mlir::Block *targetBlock) { 845 assert(targetBlock && "missing unconditional target block"); 846 builder->create<cf::BranchOp>(toLocation(), targetBlock); 847 } 848 849 void genFIRConditionalBranch(mlir::Value cond, mlir::Block *trueTarget, 850 mlir::Block *falseTarget) { 851 assert(trueTarget && "missing conditional branch true block"); 852 assert(falseTarget && "missing conditional branch false block"); 853 mlir::Location loc = toLocation(); 854 mlir::Value bcc = builder->createConvert(loc, builder->getI1Type(), cond); 855 builder->create<mlir::cf::CondBranchOp>(loc, bcc, trueTarget, llvm::None, 856 falseTarget, llvm::None); 857 } 858 void genFIRConditionalBranch(mlir::Value cond, 859 Fortran::lower::pft::Evaluation *trueTarget, 860 Fortran::lower::pft::Evaluation *falseTarget) { 861 genFIRConditionalBranch(cond, trueTarget->block, falseTarget->block); 862 } 863 void genFIRConditionalBranch(const Fortran::parser::ScalarLogicalExpr &expr, 864 mlir::Block *trueTarget, 865 mlir::Block *falseTarget) { 866 Fortran::lower::StatementContext stmtCtx; 867 mlir::Value cond = 868 createFIRExpr(toLocation(), Fortran::semantics::GetExpr(expr), stmtCtx); 869 stmtCtx.finalize(); 870 genFIRConditionalBranch(cond, trueTarget, falseTarget); 871 } 872 void genFIRConditionalBranch(const Fortran::parser::ScalarLogicalExpr &expr, 873 Fortran::lower::pft::Evaluation *trueTarget, 874 Fortran::lower::pft::Evaluation *falseTarget) { 875 Fortran::lower::StatementContext stmtCtx; 876 mlir::Value cond = 877 createFIRExpr(toLocation(), Fortran::semantics::GetExpr(expr), stmtCtx); 878 stmtCtx.finalize(); 879 genFIRConditionalBranch(cond, trueTarget->block, falseTarget->block); 880 } 881 882 //===--------------------------------------------------------------------===// 883 // Termination of symbolically referenced execution units 884 //===--------------------------------------------------------------------===// 885 886 /// END of program 887 /// 888 /// Generate the cleanup block before the program exits 889 void genExitRoutine() { 890 if (blockIsUnterminated()) 891 builder->create<mlir::func::ReturnOp>(toLocation()); 892 } 893 void genFIR(const Fortran::parser::EndProgramStmt &) { genExitRoutine(); } 894 895 /// END of procedure-like constructs 896 /// 897 /// Generate the cleanup block before the procedure exits 898 void genReturnSymbol(const Fortran::semantics::Symbol &functionSymbol) { 899 const Fortran::semantics::Symbol &resultSym = 900 functionSymbol.get<Fortran::semantics::SubprogramDetails>().result(); 901 Fortran::lower::SymbolBox resultSymBox = lookupSymbol(resultSym); 902 mlir::Location loc = toLocation(); 903 if (!resultSymBox) { 904 mlir::emitError(loc, "failed lowering function return"); 905 return; 906 } 907 mlir::Value resultVal = resultSymBox.match( 908 [&](const fir::CharBoxValue &x) -> mlir::Value { 909 return fir::factory::CharacterExprHelper{*builder, loc} 910 .createEmboxChar(x.getBuffer(), x.getLen()); 911 }, 912 [&](const auto &) -> mlir::Value { 913 mlir::Value resultRef = resultSymBox.getAddr(); 914 mlir::Type resultType = genType(resultSym); 915 mlir::Type resultRefType = builder->getRefType(resultType); 916 // A function with multiple entry points returning different types 917 // tags all result variables with one of the largest types to allow 918 // them to share the same storage. Convert this to the actual type. 919 if (resultRef.getType() != resultRefType) 920 resultRef = builder->createConvert(loc, resultRefType, resultRef); 921 return builder->create<fir::LoadOp>(loc, resultRef); 922 }); 923 builder->create<mlir::func::ReturnOp>(loc, resultVal); 924 } 925 926 /// Get the return value of a call to \p symbol, which is a subroutine entry 927 /// point that has alternative return specifiers. 928 const mlir::Value 929 getAltReturnResult(const Fortran::semantics::Symbol &symbol) { 930 assert(Fortran::semantics::HasAlternateReturns(symbol) && 931 "subroutine does not have alternate returns"); 932 return getSymbolAddress(symbol); 933 } 934 935 void genFIRProcedureExit(Fortran::lower::pft::FunctionLikeUnit &funit, 936 const Fortran::semantics::Symbol &symbol) { 937 if (mlir::Block *finalBlock = funit.finalBlock) { 938 // The current block must end with a terminator. 939 if (blockIsUnterminated()) 940 builder->create<mlir::cf::BranchOp>(toLocation(), finalBlock); 941 // Set insertion point to final block. 942 builder->setInsertionPoint(finalBlock, finalBlock->end()); 943 } 944 if (Fortran::semantics::IsFunction(symbol)) { 945 genReturnSymbol(symbol); 946 } else if (Fortran::semantics::HasAlternateReturns(symbol)) { 947 mlir::Value retval = builder->create<fir::LoadOp>( 948 toLocation(), getAltReturnResult(symbol)); 949 builder->create<mlir::func::ReturnOp>(toLocation(), retval); 950 } else { 951 genExitRoutine(); 952 } 953 } 954 955 // 956 // Statements that have control-flow semantics 957 // 958 959 /// Generate an If[Then]Stmt condition or its negation. 960 template <typename A> 961 mlir::Value genIfCondition(const A *stmt, bool negate = false) { 962 mlir::Location loc = toLocation(); 963 Fortran::lower::StatementContext stmtCtx; 964 mlir::Value condExpr = createFIRExpr( 965 loc, 966 Fortran::semantics::GetExpr( 967 std::get<Fortran::parser::ScalarLogicalExpr>(stmt->t)), 968 stmtCtx); 969 stmtCtx.finalize(); 970 mlir::Value cond = 971 builder->createConvert(loc, builder->getI1Type(), condExpr); 972 if (negate) 973 cond = builder->create<mlir::arith::XOrIOp>( 974 loc, cond, builder->createIntegerConstant(loc, cond.getType(), 1)); 975 return cond; 976 } 977 978 static bool 979 isArraySectionWithoutVectorSubscript(const Fortran::lower::SomeExpr &expr) { 980 return expr.Rank() > 0 && Fortran::evaluate::IsVariable(expr) && 981 !Fortran::evaluate::UnwrapWholeSymbolDataRef(expr) && 982 !Fortran::evaluate::HasVectorSubscript(expr); 983 } 984 985 [[maybe_unused]] static bool 986 isFuncResultDesignator(const Fortran::lower::SomeExpr &expr) { 987 const Fortran::semantics::Symbol *sym = 988 Fortran::evaluate::GetFirstSymbol(expr); 989 return sym && sym->IsFuncResult(); 990 } 991 992 static bool isWholeAllocatable(const Fortran::lower::SomeExpr &expr) { 993 const Fortran::semantics::Symbol *sym = 994 Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(expr); 995 return sym && Fortran::semantics::IsAllocatable(*sym); 996 } 997 998 /// Shared for both assignments and pointer assignments. 999 void genAssignment(const Fortran::evaluate::Assignment &assign) { 1000 Fortran::lower::StatementContext stmtCtx; 1001 mlir::Location loc = toLocation(); 1002 if (explicitIterationSpace()) { 1003 Fortran::lower::createArrayLoads(*this, explicitIterSpace, localSymbols); 1004 explicitIterSpace.genLoopNest(); 1005 } 1006 std::visit( 1007 Fortran::common::visitors{ 1008 // [1] Plain old assignment. 1009 [&](const Fortran::evaluate::Assignment::Intrinsic &) { 1010 const Fortran::semantics::Symbol *sym = 1011 Fortran::evaluate::GetLastSymbol(assign.lhs); 1012 1013 if (!sym) 1014 TODO(loc, "assignment to pointer result of function reference"); 1015 1016 std::optional<Fortran::evaluate::DynamicType> lhsType = 1017 assign.lhs.GetType(); 1018 assert(lhsType && "lhs cannot be typeless"); 1019 // Assignment to polymorphic allocatables may require changing the 1020 // variable dynamic type (See Fortran 2018 10.2.1.3 p3). 1021 if (lhsType->IsPolymorphic() && isWholeAllocatable(assign.lhs)) 1022 TODO(loc, "assignment to polymorphic allocatable"); 1023 1024 // Note: No ad-hoc handling for pointers is required here. The 1025 // target will be assigned as per 2018 10.2.1.3 p2. genExprAddr 1026 // on a pointer returns the target address and not the address of 1027 // the pointer variable. 1028 1029 if (assign.lhs.Rank() > 0 || explicitIterationSpace()) { 1030 // Array assignment 1031 // See Fortran 2018 10.2.1.3 p5, p6, and p7 1032 genArrayAssignment(assign, stmtCtx); 1033 return; 1034 } 1035 1036 // Scalar assignment 1037 const bool isNumericScalar = 1038 isNumericScalarCategory(lhsType->category()); 1039 fir::ExtendedValue rhs = isNumericScalar 1040 ? genExprValue(assign.rhs, stmtCtx) 1041 : genExprAddr(assign.rhs, stmtCtx); 1042 bool lhsIsWholeAllocatable = isWholeAllocatable(assign.lhs); 1043 llvm::Optional<fir::factory::MutableBoxReallocation> lhsRealloc; 1044 llvm::Optional<fir::MutableBoxValue> lhsMutableBox; 1045 auto lhs = [&]() -> fir::ExtendedValue { 1046 if (lhsIsWholeAllocatable) { 1047 lhsMutableBox = genExprMutableBox(loc, assign.lhs); 1048 llvm::SmallVector<mlir::Value> lengthParams; 1049 if (const fir::CharBoxValue *charBox = rhs.getCharBox()) 1050 lengthParams.push_back(charBox->getLen()); 1051 else if (fir::isDerivedWithLengthParameters(rhs)) 1052 TODO(loc, "assignment to derived type allocatable with " 1053 "length parameters"); 1054 lhsRealloc = fir::factory::genReallocIfNeeded( 1055 *builder, loc, *lhsMutableBox, 1056 /*shape=*/llvm::None, lengthParams); 1057 return lhsRealloc->newValue; 1058 } 1059 return genExprAddr(assign.lhs, stmtCtx); 1060 }(); 1061 1062 if (isNumericScalar) { 1063 // Fortran 2018 10.2.1.3 p8 and p9 1064 // Conversions should have been inserted by semantic analysis, 1065 // but they can be incorrect between the rhs and lhs. Correct 1066 // that here. 1067 mlir::Value addr = fir::getBase(lhs); 1068 mlir::Value val = fir::getBase(rhs); 1069 // A function with multiple entry points returning different 1070 // types tags all result variables with one of the largest 1071 // types to allow them to share the same storage. Assignment 1072 // to a result variable of one of the other types requires 1073 // conversion to the actual type. 1074 mlir::Type toTy = genType(assign.lhs); 1075 mlir::Value cast = 1076 builder->convertWithSemantics(loc, toTy, val); 1077 if (fir::dyn_cast_ptrEleTy(addr.getType()) != toTy) { 1078 assert(isFuncResultDesignator(assign.lhs) && "type mismatch"); 1079 addr = builder->createConvert( 1080 toLocation(), builder->getRefType(toTy), addr); 1081 } 1082 builder->create<fir::StoreOp>(loc, cast, addr); 1083 } else if (isCharacterCategory(lhsType->category())) { 1084 // Fortran 2018 10.2.1.3 p10 and p11 1085 fir::factory::CharacterExprHelper{*builder, loc}.createAssign( 1086 lhs, rhs); 1087 } else if (isDerivedCategory(lhsType->category())) { 1088 // Fortran 2018 10.2.1.3 p13 and p14 1089 // Recursively gen an assignment on each element pair. 1090 fir::factory::genRecordAssignment(*builder, loc, lhs, rhs); 1091 } else { 1092 llvm_unreachable("unknown category"); 1093 } 1094 if (lhsIsWholeAllocatable) 1095 fir::factory::finalizeRealloc( 1096 *builder, loc, lhsMutableBox.getValue(), 1097 /*lbounds=*/llvm::None, /*takeLboundsIfRealloc=*/false, 1098 lhsRealloc.getValue()); 1099 }, 1100 1101 // [2] User defined assignment. If the context is a scalar 1102 // expression then call the procedure. 1103 [&](const Fortran::evaluate::ProcedureRef &procRef) { 1104 Fortran::lower::StatementContext &ctx = 1105 explicitIterationSpace() ? explicitIterSpace.stmtContext() 1106 : stmtCtx; 1107 Fortran::lower::createSubroutineCall( 1108 *this, procRef, explicitIterSpace, implicitIterSpace, 1109 localSymbols, ctx, /*isUserDefAssignment=*/true); 1110 }, 1111 1112 // [3] Pointer assignment with possibly empty bounds-spec. R1035: a 1113 // bounds-spec is a lower bound value. 1114 [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) { 1115 if (IsProcedure(assign.rhs)) 1116 TODO(loc, "procedure pointer assignment"); 1117 std::optional<Fortran::evaluate::DynamicType> lhsType = 1118 assign.lhs.GetType(); 1119 std::optional<Fortran::evaluate::DynamicType> rhsType = 1120 assign.rhs.GetType(); 1121 // Polymorphic lhs/rhs may need more care. See F2018 10.2.2.3. 1122 if ((lhsType && lhsType->IsPolymorphic()) || 1123 (rhsType && rhsType->IsPolymorphic())) 1124 TODO(loc, "pointer assignment involving polymorphic entity"); 1125 1126 // FIXME: in the explicit space context, we want to use 1127 // ScalarArrayExprLowering here. 1128 fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs); 1129 llvm::SmallVector<mlir::Value> lbounds; 1130 for (const Fortran::evaluate::ExtentExpr &lbExpr : lbExprs) 1131 lbounds.push_back( 1132 fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx))); 1133 Fortran::lower::associateMutableBox(*this, loc, lhs, assign.rhs, 1134 lbounds, stmtCtx); 1135 if (explicitIterationSpace()) { 1136 mlir::ValueRange inners = explicitIterSpace.getInnerArgs(); 1137 if (!inners.empty()) { 1138 // TODO: should force a copy-in/copy-out here. 1139 // e.g., obj%ptr(i+1) => obj%ptr(i) 1140 builder->create<fir::ResultOp>(loc, inners); 1141 } 1142 } 1143 }, 1144 1145 // [4] Pointer assignment with bounds-remapping. R1036: a 1146 // bounds-remapping is a pair, lower bound and upper bound. 1147 [&](const Fortran::evaluate::Assignment::BoundsRemapping 1148 &boundExprs) { 1149 std::optional<Fortran::evaluate::DynamicType> lhsType = 1150 assign.lhs.GetType(); 1151 std::optional<Fortran::evaluate::DynamicType> rhsType = 1152 assign.rhs.GetType(); 1153 // Polymorphic lhs/rhs may need more care. See F2018 10.2.2.3. 1154 if ((lhsType && lhsType->IsPolymorphic()) || 1155 (rhsType && rhsType->IsPolymorphic())) 1156 TODO(loc, "pointer assignment involving polymorphic entity"); 1157 1158 // FIXME: in the explicit space context, we want to use 1159 // ScalarArrayExprLowering here. 1160 fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs); 1161 if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>( 1162 assign.rhs)) { 1163 fir::factory::disassociateMutableBox(*builder, loc, lhs); 1164 return; 1165 } 1166 llvm::SmallVector<mlir::Value> lbounds; 1167 llvm::SmallVector<mlir::Value> ubounds; 1168 for (const std::pair<Fortran::evaluate::ExtentExpr, 1169 Fortran::evaluate::ExtentExpr> &pair : 1170 boundExprs) { 1171 const Fortran::evaluate::ExtentExpr &lbExpr = pair.first; 1172 const Fortran::evaluate::ExtentExpr &ubExpr = pair.second; 1173 lbounds.push_back( 1174 fir::getBase(genExprValue(toEvExpr(lbExpr), stmtCtx))); 1175 ubounds.push_back( 1176 fir::getBase(genExprValue(toEvExpr(ubExpr), stmtCtx))); 1177 } 1178 // Do not generate a temp in case rhs is an array section. 1179 fir::ExtendedValue rhs = 1180 isArraySectionWithoutVectorSubscript(assign.rhs) 1181 ? Fortran::lower::createSomeArrayBox( 1182 *this, assign.rhs, localSymbols, stmtCtx) 1183 : genExprAddr(assign.rhs, stmtCtx); 1184 fir::factory::associateMutableBoxWithRemap(*builder, loc, lhs, 1185 rhs, lbounds, ubounds); 1186 if (explicitIterationSpace()) { 1187 mlir::ValueRange inners = explicitIterSpace.getInnerArgs(); 1188 if (!inners.empty()) { 1189 // TODO: should force a copy-in/copy-out here. 1190 // e.g., obj%ptr(i+1) => obj%ptr(i) 1191 builder->create<fir::ResultOp>(loc, inners); 1192 } 1193 } 1194 }, 1195 }, 1196 assign.u); 1197 if (explicitIterationSpace()) 1198 Fortran::lower::createArrayMergeStores(*this, explicitIterSpace); 1199 } 1200 1201 /// Lowering of CALL statement 1202 void genFIR(const Fortran::parser::CallStmt &stmt) { 1203 Fortran::lower::StatementContext stmtCtx; 1204 Fortran::lower::pft::Evaluation &eval = getEval(); 1205 setCurrentPosition(stmt.v.source); 1206 assert(stmt.typedCall && "Call was not analyzed"); 1207 // Call statement lowering shares code with function call lowering. 1208 mlir::Value res = Fortran::lower::createSubroutineCall( 1209 *this, *stmt.typedCall, explicitIterSpace, implicitIterSpace, 1210 localSymbols, stmtCtx, /*isUserDefAssignment=*/false); 1211 if (!res) 1212 return; // "Normal" subroutine call. 1213 // Call with alternate return specifiers. 1214 // The call returns an index that selects an alternate return branch target. 1215 llvm::SmallVector<int64_t> indexList; 1216 llvm::SmallVector<mlir::Block *> blockList; 1217 int64_t index = 0; 1218 for (const Fortran::parser::ActualArgSpec &arg : 1219 std::get<std::list<Fortran::parser::ActualArgSpec>>(stmt.v.t)) { 1220 const auto &actual = std::get<Fortran::parser::ActualArg>(arg.t); 1221 if (const auto *altReturn = 1222 std::get_if<Fortran::parser::AltReturnSpec>(&actual.u)) { 1223 indexList.push_back(++index); 1224 blockList.push_back(blockOfLabel(eval, altReturn->v)); 1225 } 1226 } 1227 blockList.push_back(eval.nonNopSuccessor().block); // default = fallthrough 1228 stmtCtx.finalize(); 1229 builder->create<fir::SelectOp>(toLocation(), res, indexList, blockList); 1230 } 1231 1232 void genFIR(const Fortran::parser::ComputedGotoStmt &stmt) { 1233 Fortran::lower::StatementContext stmtCtx; 1234 Fortran::lower::pft::Evaluation &eval = getEval(); 1235 mlir::Value selectExpr = 1236 createFIRExpr(toLocation(), 1237 Fortran::semantics::GetExpr( 1238 std::get<Fortran::parser::ScalarIntExpr>(stmt.t)), 1239 stmtCtx); 1240 stmtCtx.finalize(); 1241 llvm::SmallVector<int64_t> indexList; 1242 llvm::SmallVector<mlir::Block *> blockList; 1243 int64_t index = 0; 1244 for (Fortran::parser::Label label : 1245 std::get<std::list<Fortran::parser::Label>>(stmt.t)) { 1246 indexList.push_back(++index); 1247 blockList.push_back(blockOfLabel(eval, label)); 1248 } 1249 blockList.push_back(eval.nonNopSuccessor().block); // default 1250 builder->create<fir::SelectOp>(toLocation(), selectExpr, indexList, 1251 blockList); 1252 } 1253 1254 void genFIR(const Fortran::parser::ArithmeticIfStmt &stmt) { 1255 Fortran::lower::StatementContext stmtCtx; 1256 Fortran::lower::pft::Evaluation &eval = getEval(); 1257 mlir::Value expr = createFIRExpr( 1258 toLocation(), 1259 Fortran::semantics::GetExpr(std::get<Fortran::parser::Expr>(stmt.t)), 1260 stmtCtx); 1261 stmtCtx.finalize(); 1262 mlir::Type exprType = expr.getType(); 1263 mlir::Location loc = toLocation(); 1264 if (exprType.isSignlessInteger()) { 1265 // Arithmetic expression has Integer type. Generate a SelectCaseOp 1266 // with ranges {(-inf:-1], 0=default, [1:inf)}. 1267 MLIRContext *context = builder->getContext(); 1268 llvm::SmallVector<mlir::Attribute> attrList; 1269 llvm::SmallVector<mlir::Value> valueList; 1270 llvm::SmallVector<mlir::Block *> blockList; 1271 attrList.push_back(fir::UpperBoundAttr::get(context)); 1272 valueList.push_back(builder->createIntegerConstant(loc, exprType, -1)); 1273 blockList.push_back(blockOfLabel(eval, std::get<1>(stmt.t))); 1274 attrList.push_back(fir::LowerBoundAttr::get(context)); 1275 valueList.push_back(builder->createIntegerConstant(loc, exprType, 1)); 1276 blockList.push_back(blockOfLabel(eval, std::get<3>(stmt.t))); 1277 attrList.push_back(mlir::UnitAttr::get(context)); // 0 is the "default" 1278 blockList.push_back(blockOfLabel(eval, std::get<2>(stmt.t))); 1279 builder->create<fir::SelectCaseOp>(loc, expr, attrList, valueList, 1280 blockList); 1281 return; 1282 } 1283 // Arithmetic expression has Real type. Generate 1284 // sum = expr + expr [ raise an exception if expr is a NaN ] 1285 // if (sum < 0.0) goto L1 else if (sum > 0.0) goto L3 else goto L2 1286 auto sum = builder->create<mlir::arith::AddFOp>(loc, expr, expr); 1287 auto zero = builder->create<mlir::arith::ConstantOp>( 1288 loc, exprType, builder->getFloatAttr(exprType, 0.0)); 1289 auto cond1 = builder->create<mlir::arith::CmpFOp>( 1290 loc, mlir::arith::CmpFPredicate::OLT, sum, zero); 1291 mlir::Block *elseIfBlock = 1292 builder->getBlock()->splitBlock(builder->getInsertionPoint()); 1293 genFIRConditionalBranch(cond1, blockOfLabel(eval, std::get<1>(stmt.t)), 1294 elseIfBlock); 1295 startBlock(elseIfBlock); 1296 auto cond2 = builder->create<mlir::arith::CmpFOp>( 1297 loc, mlir::arith::CmpFPredicate::OGT, sum, zero); 1298 genFIRConditionalBranch(cond2, blockOfLabel(eval, std::get<3>(stmt.t)), 1299 blockOfLabel(eval, std::get<2>(stmt.t))); 1300 } 1301 1302 void genFIR(const Fortran::parser::AssignedGotoStmt &stmt) { 1303 // Program requirement 1990 8.2.4 - 1304 // 1305 // At the time of execution of an assigned GOTO statement, the integer 1306 // variable must be defined with the value of a statement label of a 1307 // branch target statement that appears in the same scoping unit. 1308 // Note that the variable may be defined with a statement label value 1309 // only by an ASSIGN statement in the same scoping unit as the assigned 1310 // GOTO statement. 1311 1312 mlir::Location loc = toLocation(); 1313 Fortran::lower::pft::Evaluation &eval = getEval(); 1314 const Fortran::lower::pft::SymbolLabelMap &symbolLabelMap = 1315 eval.getOwningProcedure()->assignSymbolLabelMap; 1316 const Fortran::semantics::Symbol &symbol = 1317 *std::get<Fortran::parser::Name>(stmt.t).symbol; 1318 auto selectExpr = 1319 builder->create<fir::LoadOp>(loc, getSymbolAddress(symbol)); 1320 auto iter = symbolLabelMap.find(symbol); 1321 if (iter == symbolLabelMap.end()) { 1322 // Fail for a nonconforming program unit that does not have any ASSIGN 1323 // statements. The front end should check for this. 1324 mlir::emitError(loc, "(semantics issue) no assigned goto targets"); 1325 exit(1); 1326 } 1327 auto labelSet = iter->second; 1328 llvm::SmallVector<int64_t> indexList; 1329 llvm::SmallVector<mlir::Block *> blockList; 1330 auto addLabel = [&](Fortran::parser::Label label) { 1331 indexList.push_back(label); 1332 blockList.push_back(blockOfLabel(eval, label)); 1333 }; 1334 // Add labels from an explicit list. The list may have duplicates. 1335 for (Fortran::parser::Label label : 1336 std::get<std::list<Fortran::parser::Label>>(stmt.t)) { 1337 if (labelSet.count(label) && 1338 std::find(indexList.begin(), indexList.end(), label) == 1339 indexList.end()) { // ignore duplicates 1340 addLabel(label); 1341 } 1342 } 1343 // Absent an explicit list, add all possible label targets. 1344 if (indexList.empty()) 1345 for (auto &label : labelSet) 1346 addLabel(label); 1347 // Add a nop/fallthrough branch to the switch for a nonconforming program 1348 // unit that violates the program requirement above. 1349 blockList.push_back(eval.nonNopSuccessor().block); // default 1350 builder->create<fir::SelectOp>(loc, selectExpr, indexList, blockList); 1351 } 1352 1353 void genFIR(const Fortran::parser::DoConstruct &doConstruct) { 1354 TODO(toLocation(), "DoConstruct lowering"); 1355 } 1356 1357 void genFIR(const Fortran::parser::IfConstruct &) { 1358 mlir::Location loc = toLocation(); 1359 Fortran::lower::pft::Evaluation &eval = getEval(); 1360 if (eval.lowerAsStructured()) { 1361 // Structured fir.if nest. 1362 fir::IfOp topIfOp, currentIfOp; 1363 for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) { 1364 auto genIfOp = [&](mlir::Value cond) { 1365 auto ifOp = builder->create<fir::IfOp>(loc, cond, /*withElse=*/true); 1366 builder->setInsertionPointToStart(&ifOp.getThenRegion().front()); 1367 return ifOp; 1368 }; 1369 if (auto *s = e.getIf<Fortran::parser::IfThenStmt>()) { 1370 topIfOp = currentIfOp = genIfOp(genIfCondition(s, e.negateCondition)); 1371 } else if (auto *s = e.getIf<Fortran::parser::IfStmt>()) { 1372 topIfOp = currentIfOp = genIfOp(genIfCondition(s, e.negateCondition)); 1373 } else if (auto *s = e.getIf<Fortran::parser::ElseIfStmt>()) { 1374 builder->setInsertionPointToStart( 1375 ¤tIfOp.getElseRegion().front()); 1376 currentIfOp = genIfOp(genIfCondition(s)); 1377 } else if (e.isA<Fortran::parser::ElseStmt>()) { 1378 builder->setInsertionPointToStart( 1379 ¤tIfOp.getElseRegion().front()); 1380 } else if (e.isA<Fortran::parser::EndIfStmt>()) { 1381 builder->setInsertionPointAfter(topIfOp); 1382 } else { 1383 genFIR(e, /*unstructuredContext=*/false); 1384 } 1385 } 1386 return; 1387 } 1388 1389 // Unstructured branch sequence. 1390 for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) { 1391 auto genIfBranch = [&](mlir::Value cond) { 1392 if (e.lexicalSuccessor == e.controlSuccessor) // empty block -> exit 1393 genFIRConditionalBranch(cond, e.parentConstruct->constructExit, 1394 e.controlSuccessor); 1395 else // non-empty block 1396 genFIRConditionalBranch(cond, e.lexicalSuccessor, e.controlSuccessor); 1397 }; 1398 if (auto *s = e.getIf<Fortran::parser::IfThenStmt>()) { 1399 maybeStartBlock(e.block); 1400 genIfBranch(genIfCondition(s, e.negateCondition)); 1401 } else if (auto *s = e.getIf<Fortran::parser::IfStmt>()) { 1402 maybeStartBlock(e.block); 1403 genIfBranch(genIfCondition(s, e.negateCondition)); 1404 } else if (auto *s = e.getIf<Fortran::parser::ElseIfStmt>()) { 1405 startBlock(e.block); 1406 genIfBranch(genIfCondition(s)); 1407 } else { 1408 genFIR(e); 1409 } 1410 } 1411 } 1412 1413 void genFIR(const Fortran::parser::CaseConstruct &) { 1414 for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations()) 1415 genFIR(e); 1416 } 1417 1418 template <typename A> 1419 void genNestedStatement(const Fortran::parser::Statement<A> &stmt) { 1420 setCurrentPosition(stmt.source); 1421 genFIR(stmt.statement); 1422 } 1423 1424 /// Force the binding of an explicit symbol. This is used to bind and re-bind 1425 /// a concurrent control symbol to its value. 1426 void forceControlVariableBinding(const Fortran::semantics::Symbol *sym, 1427 mlir::Value inducVar) { 1428 mlir::Location loc = toLocation(); 1429 assert(sym && "There must be a symbol to bind"); 1430 mlir::Type toTy = genType(*sym); 1431 // FIXME: this should be a "per iteration" temporary. 1432 mlir::Value tmp = builder->createTemporary( 1433 loc, toTy, toStringRef(sym->name()), 1434 llvm::ArrayRef<mlir::NamedAttribute>{ 1435 Fortran::lower::getAdaptToByRefAttr(*builder)}); 1436 mlir::Value cast = builder->createConvert(loc, toTy, inducVar); 1437 builder->create<fir::StoreOp>(loc, cast, tmp); 1438 localSymbols.addSymbol(*sym, tmp, /*force=*/true); 1439 } 1440 1441 /// Process a concurrent header for a FORALL. (Concurrent headers for DO 1442 /// CONCURRENT loops are lowered elsewhere.) 1443 void genFIR(const Fortran::parser::ConcurrentHeader &header) { 1444 llvm::SmallVector<mlir::Value> lows; 1445 llvm::SmallVector<mlir::Value> highs; 1446 llvm::SmallVector<mlir::Value> steps; 1447 if (explicitIterSpace.isOutermostForall()) { 1448 // For the outermost forall, we evaluate the bounds expressions once. 1449 // Contrastingly, if this forall is nested, the bounds expressions are 1450 // assumed to be pure, possibly dependent on outer concurrent control 1451 // variables, possibly variant with respect to arguments, and will be 1452 // re-evaluated. 1453 mlir::Location loc = toLocation(); 1454 mlir::Type idxTy = builder->getIndexType(); 1455 Fortran::lower::StatementContext &stmtCtx = 1456 explicitIterSpace.stmtContext(); 1457 auto lowerExpr = [&](auto &e) { 1458 return fir::getBase(genExprValue(e, stmtCtx)); 1459 }; 1460 for (const Fortran::parser::ConcurrentControl &ctrl : 1461 std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) { 1462 const Fortran::lower::SomeExpr *lo = 1463 Fortran::semantics::GetExpr(std::get<1>(ctrl.t)); 1464 const Fortran::lower::SomeExpr *hi = 1465 Fortran::semantics::GetExpr(std::get<2>(ctrl.t)); 1466 auto &optStep = 1467 std::get<std::optional<Fortran::parser::ScalarIntExpr>>(ctrl.t); 1468 lows.push_back(builder->createConvert(loc, idxTy, lowerExpr(*lo))); 1469 highs.push_back(builder->createConvert(loc, idxTy, lowerExpr(*hi))); 1470 steps.push_back( 1471 optStep.has_value() 1472 ? builder->createConvert( 1473 loc, idxTy, 1474 lowerExpr(*Fortran::semantics::GetExpr(*optStep))) 1475 : builder->createIntegerConstant(loc, idxTy, 1)); 1476 } 1477 } 1478 auto lambda = [&, lows, highs, steps]() { 1479 // Create our iteration space from the header spec. 1480 mlir::Location loc = toLocation(); 1481 mlir::Type idxTy = builder->getIndexType(); 1482 llvm::SmallVector<fir::DoLoopOp> loops; 1483 Fortran::lower::StatementContext &stmtCtx = 1484 explicitIterSpace.stmtContext(); 1485 auto lowerExpr = [&](auto &e) { 1486 return fir::getBase(genExprValue(e, stmtCtx)); 1487 }; 1488 const bool outermost = !lows.empty(); 1489 std::size_t headerIndex = 0; 1490 for (const Fortran::parser::ConcurrentControl &ctrl : 1491 std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) { 1492 const Fortran::semantics::Symbol *ctrlVar = 1493 std::get<Fortran::parser::Name>(ctrl.t).symbol; 1494 mlir::Value lb; 1495 mlir::Value ub; 1496 mlir::Value by; 1497 if (outermost) { 1498 assert(headerIndex < lows.size()); 1499 if (headerIndex == 0) 1500 explicitIterSpace.resetInnerArgs(); 1501 lb = lows[headerIndex]; 1502 ub = highs[headerIndex]; 1503 by = steps[headerIndex++]; 1504 } else { 1505 const Fortran::lower::SomeExpr *lo = 1506 Fortran::semantics::GetExpr(std::get<1>(ctrl.t)); 1507 const Fortran::lower::SomeExpr *hi = 1508 Fortran::semantics::GetExpr(std::get<2>(ctrl.t)); 1509 auto &optStep = 1510 std::get<std::optional<Fortran::parser::ScalarIntExpr>>(ctrl.t); 1511 lb = builder->createConvert(loc, idxTy, lowerExpr(*lo)); 1512 ub = builder->createConvert(loc, idxTy, lowerExpr(*hi)); 1513 by = optStep.has_value() 1514 ? builder->createConvert( 1515 loc, idxTy, 1516 lowerExpr(*Fortran::semantics::GetExpr(*optStep))) 1517 : builder->createIntegerConstant(loc, idxTy, 1); 1518 } 1519 auto lp = builder->create<fir::DoLoopOp>( 1520 loc, lb, ub, by, /*unordered=*/true, 1521 /*finalCount=*/false, explicitIterSpace.getInnerArgs()); 1522 if (!loops.empty() || !outermost) 1523 builder->create<fir::ResultOp>(loc, lp.getResults()); 1524 explicitIterSpace.setInnerArgs(lp.getRegionIterArgs()); 1525 builder->setInsertionPointToStart(lp.getBody()); 1526 forceControlVariableBinding(ctrlVar, lp.getInductionVar()); 1527 loops.push_back(lp); 1528 } 1529 if (outermost) 1530 explicitIterSpace.setOuterLoop(loops[0]); 1531 explicitIterSpace.appendLoops(loops); 1532 if (const auto &mask = 1533 std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>( 1534 header.t); 1535 mask.has_value()) { 1536 mlir::Type i1Ty = builder->getI1Type(); 1537 fir::ExtendedValue maskExv = 1538 genExprValue(*Fortran::semantics::GetExpr(mask.value()), stmtCtx); 1539 mlir::Value cond = 1540 builder->createConvert(loc, i1Ty, fir::getBase(maskExv)); 1541 auto ifOp = builder->create<fir::IfOp>( 1542 loc, explicitIterSpace.innerArgTypes(), cond, 1543 /*withElseRegion=*/true); 1544 builder->create<fir::ResultOp>(loc, ifOp.getResults()); 1545 builder->setInsertionPointToStart(&ifOp.getElseRegion().front()); 1546 builder->create<fir::ResultOp>(loc, explicitIterSpace.getInnerArgs()); 1547 builder->setInsertionPointToStart(&ifOp.getThenRegion().front()); 1548 } 1549 }; 1550 // Push the lambda to gen the loop nest context. 1551 explicitIterSpace.pushLoopNest(lambda); 1552 } 1553 1554 void genFIR(const Fortran::parser::ForallAssignmentStmt &stmt) { 1555 std::visit([&](const auto &x) { genFIR(x); }, stmt.u); 1556 } 1557 1558 void genFIR(const Fortran::parser::EndForallStmt &) { 1559 cleanupExplicitSpace(); 1560 } 1561 1562 template <typename A> 1563 void prepareExplicitSpace(const A &forall) { 1564 if (!explicitIterSpace.isActive()) 1565 analyzeExplicitSpace(forall); 1566 localSymbols.pushScope(); 1567 explicitIterSpace.enter(); 1568 } 1569 1570 /// Cleanup all the FORALL context information when we exit. 1571 void cleanupExplicitSpace() { 1572 explicitIterSpace.leave(); 1573 localSymbols.popScope(); 1574 } 1575 1576 /// Generate FIR for a FORALL statement. 1577 void genFIR(const Fortran::parser::ForallStmt &stmt) { 1578 prepareExplicitSpace(stmt); 1579 genFIR(std::get< 1580 Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>( 1581 stmt.t) 1582 .value()); 1583 genFIR(std::get<Fortran::parser::UnlabeledStatement< 1584 Fortran::parser::ForallAssignmentStmt>>(stmt.t) 1585 .statement); 1586 cleanupExplicitSpace(); 1587 } 1588 1589 /// Generate FIR for a FORALL construct. 1590 void genFIR(const Fortran::parser::ForallConstruct &forall) { 1591 prepareExplicitSpace(forall); 1592 genNestedStatement( 1593 std::get< 1594 Fortran::parser::Statement<Fortran::parser::ForallConstructStmt>>( 1595 forall.t)); 1596 for (const Fortran::parser::ForallBodyConstruct &s : 1597 std::get<std::list<Fortran::parser::ForallBodyConstruct>>(forall.t)) { 1598 std::visit( 1599 Fortran::common::visitors{ 1600 [&](const Fortran::parser::WhereConstruct &b) { genFIR(b); }, 1601 [&](const Fortran::common::Indirection< 1602 Fortran::parser::ForallConstruct> &b) { genFIR(b.value()); }, 1603 [&](const auto &b) { genNestedStatement(b); }}, 1604 s.u); 1605 } 1606 genNestedStatement( 1607 std::get<Fortran::parser::Statement<Fortran::parser::EndForallStmt>>( 1608 forall.t)); 1609 } 1610 1611 /// Lower the concurrent header specification. 1612 void genFIR(const Fortran::parser::ForallConstructStmt &stmt) { 1613 genFIR(std::get< 1614 Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>( 1615 stmt.t) 1616 .value()); 1617 } 1618 1619 void genFIR(const Fortran::parser::CompilerDirective &) { 1620 TODO(toLocation(), "CompilerDirective lowering"); 1621 } 1622 1623 void genFIR(const Fortran::parser::OpenACCConstruct &) { 1624 TODO(toLocation(), "OpenACCConstruct lowering"); 1625 } 1626 1627 void genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &) { 1628 TODO(toLocation(), "OpenACCDeclarativeConstruct lowering"); 1629 } 1630 1631 void genFIR(const Fortran::parser::OpenMPConstruct &omp) { 1632 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint(); 1633 localSymbols.pushScope(); 1634 Fortran::lower::genOpenMPConstruct(*this, getEval(), omp); 1635 1636 for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations()) 1637 genFIR(e); 1638 localSymbols.popScope(); 1639 builder->restoreInsertionPoint(insertPt); 1640 } 1641 1642 void genFIR(const Fortran::parser::OpenMPDeclarativeConstruct &) { 1643 TODO(toLocation(), "OpenMPDeclarativeConstruct lowering"); 1644 } 1645 1646 /// Generate FIR for a SELECT CASE statement. 1647 /// The type may be CHARACTER, INTEGER, or LOGICAL. 1648 void genFIR(const Fortran::parser::SelectCaseStmt &stmt) { 1649 Fortran::lower::pft::Evaluation &eval = getEval(); 1650 MLIRContext *context = builder->getContext(); 1651 mlir::Location loc = toLocation(); 1652 Fortran::lower::StatementContext stmtCtx; 1653 const Fortran::lower::SomeExpr *expr = Fortran::semantics::GetExpr( 1654 std::get<Fortran::parser::Scalar<Fortran::parser::Expr>>(stmt.t)); 1655 bool isCharSelector = isCharacterCategory(expr->GetType()->category()); 1656 bool isLogicalSelector = isLogicalCategory(expr->GetType()->category()); 1657 auto charValue = [&](const Fortran::lower::SomeExpr *expr) { 1658 fir::ExtendedValue exv = genExprAddr(*expr, stmtCtx, &loc); 1659 return exv.match( 1660 [&](const fir::CharBoxValue &cbv) { 1661 return fir::factory::CharacterExprHelper{*builder, loc} 1662 .createEmboxChar(cbv.getAddr(), cbv.getLen()); 1663 }, 1664 [&](auto) { 1665 fir::emitFatalError(loc, "not a character"); 1666 return mlir::Value{}; 1667 }); 1668 }; 1669 mlir::Value selector; 1670 if (isCharSelector) { 1671 selector = charValue(expr); 1672 } else { 1673 selector = createFIRExpr(loc, expr, stmtCtx); 1674 if (isLogicalSelector) 1675 selector = builder->createConvert(loc, builder->getI1Type(), selector); 1676 } 1677 mlir::Type selectType = selector.getType(); 1678 llvm::SmallVector<mlir::Attribute> attrList; 1679 llvm::SmallVector<mlir::Value> valueList; 1680 llvm::SmallVector<mlir::Block *> blockList; 1681 mlir::Block *defaultBlock = eval.parentConstruct->constructExit->block; 1682 using CaseValue = Fortran::parser::Scalar<Fortran::parser::ConstantExpr>; 1683 auto addValue = [&](const CaseValue &caseValue) { 1684 const Fortran::lower::SomeExpr *expr = 1685 Fortran::semantics::GetExpr(caseValue.thing); 1686 if (isCharSelector) 1687 valueList.push_back(charValue(expr)); 1688 else if (isLogicalSelector) 1689 valueList.push_back(builder->createConvert( 1690 loc, selectType, createFIRExpr(toLocation(), expr, stmtCtx))); 1691 else 1692 valueList.push_back(builder->createIntegerConstant( 1693 loc, selectType, *Fortran::evaluate::ToInt64(*expr))); 1694 }; 1695 for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e; 1696 e = e->controlSuccessor) { 1697 const auto &caseStmt = e->getIf<Fortran::parser::CaseStmt>(); 1698 assert(e->block && "missing CaseStmt block"); 1699 const auto &caseSelector = 1700 std::get<Fortran::parser::CaseSelector>(caseStmt->t); 1701 const auto *caseValueRangeList = 1702 std::get_if<std::list<Fortran::parser::CaseValueRange>>( 1703 &caseSelector.u); 1704 if (!caseValueRangeList) { 1705 defaultBlock = e->block; 1706 continue; 1707 } 1708 for (const Fortran::parser::CaseValueRange &caseValueRange : 1709 *caseValueRangeList) { 1710 blockList.push_back(e->block); 1711 if (const auto *caseValue = std::get_if<CaseValue>(&caseValueRange.u)) { 1712 attrList.push_back(fir::PointIntervalAttr::get(context)); 1713 addValue(*caseValue); 1714 continue; 1715 } 1716 const auto &caseRange = 1717 std::get<Fortran::parser::CaseValueRange::Range>(caseValueRange.u); 1718 if (caseRange.lower && caseRange.upper) { 1719 attrList.push_back(fir::ClosedIntervalAttr::get(context)); 1720 addValue(*caseRange.lower); 1721 addValue(*caseRange.upper); 1722 } else if (caseRange.lower) { 1723 attrList.push_back(fir::LowerBoundAttr::get(context)); 1724 addValue(*caseRange.lower); 1725 } else { 1726 attrList.push_back(fir::UpperBoundAttr::get(context)); 1727 addValue(*caseRange.upper); 1728 } 1729 } 1730 } 1731 // Skip a logical default block that can never be referenced. 1732 if (isLogicalSelector && attrList.size() == 2) 1733 defaultBlock = eval.parentConstruct->constructExit->block; 1734 attrList.push_back(mlir::UnitAttr::get(context)); 1735 blockList.push_back(defaultBlock); 1736 1737 // Generate a fir::SelectCaseOp. 1738 // Explicit branch code is better for the LOGICAL type. The CHARACTER type 1739 // does not yet have downstream support, and also uses explicit branch code. 1740 // The -no-structured-fir option can be used to force generation of INTEGER 1741 // type branch code. 1742 if (!isLogicalSelector && !isCharSelector && eval.lowerAsStructured()) { 1743 // Numeric selector is a ssa register, all temps that may have 1744 // been generated while evaluating it can be cleaned-up before the 1745 // fir.select_case. 1746 stmtCtx.finalize(); 1747 builder->create<fir::SelectCaseOp>(loc, selector, attrList, valueList, 1748 blockList); 1749 return; 1750 } 1751 1752 // Generate a sequence of case value comparisons and branches. 1753 auto caseValue = valueList.begin(); 1754 auto caseBlock = blockList.begin(); 1755 for (mlir::Attribute attr : attrList) { 1756 if (attr.isa<mlir::UnitAttr>()) { 1757 genFIRBranch(*caseBlock++); 1758 break; 1759 } 1760 auto genCond = [&](mlir::Value rhs, 1761 mlir::arith::CmpIPredicate pred) -> mlir::Value { 1762 if (!isCharSelector) 1763 return builder->create<mlir::arith::CmpIOp>(loc, pred, selector, rhs); 1764 fir::factory::CharacterExprHelper charHelper{*builder, loc}; 1765 std::pair<mlir::Value, mlir::Value> lhsVal = 1766 charHelper.createUnboxChar(selector); 1767 mlir::Value &lhsAddr = lhsVal.first; 1768 mlir::Value &lhsLen = lhsVal.second; 1769 std::pair<mlir::Value, mlir::Value> rhsVal = 1770 charHelper.createUnboxChar(rhs); 1771 mlir::Value &rhsAddr = rhsVal.first; 1772 mlir::Value &rhsLen = rhsVal.second; 1773 return fir::runtime::genCharCompare(*builder, loc, pred, lhsAddr, 1774 lhsLen, rhsAddr, rhsLen); 1775 }; 1776 mlir::Block *newBlock = insertBlock(*caseBlock); 1777 if (attr.isa<fir::ClosedIntervalAttr>()) { 1778 mlir::Block *newBlock2 = insertBlock(*caseBlock); 1779 mlir::Value cond = 1780 genCond(*caseValue++, mlir::arith::CmpIPredicate::sge); 1781 genFIRConditionalBranch(cond, newBlock, newBlock2); 1782 builder->setInsertionPointToEnd(newBlock); 1783 mlir::Value cond2 = 1784 genCond(*caseValue++, mlir::arith::CmpIPredicate::sle); 1785 genFIRConditionalBranch(cond2, *caseBlock++, newBlock2); 1786 builder->setInsertionPointToEnd(newBlock2); 1787 continue; 1788 } 1789 mlir::arith::CmpIPredicate pred; 1790 if (attr.isa<fir::PointIntervalAttr>()) { 1791 pred = mlir::arith::CmpIPredicate::eq; 1792 } else if (attr.isa<fir::LowerBoundAttr>()) { 1793 pred = mlir::arith::CmpIPredicate::sge; 1794 } else { 1795 assert(attr.isa<fir::UpperBoundAttr>() && "unexpected predicate"); 1796 pred = mlir::arith::CmpIPredicate::sle; 1797 } 1798 mlir::Value cond = genCond(*caseValue++, pred); 1799 genFIRConditionalBranch(cond, *caseBlock++, newBlock); 1800 builder->setInsertionPointToEnd(newBlock); 1801 } 1802 assert(caseValue == valueList.end() && caseBlock == blockList.end() && 1803 "select case list mismatch"); 1804 // Clean-up the selector at the end of the construct if it is a temporary 1805 // (which is possible with characters). 1806 mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint(); 1807 builder->setInsertionPointToEnd(eval.parentConstruct->constructExit->block); 1808 stmtCtx.finalize(); 1809 builder->restoreInsertionPoint(insertPt); 1810 } 1811 1812 fir::ExtendedValue 1813 genAssociateSelector(const Fortran::lower::SomeExpr &selector, 1814 Fortran::lower::StatementContext &stmtCtx) { 1815 return isArraySectionWithoutVectorSubscript(selector) 1816 ? Fortran::lower::createSomeArrayBox(*this, selector, 1817 localSymbols, stmtCtx) 1818 : genExprAddr(selector, stmtCtx); 1819 } 1820 1821 void genFIR(const Fortran::parser::AssociateConstruct &) { 1822 Fortran::lower::StatementContext stmtCtx; 1823 Fortran::lower::pft::Evaluation &eval = getEval(); 1824 for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) { 1825 if (auto *stmt = e.getIf<Fortran::parser::AssociateStmt>()) { 1826 if (eval.lowerAsUnstructured()) 1827 maybeStartBlock(e.block); 1828 localSymbols.pushScope(); 1829 for (const Fortran::parser::Association &assoc : 1830 std::get<std::list<Fortran::parser::Association>>(stmt->t)) { 1831 Fortran::semantics::Symbol &sym = 1832 *std::get<Fortran::parser::Name>(assoc.t).symbol; 1833 const Fortran::lower::SomeExpr &selector = 1834 *sym.get<Fortran::semantics::AssocEntityDetails>().expr(); 1835 localSymbols.addSymbol(sym, genAssociateSelector(selector, stmtCtx)); 1836 } 1837 } else if (e.getIf<Fortran::parser::EndAssociateStmt>()) { 1838 if (eval.lowerAsUnstructured()) 1839 maybeStartBlock(e.block); 1840 stmtCtx.finalize(); 1841 localSymbols.popScope(); 1842 } else { 1843 genFIR(e); 1844 } 1845 } 1846 } 1847 1848 void genFIR(const Fortran::parser::BlockConstruct &blockConstruct) { 1849 TODO(toLocation(), "BlockConstruct lowering"); 1850 } 1851 1852 void genFIR(const Fortran::parser::BlockStmt &) { 1853 TODO(toLocation(), "BlockStmt lowering"); 1854 } 1855 1856 void genFIR(const Fortran::parser::EndBlockStmt &) { 1857 TODO(toLocation(), "EndBlockStmt lowering"); 1858 } 1859 1860 void genFIR(const Fortran::parser::ChangeTeamConstruct &construct) { 1861 TODO(toLocation(), "ChangeTeamConstruct lowering"); 1862 } 1863 1864 void genFIR(const Fortran::parser::ChangeTeamStmt &stmt) { 1865 TODO(toLocation(), "ChangeTeamStmt lowering"); 1866 } 1867 1868 void genFIR(const Fortran::parser::EndChangeTeamStmt &stmt) { 1869 TODO(toLocation(), "EndChangeTeamStmt lowering"); 1870 } 1871 1872 void genFIR(const Fortran::parser::CriticalConstruct &criticalConstruct) { 1873 TODO(toLocation(), "CriticalConstruct lowering"); 1874 } 1875 1876 void genFIR(const Fortran::parser::CriticalStmt &) { 1877 TODO(toLocation(), "CriticalStmt lowering"); 1878 } 1879 1880 void genFIR(const Fortran::parser::EndCriticalStmt &) { 1881 TODO(toLocation(), "EndCriticalStmt lowering"); 1882 } 1883 1884 void genFIR(const Fortran::parser::SelectRankConstruct &selectRankConstruct) { 1885 TODO(toLocation(), "SelectRankConstruct lowering"); 1886 } 1887 1888 void genFIR(const Fortran::parser::SelectRankStmt &) { 1889 TODO(toLocation(), "SelectRankStmt lowering"); 1890 } 1891 1892 void genFIR(const Fortran::parser::SelectRankCaseStmt &) { 1893 TODO(toLocation(), "SelectRankCaseStmt lowering"); 1894 } 1895 1896 void genFIR(const Fortran::parser::SelectTypeConstruct &selectTypeConstruct) { 1897 TODO(toLocation(), "SelectTypeConstruct lowering"); 1898 } 1899 1900 void genFIR(const Fortran::parser::SelectTypeStmt &) { 1901 TODO(toLocation(), "SelectTypeStmt lowering"); 1902 } 1903 1904 void genFIR(const Fortran::parser::TypeGuardStmt &) { 1905 TODO(toLocation(), "TypeGuardStmt lowering"); 1906 } 1907 1908 //===--------------------------------------------------------------------===// 1909 // IO statements (see io.h) 1910 //===--------------------------------------------------------------------===// 1911 1912 void genFIR(const Fortran::parser::BackspaceStmt &stmt) { 1913 mlir::Value iostat = genBackspaceStatement(*this, stmt); 1914 genIoConditionBranches(getEval(), stmt.v, iostat); 1915 } 1916 1917 void genFIR(const Fortran::parser::CloseStmt &stmt) { 1918 mlir::Value iostat = genCloseStatement(*this, stmt); 1919 genIoConditionBranches(getEval(), stmt.v, iostat); 1920 } 1921 1922 void genFIR(const Fortran::parser::EndfileStmt &stmt) { 1923 mlir::Value iostat = genEndfileStatement(*this, stmt); 1924 genIoConditionBranches(getEval(), stmt.v, iostat); 1925 } 1926 1927 void genFIR(const Fortran::parser::FlushStmt &stmt) { 1928 mlir::Value iostat = genFlushStatement(*this, stmt); 1929 genIoConditionBranches(getEval(), stmt.v, iostat); 1930 } 1931 1932 void genFIR(const Fortran::parser::InquireStmt &stmt) { 1933 mlir::Value iostat = genInquireStatement(*this, stmt); 1934 if (const auto *specs = 1935 std::get_if<std::list<Fortran::parser::InquireSpec>>(&stmt.u)) 1936 genIoConditionBranches(getEval(), *specs, iostat); 1937 } 1938 1939 void genFIR(const Fortran::parser::OpenStmt &stmt) { 1940 mlir::Value iostat = genOpenStatement(*this, stmt); 1941 genIoConditionBranches(getEval(), stmt.v, iostat); 1942 } 1943 1944 void genFIR(const Fortran::parser::PrintStmt &stmt) { 1945 genPrintStatement(*this, stmt); 1946 } 1947 1948 void genFIR(const Fortran::parser::ReadStmt &stmt) { 1949 mlir::Value iostat = genReadStatement(*this, stmt); 1950 genIoConditionBranches(getEval(), stmt.controls, iostat); 1951 } 1952 1953 void genFIR(const Fortran::parser::RewindStmt &stmt) { 1954 mlir::Value iostat = genRewindStatement(*this, stmt); 1955 genIoConditionBranches(getEval(), stmt.v, iostat); 1956 } 1957 1958 void genFIR(const Fortran::parser::WaitStmt &stmt) { 1959 mlir::Value iostat = genWaitStatement(*this, stmt); 1960 genIoConditionBranches(getEval(), stmt.v, iostat); 1961 } 1962 1963 void genFIR(const Fortran::parser::WriteStmt &stmt) { 1964 mlir::Value iostat = genWriteStatement(*this, stmt); 1965 genIoConditionBranches(getEval(), stmt.controls, iostat); 1966 } 1967 1968 template <typename A> 1969 void genIoConditionBranches(Fortran::lower::pft::Evaluation &eval, 1970 const A &specList, mlir::Value iostat) { 1971 if (!iostat) 1972 return; 1973 1974 mlir::Block *endBlock = nullptr; 1975 mlir::Block *eorBlock = nullptr; 1976 mlir::Block *errBlock = nullptr; 1977 for (const auto &spec : specList) { 1978 std::visit(Fortran::common::visitors{ 1979 [&](const Fortran::parser::EndLabel &label) { 1980 endBlock = blockOfLabel(eval, label.v); 1981 }, 1982 [&](const Fortran::parser::EorLabel &label) { 1983 eorBlock = blockOfLabel(eval, label.v); 1984 }, 1985 [&](const Fortran::parser::ErrLabel &label) { 1986 errBlock = blockOfLabel(eval, label.v); 1987 }, 1988 [](const auto &) {}}, 1989 spec.u); 1990 } 1991 if (!endBlock && !eorBlock && !errBlock) 1992 return; 1993 1994 mlir::Location loc = toLocation(); 1995 mlir::Type indexType = builder->getIndexType(); 1996 mlir::Value selector = builder->createConvert(loc, indexType, iostat); 1997 llvm::SmallVector<int64_t> indexList; 1998 llvm::SmallVector<mlir::Block *> blockList; 1999 if (eorBlock) { 2000 indexList.push_back(Fortran::runtime::io::IostatEor); 2001 blockList.push_back(eorBlock); 2002 } 2003 if (endBlock) { 2004 indexList.push_back(Fortran::runtime::io::IostatEnd); 2005 blockList.push_back(endBlock); 2006 } 2007 if (errBlock) { 2008 indexList.push_back(0); 2009 blockList.push_back(eval.nonNopSuccessor().block); 2010 // ERR label statement is the default successor. 2011 blockList.push_back(errBlock); 2012 } else { 2013 // Fallthrough successor statement is the default successor. 2014 blockList.push_back(eval.nonNopSuccessor().block); 2015 } 2016 builder->create<fir::SelectOp>(loc, selector, indexList, blockList); 2017 } 2018 2019 //===--------------------------------------------------------------------===// 2020 // Memory allocation and deallocation 2021 //===--------------------------------------------------------------------===// 2022 2023 void genFIR(const Fortran::parser::AllocateStmt &stmt) { 2024 Fortran::lower::genAllocateStmt(*this, stmt, toLocation()); 2025 } 2026 2027 void genFIR(const Fortran::parser::DeallocateStmt &stmt) { 2028 Fortran::lower::genDeallocateStmt(*this, stmt, toLocation()); 2029 } 2030 2031 /// Nullify pointer object list 2032 /// 2033 /// For each pointer object, reset the pointer to a disassociated status. 2034 /// We do this by setting each pointer to null. 2035 void genFIR(const Fortran::parser::NullifyStmt &stmt) { 2036 mlir::Location loc = toLocation(); 2037 for (auto &pointerObject : stmt.v) { 2038 const Fortran::lower::SomeExpr *expr = 2039 Fortran::semantics::GetExpr(pointerObject); 2040 assert(expr); 2041 fir::MutableBoxValue box = genExprMutableBox(loc, *expr); 2042 fir::factory::disassociateMutableBox(*builder, loc, box); 2043 } 2044 } 2045 2046 //===--------------------------------------------------------------------===// 2047 2048 void genFIR(const Fortran::parser::EventPostStmt &stmt) { 2049 TODO(toLocation(), "EventPostStmt lowering"); 2050 } 2051 2052 void genFIR(const Fortran::parser::EventWaitStmt &stmt) { 2053 TODO(toLocation(), "EventWaitStmt lowering"); 2054 } 2055 2056 void genFIR(const Fortran::parser::FormTeamStmt &stmt) { 2057 TODO(toLocation(), "FormTeamStmt lowering"); 2058 } 2059 2060 void genFIR(const Fortran::parser::LockStmt &stmt) { 2061 TODO(toLocation(), "LockStmt lowering"); 2062 } 2063 2064 /// Return true if the current context is a conditionalized and implied 2065 /// iteration space. 2066 bool implicitIterationSpace() { return !implicitIterSpace.empty(); } 2067 2068 /// Return true if context is currently an explicit iteration space. A scalar 2069 /// assignment expression may be contextually within a user-defined iteration 2070 /// space, transforming it into an array expression. 2071 bool explicitIterationSpace() { return explicitIterSpace.isActive(); } 2072 2073 /// Generate an array assignment. 2074 /// This is an assignment expression with rank > 0. The assignment may or may 2075 /// not be in a WHERE and/or FORALL context. 2076 void genArrayAssignment(const Fortran::evaluate::Assignment &assign, 2077 Fortran::lower::StatementContext &stmtCtx) { 2078 if (isWholeAllocatable(assign.lhs)) { 2079 // Assignment to allocatables may require the lhs to be 2080 // deallocated/reallocated. See Fortran 2018 10.2.1.3 p3 2081 Fortran::lower::createAllocatableArrayAssignment( 2082 *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace, 2083 localSymbols, stmtCtx); 2084 return; 2085 } 2086 2087 if (!implicitIterationSpace() && !explicitIterationSpace()) { 2088 // No masks and the iteration space is implied by the array, so create a 2089 // simple array assignment. 2090 Fortran::lower::createSomeArrayAssignment(*this, assign.lhs, assign.rhs, 2091 localSymbols, stmtCtx); 2092 return; 2093 } 2094 2095 // If there is an explicit iteration space, generate an array assignment 2096 // with a user-specified iteration space and possibly with masks. These 2097 // assignments may *appear* to be scalar expressions, but the scalar 2098 // expression is evaluated at all points in the user-defined space much like 2099 // an ordinary array assignment. More specifically, the semantics inside the 2100 // FORALL much more closely resembles that of WHERE than a scalar 2101 // assignment. 2102 // Otherwise, generate a masked array assignment. The iteration space is 2103 // implied by the lhs array expression. 2104 Fortran::lower::createAnyMaskedArrayAssignment( 2105 *this, assign.lhs, assign.rhs, explicitIterSpace, implicitIterSpace, 2106 localSymbols, 2107 explicitIterationSpace() ? explicitIterSpace.stmtContext() 2108 : implicitIterSpace.stmtContext()); 2109 } 2110 2111 void genFIR(const Fortran::parser::WhereConstruct &c) { 2112 implicitIterSpace.growStack(); 2113 genNestedStatement( 2114 std::get< 2115 Fortran::parser::Statement<Fortran::parser::WhereConstructStmt>>( 2116 c.t)); 2117 for (const auto &body : 2118 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(c.t)) 2119 genFIR(body); 2120 for (const auto &e : 2121 std::get<std::list<Fortran::parser::WhereConstruct::MaskedElsewhere>>( 2122 c.t)) 2123 genFIR(e); 2124 if (const auto &e = 2125 std::get<std::optional<Fortran::parser::WhereConstruct::Elsewhere>>( 2126 c.t); 2127 e.has_value()) 2128 genFIR(*e); 2129 genNestedStatement( 2130 std::get<Fortran::parser::Statement<Fortran::parser::EndWhereStmt>>( 2131 c.t)); 2132 } 2133 void genFIR(const Fortran::parser::WhereBodyConstruct &body) { 2134 std::visit( 2135 Fortran::common::visitors{ 2136 [&](const Fortran::parser::Statement< 2137 Fortran::parser::AssignmentStmt> &stmt) { 2138 genNestedStatement(stmt); 2139 }, 2140 [&](const Fortran::parser::Statement<Fortran::parser::WhereStmt> 2141 &stmt) { genNestedStatement(stmt); }, 2142 [&](const Fortran::common::Indirection< 2143 Fortran::parser::WhereConstruct> &c) { genFIR(c.value()); }, 2144 }, 2145 body.u); 2146 } 2147 void genFIR(const Fortran::parser::WhereConstructStmt &stmt) { 2148 implicitIterSpace.append(Fortran::semantics::GetExpr( 2149 std::get<Fortran::parser::LogicalExpr>(stmt.t))); 2150 } 2151 void genFIR(const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) { 2152 genNestedStatement( 2153 std::get< 2154 Fortran::parser::Statement<Fortran::parser::MaskedElsewhereStmt>>( 2155 ew.t)); 2156 for (const auto &body : 2157 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t)) 2158 genFIR(body); 2159 } 2160 void genFIR(const Fortran::parser::MaskedElsewhereStmt &stmt) { 2161 implicitIterSpace.append(Fortran::semantics::GetExpr( 2162 std::get<Fortran::parser::LogicalExpr>(stmt.t))); 2163 } 2164 void genFIR(const Fortran::parser::WhereConstruct::Elsewhere &ew) { 2165 genNestedStatement( 2166 std::get<Fortran::parser::Statement<Fortran::parser::ElsewhereStmt>>( 2167 ew.t)); 2168 for (const auto &body : 2169 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t)) 2170 genFIR(body); 2171 } 2172 void genFIR(const Fortran::parser::ElsewhereStmt &stmt) { 2173 implicitIterSpace.append(nullptr); 2174 } 2175 void genFIR(const Fortran::parser::EndWhereStmt &) { 2176 implicitIterSpace.shrinkStack(); 2177 } 2178 2179 void genFIR(const Fortran::parser::WhereStmt &stmt) { 2180 Fortran::lower::StatementContext stmtCtx; 2181 const auto &assign = std::get<Fortran::parser::AssignmentStmt>(stmt.t); 2182 implicitIterSpace.growStack(); 2183 implicitIterSpace.append(Fortran::semantics::GetExpr( 2184 std::get<Fortran::parser::LogicalExpr>(stmt.t))); 2185 genAssignment(*assign.typedAssignment->v); 2186 implicitIterSpace.shrinkStack(); 2187 } 2188 2189 void genFIR(const Fortran::parser::PointerAssignmentStmt &stmt) { 2190 genAssignment(*stmt.typedAssignment->v); 2191 } 2192 2193 void genFIR(const Fortran::parser::AssignmentStmt &stmt) { 2194 genAssignment(*stmt.typedAssignment->v); 2195 } 2196 2197 void genFIR(const Fortran::parser::SyncAllStmt &stmt) { 2198 TODO(toLocation(), "SyncAllStmt lowering"); 2199 } 2200 2201 void genFIR(const Fortran::parser::SyncImagesStmt &stmt) { 2202 TODO(toLocation(), "SyncImagesStmt lowering"); 2203 } 2204 2205 void genFIR(const Fortran::parser::SyncMemoryStmt &stmt) { 2206 TODO(toLocation(), "SyncMemoryStmt lowering"); 2207 } 2208 2209 void genFIR(const Fortran::parser::SyncTeamStmt &stmt) { 2210 TODO(toLocation(), "SyncTeamStmt lowering"); 2211 } 2212 2213 void genFIR(const Fortran::parser::UnlockStmt &stmt) { 2214 TODO(toLocation(), "UnlockStmt lowering"); 2215 } 2216 2217 void genFIR(const Fortran::parser::AssignStmt &stmt) { 2218 const Fortran::semantics::Symbol &symbol = 2219 *std::get<Fortran::parser::Name>(stmt.t).symbol; 2220 mlir::Location loc = toLocation(); 2221 mlir::Value labelValue = builder->createIntegerConstant( 2222 loc, genType(symbol), std::get<Fortran::parser::Label>(stmt.t)); 2223 builder->create<fir::StoreOp>(loc, labelValue, getSymbolAddress(symbol)); 2224 } 2225 2226 void genFIR(const Fortran::parser::FormatStmt &) { 2227 // do nothing. 2228 2229 // FORMAT statements have no semantics. They may be lowered if used by a 2230 // data transfer statement. 2231 } 2232 2233 void genFIR(const Fortran::parser::PauseStmt &stmt) { 2234 genPauseStatement(*this, stmt); 2235 } 2236 2237 void genFIR(const Fortran::parser::FailImageStmt &stmt) { 2238 TODO(toLocation(), "FailImageStmt lowering"); 2239 } 2240 2241 // call STOP, ERROR STOP in runtime 2242 void genFIR(const Fortran::parser::StopStmt &stmt) { 2243 genStopStatement(*this, stmt); 2244 } 2245 2246 void genFIR(const Fortran::parser::ReturnStmt &stmt) { 2247 Fortran::lower::pft::FunctionLikeUnit *funit = 2248 getEval().getOwningProcedure(); 2249 assert(funit && "not inside main program, function or subroutine"); 2250 if (funit->isMainProgram()) { 2251 genExitRoutine(); 2252 return; 2253 } 2254 mlir::Location loc = toLocation(); 2255 if (stmt.v) { 2256 // Alternate return statement - If this is a subroutine where some 2257 // alternate entries have alternate returns, but the active entry point 2258 // does not, ignore the alternate return value. Otherwise, assign it 2259 // to the compiler-generated result variable. 2260 const Fortran::semantics::Symbol &symbol = funit->getSubprogramSymbol(); 2261 if (Fortran::semantics::HasAlternateReturns(symbol)) { 2262 Fortran::lower::StatementContext stmtCtx; 2263 const Fortran::lower::SomeExpr *expr = 2264 Fortran::semantics::GetExpr(*stmt.v); 2265 assert(expr && "missing alternate return expression"); 2266 mlir::Value altReturnIndex = builder->createConvert( 2267 loc, builder->getIndexType(), createFIRExpr(loc, expr, stmtCtx)); 2268 builder->create<fir::StoreOp>(loc, altReturnIndex, 2269 getAltReturnResult(symbol)); 2270 } 2271 } 2272 // Branch to the last block of the SUBROUTINE, which has the actual return. 2273 if (!funit->finalBlock) { 2274 mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint(); 2275 funit->finalBlock = builder->createBlock(&builder->getRegion()); 2276 builder->restoreInsertionPoint(insPt); 2277 } 2278 builder->create<mlir::cf::BranchOp>(loc, funit->finalBlock); 2279 } 2280 2281 void genFIR(const Fortran::parser::CycleStmt &) { 2282 TODO(toLocation(), "CycleStmt lowering"); 2283 } 2284 2285 void genFIR(const Fortran::parser::ExitStmt &) { 2286 TODO(toLocation(), "ExitStmt lowering"); 2287 } 2288 2289 void genFIR(const Fortran::parser::GotoStmt &) { 2290 genFIRBranch(getEval().controlSuccessor->block); 2291 } 2292 2293 void genFIR(const Fortran::parser::ElseIfStmt &) { 2294 TODO(toLocation(), "ElseIfStmt lowering"); 2295 } 2296 2297 void genFIR(const Fortran::parser::ElseStmt &) { 2298 TODO(toLocation(), "ElseStmt lowering"); 2299 } 2300 2301 void genFIR(const Fortran::parser::EndDoStmt &) { 2302 TODO(toLocation(), "EndDoStmt lowering"); 2303 } 2304 2305 void genFIR(const Fortran::parser::EndMpSubprogramStmt &) { 2306 TODO(toLocation(), "EndMpSubprogramStmt lowering"); 2307 } 2308 2309 // Nop statements - No code, or code is generated at the construct level. 2310 void genFIR(const Fortran::parser::AssociateStmt &) {} // nop 2311 void genFIR(const Fortran::parser::CaseStmt &) {} // nop 2312 void genFIR(const Fortran::parser::ContinueStmt &) {} // nop 2313 void genFIR(const Fortran::parser::EndAssociateStmt &) {} // nop 2314 void genFIR(const Fortran::parser::EndFunctionStmt &) {} // nop 2315 void genFIR(const Fortran::parser::EndIfStmt &) {} // nop 2316 void genFIR(const Fortran::parser::EndSelectStmt &) {} // nop 2317 void genFIR(const Fortran::parser::EndSubroutineStmt &) {} // nop 2318 void genFIR(const Fortran::parser::EntryStmt &) {} // nop 2319 2320 void genFIR(const Fortran::parser::IfStmt &) { 2321 TODO(toLocation(), "IfStmt lowering"); 2322 } 2323 2324 void genFIR(const Fortran::parser::IfThenStmt &) { 2325 TODO(toLocation(), "IfThenStmt lowering"); 2326 } 2327 2328 void genFIR(const Fortran::parser::NonLabelDoStmt &) { 2329 TODO(toLocation(), "NonLabelDoStmt lowering"); 2330 } 2331 2332 void genFIR(const Fortran::parser::OmpEndLoopDirective &) { 2333 TODO(toLocation(), "OmpEndLoopDirective lowering"); 2334 } 2335 2336 void genFIR(const Fortran::parser::NamelistStmt &) { 2337 TODO(toLocation(), "NamelistStmt lowering"); 2338 } 2339 2340 /// Generate FIR for the Evaluation `eval`. 2341 void genFIR(Fortran::lower::pft::Evaluation &eval, 2342 bool unstructuredContext = true) { 2343 if (unstructuredContext) { 2344 // When transitioning from unstructured to structured code, 2345 // the structured code could be a target that starts a new block. 2346 maybeStartBlock(eval.isConstruct() && eval.lowerAsStructured() 2347 ? eval.getFirstNestedEvaluation().block 2348 : eval.block); 2349 } 2350 2351 setCurrentEval(eval); 2352 setCurrentPosition(eval.position); 2353 eval.visit([&](const auto &stmt) { genFIR(stmt); }); 2354 2355 if (unstructuredContext && blockIsUnterminated()) { 2356 // Exit from an unstructured IF or SELECT construct block. 2357 Fortran::lower::pft::Evaluation *successor{}; 2358 if (eval.isActionStmt()) 2359 successor = eval.controlSuccessor; 2360 else if (eval.isConstruct() && 2361 eval.getLastNestedEvaluation() 2362 .lexicalSuccessor->isIntermediateConstructStmt()) 2363 successor = eval.constructExit; 2364 if (successor && successor->block) 2365 genFIRBranch(successor->block); 2366 } 2367 } 2368 2369 //===--------------------------------------------------------------------===// 2370 // Analysis on a nested explicit iteration space. 2371 //===--------------------------------------------------------------------===// 2372 2373 void analyzeExplicitSpace(const Fortran::parser::ConcurrentHeader &header) { 2374 explicitIterSpace.pushLevel(); 2375 for (const Fortran::parser::ConcurrentControl &ctrl : 2376 std::get<std::list<Fortran::parser::ConcurrentControl>>(header.t)) { 2377 const Fortran::semantics::Symbol *ctrlVar = 2378 std::get<Fortran::parser::Name>(ctrl.t).symbol; 2379 explicitIterSpace.addSymbol(ctrlVar); 2380 } 2381 if (const auto &mask = 2382 std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>( 2383 header.t); 2384 mask.has_value()) 2385 analyzeExplicitSpace(*Fortran::semantics::GetExpr(*mask)); 2386 } 2387 template <bool LHS = false, typename A> 2388 void analyzeExplicitSpace(const Fortran::evaluate::Expr<A> &e) { 2389 explicitIterSpace.exprBase(&e, LHS); 2390 } 2391 void analyzeExplicitSpace(const Fortran::evaluate::Assignment *assign) { 2392 auto analyzeAssign = [&](const Fortran::lower::SomeExpr &lhs, 2393 const Fortran::lower::SomeExpr &rhs) { 2394 analyzeExplicitSpace</*LHS=*/true>(lhs); 2395 analyzeExplicitSpace(rhs); 2396 }; 2397 std::visit( 2398 Fortran::common::visitors{ 2399 [&](const Fortran::evaluate::ProcedureRef &procRef) { 2400 // Ensure the procRef expressions are the one being visited. 2401 assert(procRef.arguments().size() == 2); 2402 const Fortran::lower::SomeExpr *lhs = 2403 procRef.arguments()[0].value().UnwrapExpr(); 2404 const Fortran::lower::SomeExpr *rhs = 2405 procRef.arguments()[1].value().UnwrapExpr(); 2406 assert(lhs && rhs && 2407 "user defined assignment arguments must be expressions"); 2408 analyzeAssign(*lhs, *rhs); 2409 }, 2410 [&](const auto &) { analyzeAssign(assign->lhs, assign->rhs); }}, 2411 assign->u); 2412 explicitIterSpace.endAssign(); 2413 } 2414 void analyzeExplicitSpace(const Fortran::parser::ForallAssignmentStmt &stmt) { 2415 std::visit([&](const auto &s) { analyzeExplicitSpace(s); }, stmt.u); 2416 } 2417 void analyzeExplicitSpace(const Fortran::parser::AssignmentStmt &s) { 2418 analyzeExplicitSpace(s.typedAssignment->v.operator->()); 2419 } 2420 void analyzeExplicitSpace(const Fortran::parser::PointerAssignmentStmt &s) { 2421 analyzeExplicitSpace(s.typedAssignment->v.operator->()); 2422 } 2423 void analyzeExplicitSpace(const Fortran::parser::WhereConstruct &c) { 2424 analyzeExplicitSpace( 2425 std::get< 2426 Fortran::parser::Statement<Fortran::parser::WhereConstructStmt>>( 2427 c.t) 2428 .statement); 2429 for (const Fortran::parser::WhereBodyConstruct &body : 2430 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(c.t)) 2431 analyzeExplicitSpace(body); 2432 for (const Fortran::parser::WhereConstruct::MaskedElsewhere &e : 2433 std::get<std::list<Fortran::parser::WhereConstruct::MaskedElsewhere>>( 2434 c.t)) 2435 analyzeExplicitSpace(e); 2436 if (const auto &e = 2437 std::get<std::optional<Fortran::parser::WhereConstruct::Elsewhere>>( 2438 c.t); 2439 e.has_value()) 2440 analyzeExplicitSpace(e.operator->()); 2441 } 2442 void analyzeExplicitSpace(const Fortran::parser::WhereConstructStmt &ws) { 2443 const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr( 2444 std::get<Fortran::parser::LogicalExpr>(ws.t)); 2445 addMaskVariable(exp); 2446 analyzeExplicitSpace(*exp); 2447 } 2448 void analyzeExplicitSpace( 2449 const Fortran::parser::WhereConstruct::MaskedElsewhere &ew) { 2450 analyzeExplicitSpace( 2451 std::get< 2452 Fortran::parser::Statement<Fortran::parser::MaskedElsewhereStmt>>( 2453 ew.t) 2454 .statement); 2455 for (const Fortran::parser::WhereBodyConstruct &e : 2456 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew.t)) 2457 analyzeExplicitSpace(e); 2458 } 2459 void analyzeExplicitSpace(const Fortran::parser::WhereBodyConstruct &body) { 2460 std::visit(Fortran::common::visitors{ 2461 [&](const Fortran::common::Indirection< 2462 Fortran::parser::WhereConstruct> &wc) { 2463 analyzeExplicitSpace(wc.value()); 2464 }, 2465 [&](const auto &s) { analyzeExplicitSpace(s.statement); }}, 2466 body.u); 2467 } 2468 void analyzeExplicitSpace(const Fortran::parser::MaskedElsewhereStmt &stmt) { 2469 const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr( 2470 std::get<Fortran::parser::LogicalExpr>(stmt.t)); 2471 addMaskVariable(exp); 2472 analyzeExplicitSpace(*exp); 2473 } 2474 void 2475 analyzeExplicitSpace(const Fortran::parser::WhereConstruct::Elsewhere *ew) { 2476 for (const Fortran::parser::WhereBodyConstruct &e : 2477 std::get<std::list<Fortran::parser::WhereBodyConstruct>>(ew->t)) 2478 analyzeExplicitSpace(e); 2479 } 2480 void analyzeExplicitSpace(const Fortran::parser::WhereStmt &stmt) { 2481 const Fortran::lower::SomeExpr *exp = Fortran::semantics::GetExpr( 2482 std::get<Fortran::parser::LogicalExpr>(stmt.t)); 2483 addMaskVariable(exp); 2484 analyzeExplicitSpace(*exp); 2485 const std::optional<Fortran::evaluate::Assignment> &assign = 2486 std::get<Fortran::parser::AssignmentStmt>(stmt.t).typedAssignment->v; 2487 assert(assign.has_value() && "WHERE has no statement"); 2488 analyzeExplicitSpace(assign.operator->()); 2489 } 2490 void analyzeExplicitSpace(const Fortran::parser::ForallStmt &forall) { 2491 analyzeExplicitSpace( 2492 std::get< 2493 Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>( 2494 forall.t) 2495 .value()); 2496 analyzeExplicitSpace(std::get<Fortran::parser::UnlabeledStatement< 2497 Fortran::parser::ForallAssignmentStmt>>(forall.t) 2498 .statement); 2499 analyzeExplicitSpacePop(); 2500 } 2501 void 2502 analyzeExplicitSpace(const Fortran::parser::ForallConstructStmt &forall) { 2503 analyzeExplicitSpace( 2504 std::get< 2505 Fortran::common::Indirection<Fortran::parser::ConcurrentHeader>>( 2506 forall.t) 2507 .value()); 2508 } 2509 void analyzeExplicitSpace(const Fortran::parser::ForallConstruct &forall) { 2510 analyzeExplicitSpace( 2511 std::get< 2512 Fortran::parser::Statement<Fortran::parser::ForallConstructStmt>>( 2513 forall.t) 2514 .statement); 2515 for (const Fortran::parser::ForallBodyConstruct &s : 2516 std::get<std::list<Fortran::parser::ForallBodyConstruct>>(forall.t)) { 2517 std::visit(Fortran::common::visitors{ 2518 [&](const Fortran::common::Indirection< 2519 Fortran::parser::ForallConstruct> &b) { 2520 analyzeExplicitSpace(b.value()); 2521 }, 2522 [&](const Fortran::parser::WhereConstruct &w) { 2523 analyzeExplicitSpace(w); 2524 }, 2525 [&](const auto &b) { analyzeExplicitSpace(b.statement); }}, 2526 s.u); 2527 } 2528 analyzeExplicitSpacePop(); 2529 } 2530 2531 void analyzeExplicitSpacePop() { explicitIterSpace.popLevel(); } 2532 2533 void addMaskVariable(Fortran::lower::FrontEndExpr exp) { 2534 // Note: use i8 to store bool values. This avoids round-down behavior found 2535 // with sequences of i1. That is, an array of i1 will be truncated in size 2536 // and be too small. For example, a buffer of type fir.array<7xi1> will have 2537 // 0 size. 2538 mlir::Type i64Ty = builder->getIntegerType(64); 2539 mlir::TupleType ty = fir::factory::getRaggedArrayHeaderType(*builder); 2540 mlir::Type buffTy = ty.getType(1); 2541 mlir::Type shTy = ty.getType(2); 2542 mlir::Location loc = toLocation(); 2543 mlir::Value hdr = builder->createTemporary(loc, ty); 2544 // FIXME: Is there a way to create a `zeroinitializer` in LLVM-IR dialect? 2545 // For now, explicitly set lazy ragged header to all zeros. 2546 // auto nilTup = builder->createNullConstant(loc, ty); 2547 // builder->create<fir::StoreOp>(loc, nilTup, hdr); 2548 mlir::Type i32Ty = builder->getIntegerType(32); 2549 mlir::Value zero = builder->createIntegerConstant(loc, i32Ty, 0); 2550 mlir::Value zero64 = builder->createIntegerConstant(loc, i64Ty, 0); 2551 mlir::Value flags = builder->create<fir::CoordinateOp>( 2552 loc, builder->getRefType(i64Ty), hdr, zero); 2553 builder->create<fir::StoreOp>(loc, zero64, flags); 2554 mlir::Value one = builder->createIntegerConstant(loc, i32Ty, 1); 2555 mlir::Value nullPtr1 = builder->createNullConstant(loc, buffTy); 2556 mlir::Value var = builder->create<fir::CoordinateOp>( 2557 loc, builder->getRefType(buffTy), hdr, one); 2558 builder->create<fir::StoreOp>(loc, nullPtr1, var); 2559 mlir::Value two = builder->createIntegerConstant(loc, i32Ty, 2); 2560 mlir::Value nullPtr2 = builder->createNullConstant(loc, shTy); 2561 mlir::Value shape = builder->create<fir::CoordinateOp>( 2562 loc, builder->getRefType(shTy), hdr, two); 2563 builder->create<fir::StoreOp>(loc, nullPtr2, shape); 2564 implicitIterSpace.addMaskVariable(exp, var, shape, hdr); 2565 explicitIterSpace.outermostContext().attachCleanup( 2566 [builder = this->builder, hdr, loc]() { 2567 fir::runtime::genRaggedArrayDeallocate(loc, *builder, hdr); 2568 }); 2569 } 2570 2571 //===--------------------------------------------------------------------===// 2572 2573 Fortran::lower::LoweringBridge &bridge; 2574 Fortran::evaluate::FoldingContext foldingContext; 2575 fir::FirOpBuilder *builder = nullptr; 2576 Fortran::lower::pft::Evaluation *evalPtr = nullptr; 2577 Fortran::lower::SymMap localSymbols; 2578 Fortran::parser::CharBlock currentPosition; 2579 RuntimeTypeInfoConverter runtimeTypeInfoConverter; 2580 2581 /// Tuple of host assoicated variables. 2582 mlir::Value hostAssocTuple; 2583 Fortran::lower::ImplicitIterSpace implicitIterSpace; 2584 Fortran::lower::ExplicitIterSpace explicitIterSpace; 2585 }; 2586 2587 } // namespace 2588 2589 Fortran::evaluate::FoldingContext 2590 Fortran::lower::LoweringBridge::createFoldingContext() const { 2591 return {getDefaultKinds(), getIntrinsicTable()}; 2592 } 2593 2594 void Fortran::lower::LoweringBridge::lower( 2595 const Fortran::parser::Program &prg, 2596 const Fortran::semantics::SemanticsContext &semanticsContext) { 2597 std::unique_ptr<Fortran::lower::pft::Program> pft = 2598 Fortran::lower::createPFT(prg, semanticsContext); 2599 if (dumpBeforeFir) 2600 Fortran::lower::dumpPFT(llvm::errs(), *pft); 2601 FirConverter converter{*this}; 2602 converter.run(*pft); 2603 } 2604 2605 Fortran::lower::LoweringBridge::LoweringBridge( 2606 mlir::MLIRContext &context, 2607 const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds, 2608 const Fortran::evaluate::IntrinsicProcTable &intrinsics, 2609 const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple, 2610 fir::KindMapping &kindMap) 2611 : defaultKinds{defaultKinds}, intrinsics{intrinsics}, cooked{&cooked}, 2612 context{context}, kindMap{kindMap} { 2613 // Register the diagnostic handler. 2614 context.getDiagEngine().registerHandler([](mlir::Diagnostic &diag) { 2615 llvm::raw_ostream &os = llvm::errs(); 2616 switch (diag.getSeverity()) { 2617 case mlir::DiagnosticSeverity::Error: 2618 os << "error: "; 2619 break; 2620 case mlir::DiagnosticSeverity::Remark: 2621 os << "info: "; 2622 break; 2623 case mlir::DiagnosticSeverity::Warning: 2624 os << "warning: "; 2625 break; 2626 default: 2627 break; 2628 } 2629 if (!diag.getLocation().isa<UnknownLoc>()) 2630 os << diag.getLocation() << ": "; 2631 os << diag << '\n'; 2632 os.flush(); 2633 return mlir::success(); 2634 }); 2635 2636 // Create the module and attach the attributes. 2637 module = std::make_unique<mlir::ModuleOp>( 2638 mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))); 2639 assert(module.get() && "module was not created"); 2640 fir::setTargetTriple(getModule(), triple); 2641 fir::setKindMapping(getModule(), kindMap); 2642 } 2643