1 //===-- PFTBuilder.cpp ----------------------------------------------------===// 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 #include "flang/Lower/PFTBuilder.h" 10 #include "flang/Lower/IntervalSet.h" 11 #include "flang/Lower/Support/Utils.h" 12 #include "flang/Parser/dump-parse-tree.h" 13 #include "flang/Parser/parse-tree-visitor.h" 14 #include "flang/Semantics/semantics.h" 15 #include "flang/Semantics/tools.h" 16 #include "llvm/ADT/DenseSet.h" 17 #include "llvm/ADT/IntervalMap.h" 18 #include "llvm/Support/CommandLine.h" 19 #include "llvm/Support/Debug.h" 20 21 #define DEBUG_TYPE "flang-pft" 22 23 static llvm::cl::opt<bool> clDisableStructuredFir( 24 "no-structured-fir", llvm::cl::desc("disable generation of structured FIR"), 25 llvm::cl::init(false), llvm::cl::Hidden); 26 27 using namespace Fortran; 28 29 namespace { 30 /// Helpers to unveil parser node inside Fortran::parser::Statement<>, 31 /// Fortran::parser::UnlabeledStatement, and Fortran::common::Indirection<> 32 template <typename A> 33 struct RemoveIndirectionHelper { 34 using Type = A; 35 }; 36 template <typename A> 37 struct RemoveIndirectionHelper<common::Indirection<A>> { 38 using Type = A; 39 }; 40 41 template <typename A> 42 struct UnwrapStmt { 43 static constexpr bool isStmt{false}; 44 }; 45 template <typename A> 46 struct UnwrapStmt<parser::Statement<A>> { 47 static constexpr bool isStmt{true}; 48 using Type = typename RemoveIndirectionHelper<A>::Type; 49 constexpr UnwrapStmt(const parser::Statement<A> &a) 50 : unwrapped{removeIndirection(a.statement)}, position{a.source}, 51 label{a.label} {} 52 const Type &unwrapped; 53 parser::CharBlock position; 54 std::optional<parser::Label> label; 55 }; 56 template <typename A> 57 struct UnwrapStmt<parser::UnlabeledStatement<A>> { 58 static constexpr bool isStmt{true}; 59 using Type = typename RemoveIndirectionHelper<A>::Type; 60 constexpr UnwrapStmt(const parser::UnlabeledStatement<A> &a) 61 : unwrapped{removeIndirection(a.statement)}, position{a.source} {} 62 const Type &unwrapped; 63 parser::CharBlock position; 64 std::optional<parser::Label> label; 65 }; 66 67 #ifndef NDEBUG 68 void dumpScope(const semantics::Scope *scope, int depth = -1); 69 #endif 70 71 /// The instantiation of a parse tree visitor (Pre and Post) is extremely 72 /// expensive in terms of compile and link time. So one goal here is to 73 /// limit the bridge to one such instantiation. 74 class PFTBuilder { 75 public: 76 PFTBuilder(const semantics::SemanticsContext &semanticsContext) 77 : pgm{std::make_unique<lower::pft::Program>( 78 semanticsContext.GetCommonBlocks())}, 79 semanticsContext{semanticsContext} { 80 lower::pft::PftNode pftRoot{*pgm.get()}; 81 pftParentStack.push_back(pftRoot); 82 } 83 84 /// Get the result 85 std::unique_ptr<lower::pft::Program> result() { return std::move(pgm); } 86 87 template <typename A> 88 constexpr bool Pre(const A &a) { 89 if constexpr (lower::pft::isFunctionLike<A>) { 90 return enterFunction(a, semanticsContext); 91 } else if constexpr (lower::pft::isConstruct<A> || 92 lower::pft::isDirective<A>) { 93 return enterConstructOrDirective(a); 94 } else if constexpr (UnwrapStmt<A>::isStmt) { 95 using T = typename UnwrapStmt<A>::Type; 96 // Node "a" being visited has one of the following types: 97 // Statement<T>, Statement<Indirection<T>>, UnlabeledStatement<T>, 98 // or UnlabeledStatement<Indirection<T>> 99 auto stmt{UnwrapStmt<A>(a)}; 100 if constexpr (lower::pft::isConstructStmt<T> || 101 lower::pft::isOtherStmt<T>) { 102 addEvaluation(lower::pft::Evaluation{ 103 stmt.unwrapped, pftParentStack.back(), stmt.position, stmt.label}); 104 return false; 105 } else if constexpr (std::is_same_v<T, parser::ActionStmt>) { 106 return std::visit( 107 common::visitors{ 108 [&](const common::Indirection<parser::CallStmt> &x) { 109 addEvaluation(lower::pft::Evaluation{ 110 removeIndirection(x), pftParentStack.back(), 111 stmt.position, stmt.label}); 112 checkForRoundingModeCall(x.value()); 113 return true; 114 }, 115 [&](const common::Indirection<parser::IfStmt> &x) { 116 convertIfStmt(x.value(), stmt.position, stmt.label); 117 return false; 118 }, 119 [&](const auto &x) { 120 addEvaluation(lower::pft::Evaluation{ 121 removeIndirection(x), pftParentStack.back(), 122 stmt.position, stmt.label}); 123 return true; 124 }, 125 }, 126 stmt.unwrapped.u); 127 } 128 } 129 return true; 130 } 131 132 /// Check for a call statement that could modify the fp rounding mode. 133 void checkForRoundingModeCall(const parser::CallStmt &callStmt) { 134 const auto &pd = std::get<parser::ProcedureDesignator>(callStmt.call.t); 135 const auto *callName = std::get_if<parser::Name>(&pd.u); 136 if (!callName) 137 return; 138 const Fortran::semantics::Symbol &procSym = callName->symbol->GetUltimate(); 139 llvm::StringRef procName = toStringRef(procSym.name()); 140 if (!procName.startswith("ieee_set_")) 141 return; 142 if (procName == "ieee_set_rounding_mode_0" || 143 procName == "ieee_set_modes_0" || procName == "ieee_set_status_0") 144 evaluationListStack.back() 145 ->back() 146 .getOwningProcedure() 147 ->mayModifyRoundingMode = true; 148 } 149 150 /// Convert an IfStmt into an IfConstruct, retaining the IfStmt as the 151 /// first statement of the construct. 152 void convertIfStmt(const parser::IfStmt &ifStmt, parser::CharBlock position, 153 std::optional<parser::Label> label) { 154 // Generate a skeleton IfConstruct parse node. Its components are never 155 // referenced. The actual components are available via the IfConstruct 156 // evaluation's nested evaluationList, with the ifStmt in the position of 157 // the otherwise normal IfThenStmt. Caution: All other PFT nodes reference 158 // front end generated parse nodes; this is an exceptional case. 159 static const auto ifConstruct = parser::IfConstruct{ 160 parser::Statement<parser::IfThenStmt>{ 161 std::nullopt, 162 parser::IfThenStmt{ 163 std::optional<parser::Name>{}, 164 parser::ScalarLogicalExpr{parser::LogicalExpr{parser::Expr{ 165 parser::LiteralConstant{parser::LogicalLiteralConstant{ 166 false, std::optional<parser::KindParam>{}}}}}}}}, 167 parser::Block{}, std::list<parser::IfConstruct::ElseIfBlock>{}, 168 std::optional<parser::IfConstruct::ElseBlock>{}, 169 parser::Statement<parser::EndIfStmt>{std::nullopt, 170 parser::EndIfStmt{std::nullopt}}}; 171 enterConstructOrDirective(ifConstruct); 172 addEvaluation( 173 lower::pft::Evaluation{ifStmt, pftParentStack.back(), position, label}); 174 Pre(std::get<parser::UnlabeledStatement<parser::ActionStmt>>(ifStmt.t)); 175 static const auto endIfStmt = parser::EndIfStmt{std::nullopt}; 176 addEvaluation( 177 lower::pft::Evaluation{endIfStmt, pftParentStack.back(), {}, {}}); 178 exitConstructOrDirective(); 179 } 180 181 template <typename A> 182 constexpr void Post(const A &) { 183 if constexpr (lower::pft::isFunctionLike<A>) { 184 exitFunction(); 185 } else if constexpr (lower::pft::isConstruct<A> || 186 lower::pft::isDirective<A>) { 187 exitConstructOrDirective(); 188 } 189 } 190 191 // Module like 192 bool Pre(const parser::Module &node) { return enterModule(node); } 193 bool Pre(const parser::Submodule &node) { return enterModule(node); } 194 195 void Post(const parser::Module &) { exitModule(); } 196 void Post(const parser::Submodule &) { exitModule(); } 197 198 // Block data 199 bool Pre(const parser::BlockData &node) { 200 addUnit(lower::pft::BlockDataUnit{node, pftParentStack.back(), 201 semanticsContext}); 202 return false; 203 } 204 205 // Get rid of production wrapper 206 bool Pre(const parser::Statement<parser::ForallAssignmentStmt> &statement) { 207 addEvaluation(std::visit( 208 [&](const auto &x) { 209 return lower::pft::Evaluation{x, pftParentStack.back(), 210 statement.source, statement.label}; 211 }, 212 statement.statement.u)); 213 return false; 214 } 215 bool Pre(const parser::WhereBodyConstruct &whereBody) { 216 return std::visit( 217 common::visitors{ 218 [&](const parser::Statement<parser::AssignmentStmt> &stmt) { 219 // Not caught as other AssignmentStmt because it is not 220 // wrapped in a parser::ActionStmt. 221 addEvaluation(lower::pft::Evaluation{stmt.statement, 222 pftParentStack.back(), 223 stmt.source, stmt.label}); 224 return false; 225 }, 226 [&](const auto &) { return true; }, 227 }, 228 whereBody.u); 229 } 230 231 // CompilerDirective have special handling in case they are top level 232 // directives (i.e. they do not belong to a ProgramUnit). 233 bool Pre(const parser::CompilerDirective &directive) { 234 assert(pftParentStack.size() > 0 && 235 "At least the Program must be a parent"); 236 if (pftParentStack.back().isA<lower::pft::Program>()) { 237 addUnit( 238 lower::pft::CompilerDirectiveUnit(directive, pftParentStack.back())); 239 return false; 240 } 241 return enterConstructOrDirective(directive); 242 } 243 244 bool Pre(const parser::OpenACCRoutineConstruct &directive) { 245 assert(pftParentStack.size() > 0 && 246 "At least the Program must be a parent"); 247 if (pftParentStack.back().isA<lower::pft::Program>()) { 248 addUnit( 249 lower::pft::OpenACCDirectiveUnit(directive, pftParentStack.back())); 250 return false; 251 } 252 return enterConstructOrDirective(directive); 253 } 254 255 private: 256 /// Initialize a new module-like unit and make it the builder's focus. 257 template <typename A> 258 bool enterModule(const A &mod) { 259 Fortran::lower::pft::ModuleLikeUnit &unit = 260 addUnit(lower::pft::ModuleLikeUnit{mod, pftParentStack.back()}); 261 functionList = &unit.nestedFunctions; 262 pushEvaluationList(&unit.evaluationList); 263 pftParentStack.emplace_back(unit); 264 LLVM_DEBUG(dumpScope(&unit.getScope())); 265 return true; 266 } 267 268 void exitModule() { 269 if (!evaluationListStack.empty()) 270 popEvaluationList(); 271 pftParentStack.pop_back(); 272 resetFunctionState(); 273 } 274 275 /// Add the end statement Evaluation of a sub/program to the PFT. 276 /// There may be intervening internal subprogram definitions between 277 /// prior statements and this end statement. 278 void endFunctionBody() { 279 if (evaluationListStack.empty()) 280 return; 281 auto evaluationList = evaluationListStack.back(); 282 if (evaluationList->empty() || !evaluationList->back().isEndStmt()) { 283 const auto &endStmt = 284 pftParentStack.back().get<lower::pft::FunctionLikeUnit>().endStmt; 285 endStmt.visit(common::visitors{ 286 [&](const parser::Statement<parser::EndProgramStmt> &s) { 287 addEvaluation(lower::pft::Evaluation{ 288 s.statement, pftParentStack.back(), s.source, s.label}); 289 }, 290 [&](const parser::Statement<parser::EndFunctionStmt> &s) { 291 addEvaluation(lower::pft::Evaluation{ 292 s.statement, pftParentStack.back(), s.source, s.label}); 293 }, 294 [&](const parser::Statement<parser::EndSubroutineStmt> &s) { 295 addEvaluation(lower::pft::Evaluation{ 296 s.statement, pftParentStack.back(), s.source, s.label}); 297 }, 298 [&](const parser::Statement<parser::EndMpSubprogramStmt> &s) { 299 addEvaluation(lower::pft::Evaluation{ 300 s.statement, pftParentStack.back(), s.source, s.label}); 301 }, 302 [&](const auto &s) { 303 llvm::report_fatal_error("missing end statement or unexpected " 304 "begin statement reference"); 305 }, 306 }); 307 } 308 lastLexicalEvaluation = nullptr; 309 } 310 311 /// Pop the ModuleLikeUnit evaluationList when entering the first module 312 /// procedure. 313 void cleanModuleEvaluationList() { 314 if (evaluationListStack.empty()) 315 return; 316 if (pftParentStack.back().isA<lower::pft::ModuleLikeUnit>()) 317 popEvaluationList(); 318 } 319 320 /// Initialize a new function-like unit and make it the builder's focus. 321 template <typename A> 322 bool enterFunction(const A &func, 323 const semantics::SemanticsContext &semanticsContext) { 324 cleanModuleEvaluationList(); 325 endFunctionBody(); // enclosing host subprogram body, if any 326 Fortran::lower::pft::FunctionLikeUnit &unit = 327 addFunction(lower::pft::FunctionLikeUnit{func, pftParentStack.back(), 328 semanticsContext}); 329 labelEvaluationMap = &unit.labelEvaluationMap; 330 assignSymbolLabelMap = &unit.assignSymbolLabelMap; 331 functionList = &unit.nestedFunctions; 332 pushEvaluationList(&unit.evaluationList); 333 pftParentStack.emplace_back(unit); 334 LLVM_DEBUG(dumpScope(&unit.getScope())); 335 return true; 336 } 337 338 void exitFunction() { 339 rewriteIfGotos(); 340 endFunctionBody(); 341 analyzeBranches(nullptr, *evaluationListStack.back()); // add branch links 342 processEntryPoints(); 343 popEvaluationList(); 344 labelEvaluationMap = nullptr; 345 assignSymbolLabelMap = nullptr; 346 pftParentStack.pop_back(); 347 resetFunctionState(); 348 } 349 350 /// Initialize a new construct or directive and make it the builder's focus. 351 template <typename A> 352 bool enterConstructOrDirective(const A &constructOrDirective) { 353 Fortran::lower::pft::Evaluation &eval = addEvaluation( 354 lower::pft::Evaluation{constructOrDirective, pftParentStack.back()}); 355 eval.evaluationList.reset(new lower::pft::EvaluationList); 356 pushEvaluationList(eval.evaluationList.get()); 357 pftParentStack.emplace_back(eval); 358 constructAndDirectiveStack.emplace_back(&eval); 359 return true; 360 } 361 362 void exitConstructOrDirective() { 363 auto isOpenMPLoopConstruct = [](Fortran::lower::pft::Evaluation *eval) { 364 if (const auto *ompConstruct = eval->getIf<parser::OpenMPConstruct>()) 365 if (std::holds_alternative<parser::OpenMPLoopConstruct>( 366 ompConstruct->u)) 367 return true; 368 return false; 369 }; 370 371 rewriteIfGotos(); 372 auto *eval = constructAndDirectiveStack.back(); 373 if (eval->isExecutableDirective() && !isOpenMPLoopConstruct(eval)) { 374 // A construct at the end of an (unstructured) OpenACC or OpenMP 375 // construct region must have an exit target inside the region. 376 // This is not applicable to the OpenMP loop construct since the 377 // end of the loop is an available target inside the region. 378 Fortran::lower::pft::EvaluationList &evaluationList = 379 *eval->evaluationList; 380 if (!evaluationList.empty() && evaluationList.back().isConstruct()) { 381 static const parser::ContinueStmt exitTarget{}; 382 addEvaluation( 383 lower::pft::Evaluation{exitTarget, pftParentStack.back(), {}, {}}); 384 } 385 } 386 popEvaluationList(); 387 pftParentStack.pop_back(); 388 constructAndDirectiveStack.pop_back(); 389 } 390 391 /// Reset function state to that of an enclosing host function. 392 void resetFunctionState() { 393 if (!pftParentStack.empty()) { 394 pftParentStack.back().visit(common::visitors{ 395 [&](lower::pft::FunctionLikeUnit &p) { 396 functionList = &p.nestedFunctions; 397 labelEvaluationMap = &p.labelEvaluationMap; 398 assignSymbolLabelMap = &p.assignSymbolLabelMap; 399 }, 400 [&](lower::pft::ModuleLikeUnit &p) { 401 functionList = &p.nestedFunctions; 402 }, 403 [&](auto &) { functionList = nullptr; }, 404 }); 405 } 406 } 407 408 template <typename A> 409 A &addUnit(A &&unit) { 410 pgm->getUnits().emplace_back(std::move(unit)); 411 return std::get<A>(pgm->getUnits().back()); 412 } 413 414 template <typename A> 415 A &addFunction(A &&func) { 416 if (functionList) { 417 functionList->emplace_back(std::move(func)); 418 return functionList->back(); 419 } 420 return addUnit(std::move(func)); 421 } 422 423 // ActionStmt has a couple of non-conforming cases, explicitly handled here. 424 // The other cases use an Indirection, which are discarded in the PFT. 425 lower::pft::Evaluation 426 makeEvaluationAction(const parser::ActionStmt &statement, 427 parser::CharBlock position, 428 std::optional<parser::Label> label) { 429 return std::visit( 430 common::visitors{ 431 [&](const auto &x) { 432 return lower::pft::Evaluation{ 433 removeIndirection(x), pftParentStack.back(), position, label}; 434 }, 435 }, 436 statement.u); 437 } 438 439 /// Append an Evaluation to the end of the current list. 440 lower::pft::Evaluation &addEvaluation(lower::pft::Evaluation &&eval) { 441 assert(functionList && "not in a function"); 442 assert(!evaluationListStack.empty() && "empty evaluation list stack"); 443 if (!constructAndDirectiveStack.empty()) 444 eval.parentConstruct = constructAndDirectiveStack.back(); 445 lower::pft::FunctionLikeUnit *owningProcedure = eval.getOwningProcedure(); 446 evaluationListStack.back()->emplace_back(std::move(eval)); 447 lower::pft::Evaluation *p = &evaluationListStack.back()->back(); 448 if (p->isActionStmt() || p->isConstructStmt() || p->isEndStmt() || 449 p->isExecutableDirective()) { 450 if (lastLexicalEvaluation) { 451 lastLexicalEvaluation->lexicalSuccessor = p; 452 p->printIndex = lastLexicalEvaluation->printIndex + 1; 453 } else { 454 p->printIndex = 1; 455 } 456 lastLexicalEvaluation = p; 457 if (owningProcedure) { 458 auto &entryPointList = owningProcedure->entryPointList; 459 for (std::size_t entryIndex = entryPointList.size() - 1; 460 entryIndex && !entryPointList[entryIndex].second->lexicalSuccessor; 461 --entryIndex) 462 // Link to the entry's first executable statement. 463 entryPointList[entryIndex].second->lexicalSuccessor = p; 464 } 465 } else if (const auto *entryStmt = p->getIf<parser::EntryStmt>()) { 466 const semantics::Symbol *sym = 467 std::get<parser::Name>(entryStmt->t).symbol; 468 if (auto *details = sym->detailsIf<semantics::GenericDetails>()) 469 sym = details->specific(); 470 assert(sym->has<semantics::SubprogramDetails>() && 471 "entry must be a subprogram"); 472 owningProcedure->entryPointList.push_back(std::pair{sym, p}); 473 } 474 if (p->label.has_value()) 475 labelEvaluationMap->try_emplace(*p->label, p); 476 return evaluationListStack.back()->back(); 477 } 478 479 /// push a new list on the stack of Evaluation lists 480 void pushEvaluationList(lower::pft::EvaluationList *evaluationList) { 481 assert(functionList && "not in a function"); 482 assert(evaluationList && evaluationList->empty() && 483 "evaluation list isn't correct"); 484 evaluationListStack.emplace_back(evaluationList); 485 } 486 487 /// pop the current list and return to the last Evaluation list 488 void popEvaluationList() { 489 assert(functionList && "not in a function"); 490 evaluationListStack.pop_back(); 491 } 492 493 /// Rewrite IfConstructs containing a GotoStmt or CycleStmt to eliminate an 494 /// unstructured branch and a trivial basic block. The pre-branch-analysis 495 /// code: 496 /// 497 /// <<IfConstruct>> 498 /// 1 If[Then]Stmt: if(cond) goto L 499 /// 2 GotoStmt: goto L 500 /// 3 EndIfStmt 501 /// <<End IfConstruct>> 502 /// 4 Statement: ... 503 /// 5 Statement: ... 504 /// 6 Statement: L ... 505 /// 506 /// becomes: 507 /// 508 /// <<IfConstruct>> 509 /// 1 If[Then]Stmt [negate]: if(cond) goto L 510 /// 4 Statement: ... 511 /// 5 Statement: ... 512 /// 3 EndIfStmt 513 /// <<End IfConstruct>> 514 /// 6 Statement: L ... 515 /// 516 /// The If[Then]Stmt condition is implicitly negated. It is not modified 517 /// in the PFT. It must be negated when generating FIR. The GotoStmt or 518 /// CycleStmt is deleted. 519 /// 520 /// The transformation is only valid for forward branch targets at the same 521 /// construct nesting level as the IfConstruct. The result must not violate 522 /// construct nesting requirements or contain an EntryStmt. The result 523 /// is subject to normal un/structured code classification analysis. The 524 /// result is allowed to violate the F18 Clause 11.1.2.1 prohibition on 525 /// transfer of control into the interior of a construct block, as that does 526 /// not compromise correct code generation. When two transformation 527 /// candidates overlap, at least one must be disallowed. In such cases, 528 /// the current heuristic favors simple code generation, which happens to 529 /// favor later candidates over earlier candidates. That choice is probably 530 /// not significant, but could be changed. 531 /// 532 void rewriteIfGotos() { 533 auto &evaluationList = *evaluationListStack.back(); 534 if (!evaluationList.size()) 535 return; 536 struct T { 537 lower::pft::EvaluationList::iterator ifConstructIt; 538 parser::Label ifTargetLabel; 539 bool isCycleStmt = false; 540 }; 541 llvm::SmallVector<T> ifCandidateStack; 542 const auto *doStmt = 543 evaluationList.begin()->getIf<parser::NonLabelDoStmt>(); 544 std::string doName = doStmt ? getConstructName(*doStmt) : std::string{}; 545 for (auto it = evaluationList.begin(), end = evaluationList.end(); 546 it != end; ++it) { 547 auto &eval = *it; 548 if (eval.isA<parser::EntryStmt>() || eval.isIntermediateConstructStmt()) { 549 ifCandidateStack.clear(); 550 continue; 551 } 552 auto firstStmt = [](lower::pft::Evaluation *e) { 553 return e->isConstruct() ? &*e->evaluationList->begin() : e; 554 }; 555 const Fortran::lower::pft::Evaluation &targetEval = *firstStmt(&eval); 556 bool targetEvalIsEndDoStmt = targetEval.isA<parser::EndDoStmt>(); 557 auto branchTargetMatch = [&]() { 558 if (const parser::Label targetLabel = 559 ifCandidateStack.back().ifTargetLabel) 560 if (targetEval.label && targetLabel == *targetEval.label) 561 return true; // goto target match 562 if (targetEvalIsEndDoStmt && ifCandidateStack.back().isCycleStmt) 563 return true; // cycle target match 564 return false; 565 }; 566 if (targetEval.label || targetEvalIsEndDoStmt) { 567 while (!ifCandidateStack.empty() && branchTargetMatch()) { 568 lower::pft::EvaluationList::iterator ifConstructIt = 569 ifCandidateStack.back().ifConstructIt; 570 lower::pft::EvaluationList::iterator successorIt = 571 std::next(ifConstructIt); 572 if (successorIt != it) { 573 Fortran::lower::pft::EvaluationList &ifBodyList = 574 *ifConstructIt->evaluationList; 575 lower::pft::EvaluationList::iterator branchStmtIt = 576 std::next(ifBodyList.begin()); 577 assert((branchStmtIt->isA<parser::GotoStmt>() || 578 branchStmtIt->isA<parser::CycleStmt>()) && 579 "expected goto or cycle statement"); 580 ifBodyList.erase(branchStmtIt); 581 lower::pft::Evaluation &ifStmt = *ifBodyList.begin(); 582 ifStmt.negateCondition = true; 583 ifStmt.lexicalSuccessor = firstStmt(&*successorIt); 584 lower::pft::EvaluationList::iterator endIfStmtIt = 585 std::prev(ifBodyList.end()); 586 std::prev(it)->lexicalSuccessor = &*endIfStmtIt; 587 endIfStmtIt->lexicalSuccessor = firstStmt(&*it); 588 ifBodyList.splice(endIfStmtIt, evaluationList, successorIt, it); 589 for (; successorIt != endIfStmtIt; ++successorIt) 590 successorIt->parentConstruct = &*ifConstructIt; 591 } 592 ifCandidateStack.pop_back(); 593 } 594 } 595 if (eval.isA<parser::IfConstruct>() && eval.evaluationList->size() == 3) { 596 const auto bodyEval = std::next(eval.evaluationList->begin()); 597 if (const auto *gotoStmt = bodyEval->getIf<parser::GotoStmt>()) { 598 ifCandidateStack.push_back({it, gotoStmt->v}); 599 } else if (doStmt) { 600 if (const auto *cycleStmt = bodyEval->getIf<parser::CycleStmt>()) { 601 std::string cycleName = getConstructName(*cycleStmt); 602 if (cycleName.empty() || cycleName == doName) 603 // This candidate will match doStmt's EndDoStmt. 604 ifCandidateStack.push_back({it, {}, true}); 605 } 606 } 607 } 608 } 609 } 610 611 /// Mark IO statement ERR, EOR, and END specifier branch targets. 612 /// Mark an IO statement with an assigned format as unstructured. 613 template <typename A> 614 void analyzeIoBranches(lower::pft::Evaluation &eval, const A &stmt) { 615 auto analyzeFormatSpec = [&](const parser::Format &format) { 616 if (const auto *expr = std::get_if<parser::Expr>(&format.u)) { 617 if (semantics::ExprHasTypeCategory(*semantics::GetExpr(*expr), 618 common::TypeCategory::Integer)) 619 eval.isUnstructured = true; 620 } 621 }; 622 auto analyzeSpecs{[&](const auto &specList) { 623 for (const auto &spec : specList) { 624 std::visit( 625 Fortran::common::visitors{ 626 [&](const Fortran::parser::Format &format) { 627 analyzeFormatSpec(format); 628 }, 629 [&](const auto &label) { 630 using LabelNodes = 631 std::tuple<parser::ErrLabel, parser::EorLabel, 632 parser::EndLabel>; 633 if constexpr (common::HasMember<decltype(label), LabelNodes>) 634 markBranchTarget(eval, label.v); 635 }}, 636 spec.u); 637 } 638 }}; 639 640 using OtherIOStmts = 641 std::tuple<parser::BackspaceStmt, parser::CloseStmt, 642 parser::EndfileStmt, parser::FlushStmt, parser::OpenStmt, 643 parser::RewindStmt, parser::WaitStmt>; 644 645 if constexpr (std::is_same_v<A, parser::ReadStmt> || 646 std::is_same_v<A, parser::WriteStmt>) { 647 if (stmt.format) 648 analyzeFormatSpec(*stmt.format); 649 analyzeSpecs(stmt.controls); 650 } else if constexpr (std::is_same_v<A, parser::PrintStmt>) { 651 analyzeFormatSpec(std::get<parser::Format>(stmt.t)); 652 } else if constexpr (std::is_same_v<A, parser::InquireStmt>) { 653 if (const auto *specList = 654 std::get_if<std::list<parser::InquireSpec>>(&stmt.u)) 655 analyzeSpecs(*specList); 656 } else if constexpr (common::HasMember<A, OtherIOStmts>) { 657 analyzeSpecs(stmt.v); 658 } else { 659 // Always crash if this is instantiated 660 static_assert(!std::is_same_v<A, parser::ReadStmt>, 661 "Unexpected IO statement"); 662 } 663 } 664 665 /// Set the exit of a construct, possibly from multiple enclosing constructs. 666 void setConstructExit(lower::pft::Evaluation &eval) { 667 eval.constructExit = &eval.evaluationList->back().nonNopSuccessor(); 668 } 669 670 /// Mark the target of a branch as a new block. 671 void markBranchTarget(lower::pft::Evaluation &sourceEvaluation, 672 lower::pft::Evaluation &targetEvaluation) { 673 sourceEvaluation.isUnstructured = true; 674 if (!sourceEvaluation.controlSuccessor) 675 sourceEvaluation.controlSuccessor = &targetEvaluation; 676 targetEvaluation.isNewBlock = true; 677 // If this is a branch into the body of a construct (usually illegal, 678 // but allowed in some legacy cases), then the targetEvaluation and its 679 // ancestors must be marked as unstructured. 680 lower::pft::Evaluation *sourceConstruct = sourceEvaluation.parentConstruct; 681 lower::pft::Evaluation *targetConstruct = targetEvaluation.parentConstruct; 682 if (targetConstruct && 683 &targetConstruct->getFirstNestedEvaluation() == &targetEvaluation) 684 // A branch to an initial constructStmt is a branch to the construct. 685 targetConstruct = targetConstruct->parentConstruct; 686 if (targetConstruct) { 687 while (sourceConstruct && sourceConstruct != targetConstruct) 688 sourceConstruct = sourceConstruct->parentConstruct; 689 if (sourceConstruct != targetConstruct) // branch into a construct body 690 for (lower::pft::Evaluation *eval = &targetEvaluation; eval; 691 eval = eval->parentConstruct) { 692 eval->isUnstructured = true; 693 // If the branch is a backward branch into an already analyzed 694 // DO or IF construct, mark the construct exit as a new block. 695 // For a forward branch, the isUnstructured flag will cause this 696 // to be done when the construct is analyzed. 697 if (eval->constructExit && (eval->isA<parser::DoConstruct>() || 698 eval->isA<parser::IfConstruct>())) 699 eval->constructExit->isNewBlock = true; 700 } 701 } 702 } 703 void markBranchTarget(lower::pft::Evaluation &sourceEvaluation, 704 parser::Label label) { 705 assert(label && "missing branch target label"); 706 lower::pft::Evaluation *targetEvaluation{ 707 labelEvaluationMap->find(label)->second}; 708 assert(targetEvaluation && "missing branch target evaluation"); 709 markBranchTarget(sourceEvaluation, *targetEvaluation); 710 } 711 712 /// Mark the successor of an Evaluation as a new block. 713 void markSuccessorAsNewBlock(lower::pft::Evaluation &eval) { 714 eval.nonNopSuccessor().isNewBlock = true; 715 } 716 717 template <typename A> 718 inline std::string getConstructName(const A &stmt) { 719 using MaybeConstructNameWrapper = 720 std::tuple<parser::BlockStmt, parser::CycleStmt, parser::ElseStmt, 721 parser::ElsewhereStmt, parser::EndAssociateStmt, 722 parser::EndBlockStmt, parser::EndCriticalStmt, 723 parser::EndDoStmt, parser::EndForallStmt, parser::EndIfStmt, 724 parser::EndSelectStmt, parser::EndWhereStmt, 725 parser::ExitStmt>; 726 if constexpr (common::HasMember<A, MaybeConstructNameWrapper>) { 727 if (stmt.v) 728 return stmt.v->ToString(); 729 } 730 731 using MaybeConstructNameInTuple = std::tuple< 732 parser::AssociateStmt, parser::CaseStmt, parser::ChangeTeamStmt, 733 parser::CriticalStmt, parser::ElseIfStmt, parser::EndChangeTeamStmt, 734 parser::ForallConstructStmt, parser::IfThenStmt, parser::LabelDoStmt, 735 parser::MaskedElsewhereStmt, parser::NonLabelDoStmt, 736 parser::SelectCaseStmt, parser::SelectRankCaseStmt, 737 parser::TypeGuardStmt, parser::WhereConstructStmt>; 738 if constexpr (common::HasMember<A, MaybeConstructNameInTuple>) { 739 if (auto name = std::get<std::optional<parser::Name>>(stmt.t)) 740 return name->ToString(); 741 } 742 743 // These statements have multiple std::optional<parser::Name> elements. 744 if constexpr (std::is_same_v<A, parser::SelectRankStmt> || 745 std::is_same_v<A, parser::SelectTypeStmt>) { 746 if (auto name = std::get<0>(stmt.t)) 747 return name->ToString(); 748 } 749 750 return {}; 751 } 752 753 /// \p parentConstruct can be null if this statement is at the highest 754 /// level of a program. 755 template <typename A> 756 void insertConstructName(const A &stmt, 757 lower::pft::Evaluation *parentConstruct) { 758 std::string name = getConstructName(stmt); 759 if (!name.empty()) 760 constructNameMap[name] = parentConstruct; 761 } 762 763 /// Insert branch links for a list of Evaluations. 764 /// \p parentConstruct can be null if the evaluationList contains the 765 /// top-level statements of a program. 766 void analyzeBranches(lower::pft::Evaluation *parentConstruct, 767 std::list<lower::pft::Evaluation> &evaluationList) { 768 lower::pft::Evaluation *lastConstructStmtEvaluation{}; 769 for (auto &eval : evaluationList) { 770 eval.visit(common::visitors{ 771 // Action statements (except IO statements) 772 [&](const parser::CallStmt &s) { 773 // Look for alternate return specifiers. 774 const auto &args = 775 std::get<std::list<parser::ActualArgSpec>>(s.call.t); 776 for (const auto &arg : args) { 777 const auto &actual = std::get<parser::ActualArg>(arg.t); 778 if (const auto *altReturn = 779 std::get_if<parser::AltReturnSpec>(&actual.u)) 780 markBranchTarget(eval, altReturn->v); 781 } 782 }, 783 [&](const parser::CycleStmt &s) { 784 std::string name = getConstructName(s); 785 lower::pft::Evaluation *construct{name.empty() 786 ? doConstructStack.back() 787 : constructNameMap[name]}; 788 assert(construct && "missing CYCLE construct"); 789 markBranchTarget(eval, construct->evaluationList->back()); 790 }, 791 [&](const parser::ExitStmt &s) { 792 std::string name = getConstructName(s); 793 lower::pft::Evaluation *construct{name.empty() 794 ? doConstructStack.back() 795 : constructNameMap[name]}; 796 assert(construct && "missing EXIT construct"); 797 markBranchTarget(eval, *construct->constructExit); 798 }, 799 [&](const parser::FailImageStmt &) { 800 eval.isUnstructured = true; 801 if (eval.lexicalSuccessor->lexicalSuccessor) 802 markSuccessorAsNewBlock(eval); 803 }, 804 [&](const parser::GotoStmt &s) { markBranchTarget(eval, s.v); }, 805 [&](const parser::IfStmt &) { 806 eval.lexicalSuccessor->isNewBlock = true; 807 lastConstructStmtEvaluation = &eval; 808 }, 809 [&](const parser::ReturnStmt &) { 810 eval.isUnstructured = true; 811 if (eval.lexicalSuccessor->lexicalSuccessor) 812 markSuccessorAsNewBlock(eval); 813 }, 814 [&](const parser::StopStmt &) { 815 eval.isUnstructured = true; 816 if (eval.lexicalSuccessor->lexicalSuccessor) 817 markSuccessorAsNewBlock(eval); 818 }, 819 [&](const parser::ComputedGotoStmt &s) { 820 for (auto &label : std::get<std::list<parser::Label>>(s.t)) 821 markBranchTarget(eval, label); 822 }, 823 [&](const parser::ArithmeticIfStmt &s) { 824 markBranchTarget(eval, std::get<1>(s.t)); 825 markBranchTarget(eval, std::get<2>(s.t)); 826 markBranchTarget(eval, std::get<3>(s.t)); 827 }, 828 [&](const parser::AssignStmt &s) { // legacy label assignment 829 auto &label = std::get<parser::Label>(s.t); 830 const auto *sym = std::get<parser::Name>(s.t).symbol; 831 assert(sym && "missing AssignStmt symbol"); 832 lower::pft::Evaluation *target{ 833 labelEvaluationMap->find(label)->second}; 834 assert(target && "missing branch target evaluation"); 835 if (!target->isA<parser::FormatStmt>()) 836 target->isNewBlock = true; 837 auto iter = assignSymbolLabelMap->find(*sym); 838 if (iter == assignSymbolLabelMap->end()) { 839 lower::pft::LabelSet labelSet{}; 840 labelSet.insert(label); 841 assignSymbolLabelMap->try_emplace(*sym, labelSet); 842 } else { 843 iter->second.insert(label); 844 } 845 }, 846 [&](const parser::AssignedGotoStmt &) { 847 // Although this statement is a branch, it doesn't have any 848 // explicit control successors. So the code at the end of the 849 // loop won't mark the successor. Do that here. 850 eval.isUnstructured = true; 851 markSuccessorAsNewBlock(eval); 852 }, 853 854 // The first executable statement after an EntryStmt is a new block. 855 [&](const parser::EntryStmt &) { 856 eval.lexicalSuccessor->isNewBlock = true; 857 }, 858 859 // Construct statements 860 [&](const parser::AssociateStmt &s) { 861 insertConstructName(s, parentConstruct); 862 }, 863 [&](const parser::BlockStmt &s) { 864 insertConstructName(s, parentConstruct); 865 }, 866 [&](const parser::SelectCaseStmt &s) { 867 insertConstructName(s, parentConstruct); 868 lastConstructStmtEvaluation = &eval; 869 }, 870 [&](const parser::CaseStmt &) { 871 eval.isNewBlock = true; 872 lastConstructStmtEvaluation->controlSuccessor = &eval; 873 lastConstructStmtEvaluation = &eval; 874 }, 875 [&](const parser::EndSelectStmt &) { 876 eval.isNewBlock = true; 877 lastConstructStmtEvaluation = nullptr; 878 }, 879 [&](const parser::ChangeTeamStmt &s) { 880 insertConstructName(s, parentConstruct); 881 }, 882 [&](const parser::CriticalStmt &s) { 883 insertConstructName(s, parentConstruct); 884 }, 885 [&](const parser::NonLabelDoStmt &s) { 886 insertConstructName(s, parentConstruct); 887 doConstructStack.push_back(parentConstruct); 888 const auto &loopControl = 889 std::get<std::optional<parser::LoopControl>>(s.t); 890 if (!loopControl.has_value()) { 891 eval.isUnstructured = true; // infinite loop 892 return; 893 } 894 eval.nonNopSuccessor().isNewBlock = true; 895 eval.controlSuccessor = &evaluationList.back(); 896 if (const auto *bounds = 897 std::get_if<parser::LoopControl::Bounds>(&loopControl->u)) { 898 if (bounds->name.thing.symbol->GetType()->IsNumeric( 899 common::TypeCategory::Real)) 900 eval.isUnstructured = true; // real-valued loop control 901 } else if (std::get_if<parser::ScalarLogicalExpr>( 902 &loopControl->u)) { 903 eval.isUnstructured = true; // while loop 904 } 905 }, 906 [&](const parser::EndDoStmt &) { 907 lower::pft::Evaluation &doEval = evaluationList.front(); 908 eval.controlSuccessor = &doEval; 909 doConstructStack.pop_back(); 910 if (parentConstruct->lowerAsStructured()) 911 return; 912 // The loop is unstructured, which wasn't known for all cases when 913 // visiting the NonLabelDoStmt. 914 parentConstruct->constructExit->isNewBlock = true; 915 const auto &doStmt = *doEval.getIf<parser::NonLabelDoStmt>(); 916 const auto &loopControl = 917 std::get<std::optional<parser::LoopControl>>(doStmt.t); 918 if (!loopControl.has_value()) 919 return; // infinite loop 920 if (const auto *concurrent = 921 std::get_if<parser::LoopControl::Concurrent>( 922 &loopControl->u)) { 923 // If there is a mask, the EndDoStmt starts a new block. 924 const auto &header = 925 std::get<parser::ConcurrentHeader>(concurrent->t); 926 eval.isNewBlock |= 927 std::get<std::optional<parser::ScalarLogicalExpr>>(header.t) 928 .has_value(); 929 } 930 }, 931 [&](const parser::IfThenStmt &s) { 932 insertConstructName(s, parentConstruct); 933 eval.lexicalSuccessor->isNewBlock = true; 934 lastConstructStmtEvaluation = &eval; 935 }, 936 [&](const parser::ElseIfStmt &) { 937 eval.isNewBlock = true; 938 eval.lexicalSuccessor->isNewBlock = true; 939 lastConstructStmtEvaluation->controlSuccessor = &eval; 940 lastConstructStmtEvaluation = &eval; 941 }, 942 [&](const parser::ElseStmt &) { 943 eval.isNewBlock = true; 944 lastConstructStmtEvaluation->controlSuccessor = &eval; 945 lastConstructStmtEvaluation = nullptr; 946 }, 947 [&](const parser::EndIfStmt &) { 948 if (parentConstruct->lowerAsUnstructured()) 949 parentConstruct->constructExit->isNewBlock = true; 950 if (lastConstructStmtEvaluation) { 951 lastConstructStmtEvaluation->controlSuccessor = 952 parentConstruct->constructExit; 953 lastConstructStmtEvaluation = nullptr; 954 } 955 }, 956 [&](const parser::SelectRankStmt &s) { 957 insertConstructName(s, parentConstruct); 958 lastConstructStmtEvaluation = &eval; 959 }, 960 [&](const parser::SelectRankCaseStmt &) { 961 eval.isNewBlock = true; 962 lastConstructStmtEvaluation->controlSuccessor = &eval; 963 lastConstructStmtEvaluation = &eval; 964 }, 965 [&](const parser::SelectTypeStmt &s) { 966 insertConstructName(s, parentConstruct); 967 lastConstructStmtEvaluation = &eval; 968 }, 969 [&](const parser::TypeGuardStmt &) { 970 eval.isNewBlock = true; 971 lastConstructStmtEvaluation->controlSuccessor = &eval; 972 lastConstructStmtEvaluation = &eval; 973 }, 974 975 // Constructs - set (unstructured) construct exit targets 976 [&](const parser::AssociateConstruct &) { 977 eval.constructExit = &eval.evaluationList->back(); 978 }, 979 [&](const parser::BlockConstruct &) { 980 eval.constructExit = &eval.evaluationList->back(); 981 }, 982 [&](const parser::CaseConstruct &) { 983 eval.constructExit = &eval.evaluationList->back(); 984 eval.isUnstructured = true; 985 }, 986 [&](const parser::ChangeTeamConstruct &) { 987 eval.constructExit = &eval.evaluationList->back(); 988 }, 989 [&](const parser::CriticalConstruct &) { 990 eval.constructExit = &eval.evaluationList->back(); 991 }, 992 [&](const parser::DoConstruct &) { setConstructExit(eval); }, 993 [&](const parser::ForallConstruct &) { setConstructExit(eval); }, 994 [&](const parser::IfConstruct &) { setConstructExit(eval); }, 995 [&](const parser::SelectRankConstruct &) { 996 eval.constructExit = &eval.evaluationList->back(); 997 eval.isUnstructured = true; 998 }, 999 [&](const parser::SelectTypeConstruct &) { 1000 eval.constructExit = &eval.evaluationList->back(); 1001 eval.isUnstructured = true; 1002 }, 1003 [&](const parser::WhereConstruct &) { setConstructExit(eval); }, 1004 1005 // Default - Common analysis for IO statements; otherwise nop. 1006 [&](const auto &stmt) { 1007 using A = std::decay_t<decltype(stmt)>; 1008 using IoStmts = std::tuple< 1009 parser::BackspaceStmt, parser::CloseStmt, parser::EndfileStmt, 1010 parser::FlushStmt, parser::InquireStmt, parser::OpenStmt, 1011 parser::PrintStmt, parser::ReadStmt, parser::RewindStmt, 1012 parser::WaitStmt, parser::WriteStmt>; 1013 if constexpr (common::HasMember<A, IoStmts>) 1014 analyzeIoBranches(eval, stmt); 1015 }, 1016 }); 1017 1018 // Analyze construct evaluations. 1019 if (eval.evaluationList) 1020 analyzeBranches(&eval, *eval.evaluationList); 1021 1022 // Propagate isUnstructured flag to enclosing construct. 1023 if (parentConstruct && eval.isUnstructured) 1024 parentConstruct->isUnstructured = true; 1025 1026 // The successor of a branch starts a new block. 1027 if (eval.controlSuccessor && eval.isActionStmt() && 1028 eval.lowerAsUnstructured()) 1029 markSuccessorAsNewBlock(eval); 1030 } 1031 } 1032 1033 /// Do processing specific to subprograms with multiple entry points. 1034 void processEntryPoints() { 1035 lower::pft::Evaluation *initialEval = &evaluationListStack.back()->front(); 1036 lower::pft::FunctionLikeUnit *unit = initialEval->getOwningProcedure(); 1037 int entryCount = unit->entryPointList.size(); 1038 if (entryCount == 1) 1039 return; 1040 1041 // The first executable statement in the subprogram is preceded by a 1042 // branch to the entry point, so it starts a new block. 1043 if (initialEval->hasNestedEvaluations()) 1044 initialEval = &initialEval->getFirstNestedEvaluation(); 1045 else if (initialEval->isA<Fortran::parser::EntryStmt>()) 1046 initialEval = initialEval->lexicalSuccessor; 1047 initialEval->isNewBlock = true; 1048 1049 // All function entry points share a single result container. 1050 // Find one of the largest results. 1051 for (int entryIndex = 0; entryIndex < entryCount; ++entryIndex) { 1052 unit->setActiveEntry(entryIndex); 1053 const auto &details = 1054 unit->getSubprogramSymbol().get<semantics::SubprogramDetails>(); 1055 if (details.isFunction()) { 1056 const semantics::Symbol *resultSym = &details.result(); 1057 assert(resultSym && "missing result symbol"); 1058 if (!unit->primaryResult || 1059 unit->primaryResult->size() < resultSym->size()) 1060 unit->primaryResult = resultSym; 1061 } 1062 } 1063 unit->setActiveEntry(0); 1064 } 1065 1066 std::unique_ptr<lower::pft::Program> pgm; 1067 std::vector<lower::pft::PftNode> pftParentStack; 1068 const semantics::SemanticsContext &semanticsContext; 1069 1070 /// functionList points to the internal or module procedure function list 1071 /// of a FunctionLikeUnit or a ModuleLikeUnit. It may be null. 1072 std::list<lower::pft::FunctionLikeUnit> *functionList{}; 1073 std::vector<lower::pft::Evaluation *> constructAndDirectiveStack{}; 1074 std::vector<lower::pft::Evaluation *> doConstructStack{}; 1075 /// evaluationListStack is the current nested construct evaluationList state. 1076 std::vector<lower::pft::EvaluationList *> evaluationListStack{}; 1077 llvm::DenseMap<parser::Label, lower::pft::Evaluation *> *labelEvaluationMap{}; 1078 lower::pft::SymbolLabelMap *assignSymbolLabelMap{}; 1079 std::map<std::string, lower::pft::Evaluation *> constructNameMap{}; 1080 lower::pft::Evaluation *lastLexicalEvaluation{}; 1081 }; 1082 1083 #ifndef NDEBUG 1084 /// Dump all program scopes and symbols with addresses to disambiguate names. 1085 /// This is static, unchanging front end information, so dump it only once. 1086 void dumpScope(const semantics::Scope *scope, int depth) { 1087 static int initialVisitCounter = 0; 1088 if (depth < 0) { 1089 if (++initialVisitCounter != 1) 1090 return; 1091 while (!scope->IsGlobal()) 1092 scope = &scope->parent(); 1093 LLVM_DEBUG(llvm::dbgs() << "Full program scope information.\n" 1094 "Addresses in angle brackets are scopes. " 1095 "Unbracketed addresses are symbols.\n"); 1096 } 1097 static const std::string white{" ++"}; 1098 std::string w = white.substr(0, depth * 2); 1099 if (depth >= 0) { 1100 LLVM_DEBUG(llvm::dbgs() << w << "<" << scope << "> "); 1101 if (auto *sym{scope->symbol()}) { 1102 LLVM_DEBUG(llvm::dbgs() << sym << " " << *sym << "\n"); 1103 } else { 1104 if (scope->IsIntrinsicModules()) { 1105 LLVM_DEBUG(llvm::dbgs() << "IntrinsicModules (no detail)\n"); 1106 return; 1107 } 1108 if (scope->kind() == Fortran::semantics::Scope::Kind::BlockConstruct) 1109 LLVM_DEBUG(llvm::dbgs() << "[block]\n"); 1110 else 1111 LLVM_DEBUG(llvm::dbgs() << "[anonymous]\n"); 1112 } 1113 } 1114 for (const auto &scp : scope->children()) 1115 if (!scp.symbol()) 1116 dumpScope(&scp, depth + 1); 1117 for (auto iter = scope->begin(); iter != scope->end(); ++iter) { 1118 common::Reference<semantics::Symbol> sym = iter->second; 1119 if (auto scp = sym->scope()) 1120 dumpScope(scp, depth + 1); 1121 else 1122 LLVM_DEBUG(llvm::dbgs() << w + " " << &*sym << " " << *sym << "\n"); 1123 } 1124 } 1125 #endif // NDEBUG 1126 1127 class PFTDumper { 1128 public: 1129 void dumpPFT(llvm::raw_ostream &outputStream, 1130 const lower::pft::Program &pft) { 1131 for (auto &unit : pft.getUnits()) { 1132 std::visit(common::visitors{ 1133 [&](const lower::pft::BlockDataUnit &unit) { 1134 outputStream << getNodeIndex(unit) << " "; 1135 outputStream << "BlockData: "; 1136 outputStream << "\nEnd BlockData\n\n"; 1137 }, 1138 [&](const lower::pft::FunctionLikeUnit &func) { 1139 dumpFunctionLikeUnit(outputStream, func); 1140 }, 1141 [&](const lower::pft::ModuleLikeUnit &unit) { 1142 dumpModuleLikeUnit(outputStream, unit); 1143 }, 1144 [&](const lower::pft::CompilerDirectiveUnit &unit) { 1145 dumpCompilerDirectiveUnit(outputStream, unit); 1146 }, 1147 [&](const lower::pft::OpenACCDirectiveUnit &unit) { 1148 dumpOpenACCDirectiveUnit(outputStream, unit); 1149 }, 1150 }, 1151 unit); 1152 } 1153 } 1154 1155 llvm::StringRef evaluationName(const lower::pft::Evaluation &eval) { 1156 return eval.visit([](const auto &parseTreeNode) { 1157 return parser::ParseTreeDumper::GetNodeName(parseTreeNode); 1158 }); 1159 } 1160 1161 void dumpEvaluation(llvm::raw_ostream &outputStream, 1162 const lower::pft::Evaluation &eval, 1163 const std::string &indentString, int indent = 1) { 1164 llvm::StringRef name = evaluationName(eval); 1165 llvm::StringRef newBlock = eval.isNewBlock ? "^" : ""; 1166 llvm::StringRef bang = eval.isUnstructured ? "!" : ""; 1167 outputStream << indentString; 1168 if (eval.printIndex) 1169 outputStream << eval.printIndex << ' '; 1170 if (eval.hasNestedEvaluations()) 1171 outputStream << "<<" << newBlock << name << bang << ">>"; 1172 else 1173 outputStream << newBlock << name << bang; 1174 if (eval.negateCondition) 1175 outputStream << " [negate]"; 1176 if (eval.constructExit) 1177 outputStream << " -> " << eval.constructExit->printIndex; 1178 else if (eval.controlSuccessor) 1179 outputStream << " -> " << eval.controlSuccessor->printIndex; 1180 else if (eval.isA<parser::EntryStmt>() && eval.lexicalSuccessor) 1181 outputStream << " -> " << eval.lexicalSuccessor->printIndex; 1182 if (!eval.position.empty()) 1183 outputStream << ": " << eval.position.ToString(); 1184 else if (auto *dir = eval.getIf<Fortran::parser::CompilerDirective>()) 1185 outputStream << ": !" << dir->source.ToString(); 1186 outputStream << '\n'; 1187 if (eval.hasNestedEvaluations()) { 1188 dumpEvaluationList(outputStream, *eval.evaluationList, indent + 1); 1189 outputStream << indentString << "<<End " << name << bang << ">>\n"; 1190 } 1191 } 1192 1193 void dumpEvaluation(llvm::raw_ostream &ostream, 1194 const lower::pft::Evaluation &eval) { 1195 dumpEvaluation(ostream, eval, ""); 1196 } 1197 1198 void dumpEvaluationList(llvm::raw_ostream &outputStream, 1199 const lower::pft::EvaluationList &evaluationList, 1200 int indent = 1) { 1201 static const auto white = " ++"s; 1202 auto indentString = white.substr(0, indent * 2); 1203 for (const lower::pft::Evaluation &eval : evaluationList) 1204 dumpEvaluation(outputStream, eval, indentString, indent); 1205 } 1206 1207 void 1208 dumpFunctionLikeUnit(llvm::raw_ostream &outputStream, 1209 const lower::pft::FunctionLikeUnit &functionLikeUnit) { 1210 outputStream << getNodeIndex(functionLikeUnit) << " "; 1211 llvm::StringRef unitKind; 1212 llvm::StringRef name; 1213 llvm::StringRef header; 1214 if (functionLikeUnit.beginStmt) { 1215 functionLikeUnit.beginStmt->visit(common::visitors{ 1216 [&](const parser::Statement<parser::ProgramStmt> &stmt) { 1217 unitKind = "Program"; 1218 name = toStringRef(stmt.statement.v.source); 1219 }, 1220 [&](const parser::Statement<parser::FunctionStmt> &stmt) { 1221 unitKind = "Function"; 1222 name = toStringRef(std::get<parser::Name>(stmt.statement.t).source); 1223 header = toStringRef(stmt.source); 1224 }, 1225 [&](const parser::Statement<parser::SubroutineStmt> &stmt) { 1226 unitKind = "Subroutine"; 1227 name = toStringRef(std::get<parser::Name>(stmt.statement.t).source); 1228 header = toStringRef(stmt.source); 1229 }, 1230 [&](const parser::Statement<parser::MpSubprogramStmt> &stmt) { 1231 unitKind = "MpSubprogram"; 1232 name = toStringRef(stmt.statement.v.source); 1233 header = toStringRef(stmt.source); 1234 }, 1235 [&](const auto &) { llvm_unreachable("not a valid begin stmt"); }, 1236 }); 1237 } else { 1238 unitKind = "Program"; 1239 name = "<anonymous>"; 1240 } 1241 outputStream << unitKind << ' ' << name; 1242 if (!header.empty()) 1243 outputStream << ": " << header; 1244 outputStream << '\n'; 1245 dumpEvaluationList(outputStream, functionLikeUnit.evaluationList); 1246 if (!functionLikeUnit.nestedFunctions.empty()) { 1247 outputStream << "\nContains\n"; 1248 for (const lower::pft::FunctionLikeUnit &func : 1249 functionLikeUnit.nestedFunctions) 1250 dumpFunctionLikeUnit(outputStream, func); 1251 outputStream << "End Contains\n"; 1252 } 1253 outputStream << "End " << unitKind << ' ' << name << "\n\n"; 1254 } 1255 1256 void dumpModuleLikeUnit(llvm::raw_ostream &outputStream, 1257 const lower::pft::ModuleLikeUnit &moduleLikeUnit) { 1258 outputStream << getNodeIndex(moduleLikeUnit) << " "; 1259 llvm::StringRef unitKind; 1260 llvm::StringRef name; 1261 llvm::StringRef header; 1262 moduleLikeUnit.beginStmt.visit(common::visitors{ 1263 [&](const parser::Statement<parser::ModuleStmt> &stmt) { 1264 unitKind = "Module"; 1265 name = toStringRef(stmt.statement.v.source); 1266 header = toStringRef(stmt.source); 1267 }, 1268 [&](const parser::Statement<parser::SubmoduleStmt> &stmt) { 1269 unitKind = "Submodule"; 1270 name = toStringRef(std::get<parser::Name>(stmt.statement.t).source); 1271 header = toStringRef(stmt.source); 1272 }, 1273 [&](const auto &) { 1274 llvm_unreachable("not a valid module begin stmt"); 1275 }, 1276 }); 1277 outputStream << unitKind << ' ' << name << ": " << header << '\n'; 1278 dumpEvaluationList(outputStream, moduleLikeUnit.evaluationList); 1279 outputStream << "Contains\n"; 1280 for (const lower::pft::FunctionLikeUnit &func : 1281 moduleLikeUnit.nestedFunctions) 1282 dumpFunctionLikeUnit(outputStream, func); 1283 outputStream << "End Contains\nEnd " << unitKind << ' ' << name << "\n\n"; 1284 } 1285 1286 // Top level directives 1287 void dumpCompilerDirectiveUnit( 1288 llvm::raw_ostream &outputStream, 1289 const lower::pft::CompilerDirectiveUnit &directive) { 1290 outputStream << getNodeIndex(directive) << " "; 1291 outputStream << "CompilerDirective: !"; 1292 outputStream << directive.get<Fortran::parser::CompilerDirective>() 1293 .source.ToString(); 1294 outputStream << "\nEnd CompilerDirective\n\n"; 1295 } 1296 1297 void 1298 dumpOpenACCDirectiveUnit(llvm::raw_ostream &outputStream, 1299 const lower::pft::OpenACCDirectiveUnit &directive) { 1300 outputStream << getNodeIndex(directive) << " "; 1301 outputStream << "OpenACCDirective: !$acc "; 1302 outputStream << directive.get<Fortran::parser::OpenACCRoutineConstruct>() 1303 .source.ToString(); 1304 outputStream << "\nEnd OpenACCDirective\n\n"; 1305 } 1306 1307 template <typename T> 1308 std::size_t getNodeIndex(const T &node) { 1309 auto addr = static_cast<const void *>(&node); 1310 auto it = nodeIndexes.find(addr); 1311 if (it != nodeIndexes.end()) 1312 return it->second; 1313 nodeIndexes.try_emplace(addr, nextIndex); 1314 return nextIndex++; 1315 } 1316 std::size_t getNodeIndex(const lower::pft::Program &) { return 0; } 1317 1318 private: 1319 llvm::DenseMap<const void *, std::size_t> nodeIndexes; 1320 std::size_t nextIndex{1}; // 0 is the root 1321 }; 1322 1323 } // namespace 1324 1325 template <typename A, typename T> 1326 static lower::pft::FunctionLikeUnit::FunctionStatement 1327 getFunctionStmt(const T &func) { 1328 lower::pft::FunctionLikeUnit::FunctionStatement result{ 1329 std::get<parser::Statement<A>>(func.t)}; 1330 return result; 1331 } 1332 1333 template <typename A, typename T> 1334 static lower::pft::ModuleLikeUnit::ModuleStatement getModuleStmt(const T &mod) { 1335 lower::pft::ModuleLikeUnit::ModuleStatement result{ 1336 std::get<parser::Statement<A>>(mod.t)}; 1337 return result; 1338 } 1339 1340 template <typename A> 1341 static const semantics::Symbol *getSymbol(A &beginStmt) { 1342 const auto *symbol = beginStmt.visit(common::visitors{ 1343 [](const parser::Statement<parser::ProgramStmt> &stmt) 1344 -> const semantics::Symbol * { return stmt.statement.v.symbol; }, 1345 [](const parser::Statement<parser::FunctionStmt> &stmt) 1346 -> const semantics::Symbol * { 1347 return std::get<parser::Name>(stmt.statement.t).symbol; 1348 }, 1349 [](const parser::Statement<parser::SubroutineStmt> &stmt) 1350 -> const semantics::Symbol * { 1351 return std::get<parser::Name>(stmt.statement.t).symbol; 1352 }, 1353 [](const parser::Statement<parser::MpSubprogramStmt> &stmt) 1354 -> const semantics::Symbol * { return stmt.statement.v.symbol; }, 1355 [](const parser::Statement<parser::ModuleStmt> &stmt) 1356 -> const semantics::Symbol * { return stmt.statement.v.symbol; }, 1357 [](const parser::Statement<parser::SubmoduleStmt> &stmt) 1358 -> const semantics::Symbol * { 1359 return std::get<parser::Name>(stmt.statement.t).symbol; 1360 }, 1361 [](const auto &) -> const semantics::Symbol * { 1362 llvm_unreachable("unknown FunctionLike or ModuleLike beginStmt"); 1363 return nullptr; 1364 }}); 1365 assert(symbol && "parser::Name must have resolved symbol"); 1366 return symbol; 1367 } 1368 1369 bool Fortran::lower::pft::Evaluation::lowerAsStructured() const { 1370 return !lowerAsUnstructured(); 1371 } 1372 1373 bool Fortran::lower::pft::Evaluation::lowerAsUnstructured() const { 1374 return isUnstructured || clDisableStructuredFir; 1375 } 1376 1377 bool Fortran::lower::pft::Evaluation::forceAsUnstructured() const { 1378 return clDisableStructuredFir; 1379 } 1380 1381 lower::pft::FunctionLikeUnit * 1382 Fortran::lower::pft::Evaluation::getOwningProcedure() const { 1383 return parent.visit(common::visitors{ 1384 [](lower::pft::FunctionLikeUnit &c) { return &c; }, 1385 [&](lower::pft::Evaluation &c) { return c.getOwningProcedure(); }, 1386 [](auto &) -> lower::pft::FunctionLikeUnit * { return nullptr; }, 1387 }); 1388 } 1389 1390 bool Fortran::lower::definedInCommonBlock(const semantics::Symbol &sym) { 1391 return semantics::FindCommonBlockContaining(sym); 1392 } 1393 1394 /// Is the symbol `sym` a global? 1395 bool Fortran::lower::symbolIsGlobal(const semantics::Symbol &sym) { 1396 return semantics::IsSaved(sym) || lower::definedInCommonBlock(sym) || 1397 semantics::IsNamedConstant(sym); 1398 } 1399 1400 namespace { 1401 /// This helper class sorts the symbols in a scope such that a symbol will 1402 /// be placed after those it depends upon. Otherwise the sort is stable and 1403 /// preserves the order of the symbol table, which is sorted by name. This 1404 /// analysis may also be done for an individual symbol. 1405 struct SymbolDependenceAnalysis { 1406 explicit SymbolDependenceAnalysis(const semantics::Scope &scope) { 1407 analyzeEquivalenceSets(scope); 1408 for (const auto &iter : scope) 1409 analyze(iter.second.get()); 1410 finalize(); 1411 } 1412 explicit SymbolDependenceAnalysis(const semantics::Symbol &symbol) { 1413 analyzeEquivalenceSets(symbol.owner()); 1414 analyze(symbol); 1415 finalize(); 1416 } 1417 Fortran::lower::pft::VariableList getVariableList() { 1418 return std::move(layeredVarList[0]); 1419 } 1420 1421 private: 1422 /// Analyze the equivalence sets defined in \p scope, plus the equivalence 1423 /// sets in host module, submodule, and procedure scopes that may define 1424 /// symbols referenced in \p scope. This analysis excludes equivalence sets 1425 /// involving common blocks, which are handled elsewhere. 1426 void analyzeEquivalenceSets(const semantics::Scope &scope) { 1427 // FIXME: When this function is called on the scope of an internal 1428 // procedure whose parent contains an EQUIVALENCE set and the internal 1429 // procedure uses variables from that EQUIVALENCE set, we end up creating 1430 // an AggregateStore for those variables unnecessarily. 1431 1432 // A function defined in a [sub]module has no explicit USE of its ancestor 1433 // [sub]modules. Analyze those scopes here to accommodate references to 1434 // symbols in them. 1435 for (auto *scp = &scope.parent(); !scp->IsGlobal(); scp = &scp->parent()) 1436 if (scp->kind() == Fortran::semantics::Scope::Kind::Module) 1437 analyzeLocalEquivalenceSets(*scp); 1438 // Analyze local, USEd, and host procedure scope equivalences. 1439 for (const auto &iter : scope) { 1440 const semantics::Symbol &ultimate = iter.second.get().GetUltimate(); 1441 if (!skipSymbol(ultimate)) 1442 analyzeLocalEquivalenceSets(ultimate.owner()); 1443 } 1444 // Add all aggregate stores to the front of the variable list. 1445 adjustSize(1); 1446 // The copy in the loop matters, 'stores' will still be used. 1447 for (auto st : stores) 1448 layeredVarList[0].emplace_back(std::move(st)); 1449 } 1450 1451 /// Analyze the equivalence sets defined locally in \p scope that don't 1452 /// involve common blocks. 1453 void analyzeLocalEquivalenceSets(const semantics::Scope &scope) { 1454 if (scope.equivalenceSets().empty()) 1455 return; // no equivalence sets to analyze 1456 if (analyzedScopes.contains(&scope)) 1457 return; // equivalence sets already analyzed 1458 1459 analyzedScopes.insert(&scope); 1460 std::list<std::list<semantics::SymbolRef>> aggregates = 1461 Fortran::semantics::GetStorageAssociations(scope); 1462 for (std::list<semantics::SymbolRef> aggregate : aggregates) { 1463 const Fortran::semantics::Symbol *aggregateSym = nullptr; 1464 bool isGlobal = false; 1465 const semantics::Symbol &first = *aggregate.front(); 1466 // Exclude equivalence sets involving common blocks. 1467 // Those are handled in instantiateCommon. 1468 if (lower::definedInCommonBlock(first)) 1469 continue; 1470 std::size_t start = first.offset(); 1471 std::size_t end = first.offset() + first.size(); 1472 const Fortran::semantics::Symbol *namingSym = nullptr; 1473 for (semantics::SymbolRef symRef : aggregate) { 1474 const semantics::Symbol &sym = *symRef; 1475 aliasSyms.insert(&sym); 1476 if (sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated)) { 1477 aggregateSym = &sym; 1478 } else { 1479 isGlobal |= lower::symbolIsGlobal(sym); 1480 start = std::min(sym.offset(), start); 1481 end = std::max(sym.offset() + sym.size(), end); 1482 if (!namingSym || (sym.name() < namingSym->name())) 1483 namingSym = &sym; 1484 } 1485 } 1486 assert(namingSym && "must contain at least one user symbol"); 1487 if (!aggregateSym) { 1488 stores.emplace_back( 1489 Fortran::lower::pft::Variable::Interval{start, end - start}, 1490 *namingSym, isGlobal); 1491 } else { 1492 stores.emplace_back(*aggregateSym, *namingSym, isGlobal); 1493 } 1494 } 1495 } 1496 1497 // Recursively visit each symbol to determine the height of its dependence on 1498 // other symbols. 1499 int analyze(const semantics::Symbol &sym) { 1500 auto done = seen.insert(&sym); 1501 if (!done.second) 1502 return 0; 1503 LLVM_DEBUG(llvm::dbgs() << "analyze symbol " << &sym << " in <" 1504 << &sym.owner() << ">: " << sym << '\n'); 1505 const bool isProcedurePointerOrDummy = 1506 semantics::IsProcedurePointer(sym) || 1507 (semantics::IsProcedure(sym) && IsDummy(sym)); 1508 // A procedure argument in a subprogram with multiple entry points might 1509 // need a layeredVarList entry to trigger creation of a symbol map entry 1510 // in some cases. Non-dummy procedures don't. 1511 if (semantics::IsProcedure(sym) && !isProcedurePointerOrDummy) 1512 return 0; 1513 // Derived type component symbols may be collected by "CollectSymbols" 1514 // below when processing something like "real :: x(derived%component)". The 1515 // symbol "component" has "ObjectEntityDetails", but it should not be 1516 // instantiated: it is part of "derived" that should be the only one to 1517 // be instantiated. 1518 if (sym.owner().IsDerivedType()) 1519 return 0; 1520 1521 semantics::Symbol ultimate = sym.GetUltimate(); 1522 if (const auto *details = 1523 ultimate.detailsIf<semantics::NamelistDetails>()) { 1524 // handle namelist group symbols 1525 for (const semantics::SymbolRef &s : details->objects()) 1526 analyze(s); 1527 return 0; 1528 } 1529 if (!ultimate.has<semantics::ObjectEntityDetails>() && 1530 !isProcedurePointerOrDummy) 1531 return 0; 1532 1533 if (sym.has<semantics::DerivedTypeDetails>()) 1534 llvm_unreachable("not yet implemented - derived type analysis"); 1535 1536 // Symbol must be something lowering will have to allocate. 1537 int depth = 0; 1538 // Analyze symbols appearing in object entity specification expressions. 1539 // This ensures these symbols will be instantiated before the current one. 1540 // This is not done for object entities that are host associated because 1541 // they must be instantiated from the value of the host symbols. 1542 // (The specification expressions should not be re-evaluated.) 1543 if (const auto *details = sym.detailsIf<semantics::ObjectEntityDetails>()) { 1544 const semantics::DeclTypeSpec *symTy = sym.GetType(); 1545 assert(symTy && "symbol must have a type"); 1546 // check CHARACTER's length 1547 if (symTy->category() == semantics::DeclTypeSpec::Character) 1548 if (auto e = symTy->characterTypeSpec().length().GetExplicit()) 1549 for (const auto &s : evaluate::CollectSymbols(*e)) 1550 depth = std::max(analyze(s) + 1, depth); 1551 1552 auto doExplicit = [&](const auto &bound) { 1553 if (bound.isExplicit()) { 1554 semantics::SomeExpr e{*bound.GetExplicit()}; 1555 for (const auto &s : evaluate::CollectSymbols(e)) 1556 depth = std::max(analyze(s) + 1, depth); 1557 } 1558 }; 1559 // Handle any symbols in array bound declarations. 1560 for (const semantics::ShapeSpec &subs : details->shape()) { 1561 doExplicit(subs.lbound()); 1562 doExplicit(subs.ubound()); 1563 } 1564 // Handle any symbols in coarray bound declarations. 1565 for (const semantics::ShapeSpec &subs : details->coshape()) { 1566 doExplicit(subs.lbound()); 1567 doExplicit(subs.ubound()); 1568 } 1569 // Handle any symbols in initialization expressions. 1570 if (auto e = details->init()) 1571 for (const auto &s : evaluate::CollectSymbols(*e)) 1572 if (!s->has<semantics::DerivedTypeDetails>()) 1573 depth = std::max(analyze(s) + 1, depth); 1574 } 1575 adjustSize(depth + 1); 1576 bool global = lower::symbolIsGlobal(sym); 1577 layeredVarList[depth].emplace_back(sym, global, depth); 1578 if (semantics::IsAllocatable(sym)) 1579 layeredVarList[depth].back().setHeapAlloc(); 1580 if (semantics::IsPointer(sym)) 1581 layeredVarList[depth].back().setPointer(); 1582 if (ultimate.attrs().test(semantics::Attr::TARGET)) 1583 layeredVarList[depth].back().setTarget(); 1584 1585 // If there are alias sets, then link the participating variables to their 1586 // aggregate stores when constructing the new variable on the list. 1587 if (lower::pft::Variable::AggregateStore *store = findStoreIfAlias(sym)) 1588 layeredVarList[depth].back().setAlias(store->getOffset()); 1589 return depth; 1590 } 1591 1592 /// Skip symbol in alias analysis. 1593 bool skipSymbol(const semantics::Symbol &sym) { 1594 // Common block equivalences are largely managed by the front end. 1595 // Compiler generated symbols ('.' names) cannot be equivalenced. 1596 // FIXME: Equivalence code generation may need to be revisited. 1597 return !sym.has<semantics::ObjectEntityDetails>() || 1598 lower::definedInCommonBlock(sym) || sym.name()[0] == '.'; 1599 } 1600 1601 // Make sure the table is of appropriate size. 1602 void adjustSize(std::size_t size) { 1603 if (layeredVarList.size() < size) 1604 layeredVarList.resize(size); 1605 } 1606 1607 Fortran::lower::pft::Variable::AggregateStore * 1608 findStoreIfAlias(const Fortran::evaluate::Symbol &sym) { 1609 const semantics::Symbol &ultimate = sym.GetUltimate(); 1610 const semantics::Scope &scope = ultimate.owner(); 1611 // Expect the total number of EQUIVALENCE sets to be small for a typical 1612 // Fortran program. 1613 if (aliasSyms.contains(&ultimate)) { 1614 LLVM_DEBUG(llvm::dbgs() << "found aggregate containing " << &ultimate 1615 << " " << ultimate.name() << " in <" << &scope 1616 << "> " << scope.GetName() << '\n'); 1617 std::size_t off = ultimate.offset(); 1618 std::size_t symSize = ultimate.size(); 1619 for (lower::pft::Variable::AggregateStore &v : stores) { 1620 if (&v.getOwningScope() == &scope) { 1621 auto intervalOff = std::get<0>(v.interval); 1622 auto intervalSize = std::get<1>(v.interval); 1623 if (off >= intervalOff && off < intervalOff + intervalSize) 1624 return &v; 1625 // Zero sized symbol in zero sized equivalence. 1626 if (off == intervalOff && symSize == 0) 1627 return &v; 1628 } 1629 } 1630 // clang-format off 1631 LLVM_DEBUG( 1632 llvm::dbgs() << "looking for " << off << "\n{\n"; 1633 for (lower::pft::Variable::AggregateStore &v : stores) { 1634 llvm::dbgs() << " in scope: " << &v.getOwningScope() << "\n"; 1635 llvm::dbgs() << " i = [" << std::get<0>(v.interval) << ".." 1636 << std::get<0>(v.interval) + std::get<1>(v.interval) 1637 << "]\n"; 1638 } 1639 llvm::dbgs() << "}\n"); 1640 // clang-format on 1641 llvm_unreachable("the store must be present"); 1642 } 1643 return nullptr; 1644 } 1645 1646 /// Flatten the result VariableList. 1647 void finalize() { 1648 for (int i = 1, end = layeredVarList.size(); i < end; ++i) 1649 layeredVarList[0].insert(layeredVarList[0].end(), 1650 layeredVarList[i].begin(), 1651 layeredVarList[i].end()); 1652 } 1653 1654 llvm::SmallSet<const semantics::Symbol *, 32> seen; 1655 std::vector<Fortran::lower::pft::VariableList> layeredVarList; 1656 llvm::SmallSet<const semantics::Symbol *, 32> aliasSyms; 1657 /// Set of scopes that have been analyzed for aliases. 1658 llvm::SmallSet<const semantics::Scope *, 4> analyzedScopes; 1659 std::vector<Fortran::lower::pft::Variable::AggregateStore> stores; 1660 }; 1661 } // namespace 1662 1663 //===----------------------------------------------------------------------===// 1664 // FunctionLikeUnit implementation 1665 //===----------------------------------------------------------------------===// 1666 1667 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit( 1668 const parser::MainProgram &func, const lower::pft::PftNode &parent, 1669 const semantics::SemanticsContext &semanticsContext) 1670 : ProgramUnit{func, parent}, endStmt{ 1671 getFunctionStmt<parser::EndProgramStmt>( 1672 func)} { 1673 const auto &programStmt = 1674 std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(func.t); 1675 if (programStmt.has_value()) { 1676 beginStmt = FunctionStatement(programStmt.value()); 1677 const semantics::Symbol *symbol = getSymbol(*beginStmt); 1678 entryPointList[0].first = symbol; 1679 scope = symbol->scope(); 1680 } else { 1681 scope = &semanticsContext.FindScope( 1682 std::get<parser::Statement<parser::EndProgramStmt>>(func.t).source); 1683 } 1684 } 1685 1686 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit( 1687 const parser::FunctionSubprogram &func, const lower::pft::PftNode &parent, 1688 const semantics::SemanticsContext &) 1689 : ProgramUnit{func, parent}, 1690 beginStmt{getFunctionStmt<parser::FunctionStmt>(func)}, 1691 endStmt{getFunctionStmt<parser::EndFunctionStmt>(func)} { 1692 const semantics::Symbol *symbol = getSymbol(*beginStmt); 1693 entryPointList[0].first = symbol; 1694 scope = symbol->scope(); 1695 } 1696 1697 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit( 1698 const parser::SubroutineSubprogram &func, const lower::pft::PftNode &parent, 1699 const semantics::SemanticsContext &) 1700 : ProgramUnit{func, parent}, 1701 beginStmt{getFunctionStmt<parser::SubroutineStmt>(func)}, 1702 endStmt{getFunctionStmt<parser::EndSubroutineStmt>(func)} { 1703 const semantics::Symbol *symbol = getSymbol(*beginStmt); 1704 entryPointList[0].first = symbol; 1705 scope = symbol->scope(); 1706 } 1707 1708 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit( 1709 const parser::SeparateModuleSubprogram &func, 1710 const lower::pft::PftNode &parent, const semantics::SemanticsContext &) 1711 : ProgramUnit{func, parent}, 1712 beginStmt{getFunctionStmt<parser::MpSubprogramStmt>(func)}, 1713 endStmt{getFunctionStmt<parser::EndMpSubprogramStmt>(func)} { 1714 const semantics::Symbol *symbol = getSymbol(*beginStmt); 1715 entryPointList[0].first = symbol; 1716 scope = symbol->scope(); 1717 } 1718 1719 Fortran::lower::HostAssociations & 1720 Fortran::lower::pft::FunctionLikeUnit::parentHostAssoc() { 1721 if (auto *par = parent.getIf<FunctionLikeUnit>()) 1722 return par->hostAssociations; 1723 llvm::report_fatal_error("parent is not a function"); 1724 } 1725 1726 bool Fortran::lower::pft::FunctionLikeUnit::parentHasTupleHostAssoc() { 1727 if (auto *par = parent.getIf<FunctionLikeUnit>()) 1728 return par->hostAssociations.hasTupleAssociations(); 1729 return false; 1730 } 1731 1732 bool Fortran::lower::pft::FunctionLikeUnit::parentHasHostAssoc() { 1733 if (auto *par = parent.getIf<FunctionLikeUnit>()) 1734 return !par->hostAssociations.empty(); 1735 return false; 1736 } 1737 1738 parser::CharBlock 1739 Fortran::lower::pft::FunctionLikeUnit::getStartingSourceLoc() const { 1740 if (beginStmt) 1741 return stmtSourceLoc(*beginStmt); 1742 return scope->sourceRange(); 1743 } 1744 1745 //===----------------------------------------------------------------------===// 1746 // ModuleLikeUnit implementation 1747 //===----------------------------------------------------------------------===// 1748 1749 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit( 1750 const parser::Module &m, const lower::pft::PftNode &parent) 1751 : ProgramUnit{m, parent}, beginStmt{getModuleStmt<parser::ModuleStmt>(m)}, 1752 endStmt{getModuleStmt<parser::EndModuleStmt>(m)} {} 1753 1754 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit( 1755 const parser::Submodule &m, const lower::pft::PftNode &parent) 1756 : ProgramUnit{m, parent}, beginStmt{getModuleStmt<parser::SubmoduleStmt>( 1757 m)}, 1758 endStmt{getModuleStmt<parser::EndSubmoduleStmt>(m)} {} 1759 1760 parser::CharBlock 1761 Fortran::lower::pft::ModuleLikeUnit::getStartingSourceLoc() const { 1762 return stmtSourceLoc(beginStmt); 1763 } 1764 const Fortran::semantics::Scope & 1765 Fortran::lower::pft::ModuleLikeUnit::getScope() const { 1766 const Fortran::semantics::Symbol *symbol = getSymbol(beginStmt); 1767 assert(symbol && symbol->scope() && 1768 "Module statement must have a symbol with a scope"); 1769 return *symbol->scope(); 1770 } 1771 1772 //===----------------------------------------------------------------------===// 1773 // BlockDataUnit implementation 1774 //===----------------------------------------------------------------------===// 1775 1776 Fortran::lower::pft::BlockDataUnit::BlockDataUnit( 1777 const parser::BlockData &bd, const lower::pft::PftNode &parent, 1778 const semantics::SemanticsContext &semanticsContext) 1779 : ProgramUnit{bd, parent}, 1780 symTab{semanticsContext.FindScope( 1781 std::get<parser::Statement<parser::EndBlockDataStmt>>(bd.t).source)} { 1782 } 1783 1784 std::unique_ptr<lower::pft::Program> 1785 Fortran::lower::createPFT(const parser::Program &root, 1786 const semantics::SemanticsContext &semanticsContext) { 1787 PFTBuilder walker(semanticsContext); 1788 Walk(root, walker); 1789 return walker.result(); 1790 } 1791 1792 void Fortran::lower::dumpPFT(llvm::raw_ostream &outputStream, 1793 const lower::pft::Program &pft) { 1794 PFTDumper{}.dumpPFT(outputStream, pft); 1795 } 1796 1797 void Fortran::lower::pft::Program::dump() const { 1798 dumpPFT(llvm::errs(), *this); 1799 } 1800 1801 void Fortran::lower::pft::Evaluation::dump() const { 1802 PFTDumper{}.dumpEvaluation(llvm::errs(), *this); 1803 } 1804 1805 void Fortran::lower::pft::Variable::dump() const { 1806 if (auto *s = std::get_if<Nominal>(&var)) { 1807 llvm::errs() << s->symbol << " " << *s->symbol; 1808 llvm::errs() << " (depth: " << s->depth << ')'; 1809 if (s->global) 1810 llvm::errs() << ", global"; 1811 if (s->heapAlloc) 1812 llvm::errs() << ", allocatable"; 1813 if (s->pointer) 1814 llvm::errs() << ", pointer"; 1815 if (s->target) 1816 llvm::errs() << ", target"; 1817 if (s->aliaser) 1818 llvm::errs() << ", equivalence(" << s->aliasOffset << ')'; 1819 } else if (auto *s = std::get_if<AggregateStore>(&var)) { 1820 llvm::errs() << "interval[" << std::get<0>(s->interval) << ", " 1821 << std::get<1>(s->interval) << "]:"; 1822 llvm::errs() << " name: " << toStringRef(s->getNamingSymbol().name()); 1823 if (s->isGlobal()) 1824 llvm::errs() << ", global"; 1825 if (s->initialValueSymbol) 1826 llvm::errs() << ", initial value: {" << *s->initialValueSymbol << "}"; 1827 } else { 1828 llvm_unreachable("not a Variable"); 1829 } 1830 llvm::errs() << '\n'; 1831 } 1832 1833 void Fortran::lower::pft::dump(Fortran::lower::pft::VariableList &variableList, 1834 std::string s) { 1835 llvm::errs() << (s.empty() ? "VariableList" : s) << " " << &variableList 1836 << " size=" << variableList.size() << "\n"; 1837 for (auto var : variableList) { 1838 llvm::errs() << " "; 1839 var.dump(); 1840 } 1841 } 1842 1843 void Fortran::lower::pft::FunctionLikeUnit::dump() const { 1844 PFTDumper{}.dumpFunctionLikeUnit(llvm::errs(), *this); 1845 } 1846 1847 void Fortran::lower::pft::ModuleLikeUnit::dump() const { 1848 PFTDumper{}.dumpModuleLikeUnit(llvm::errs(), *this); 1849 } 1850 1851 /// The BlockDataUnit dump is just the associated symbol table. 1852 void Fortran::lower::pft::BlockDataUnit::dump() const { 1853 llvm::errs() << "block data {\n" << symTab << "\n}\n"; 1854 } 1855 1856 /// Find or create an ordered list of equivalences and variables in \p scope. 1857 /// The result is cached in \p map. 1858 const lower::pft::VariableList & 1859 lower::pft::getScopeVariableList(const semantics::Scope &scope, 1860 ScopeVariableListMap &map) { 1861 LLVM_DEBUG(llvm::dbgs() << "\ngetScopeVariableList of [sub]module scope <" 1862 << &scope << "> " << scope.GetName() << "\n"); 1863 auto iter = map.find(&scope); 1864 if (iter == map.end()) { 1865 SymbolDependenceAnalysis sda(scope); 1866 map.emplace(&scope, sda.getVariableList()); 1867 iter = map.find(&scope); 1868 } 1869 return iter->second; 1870 } 1871 1872 /// Create an ordered list of equivalences and variables in \p scope. 1873 /// The result is not cached. 1874 lower::pft::VariableList 1875 lower::pft::getScopeVariableList(const semantics::Scope &scope) { 1876 LLVM_DEBUG( 1877 llvm::dbgs() << "\ngetScopeVariableList of [sub]program|block scope <" 1878 << &scope << "> " << scope.GetName() << "\n"); 1879 SymbolDependenceAnalysis sda(scope); 1880 return sda.getVariableList(); 1881 } 1882 1883 /// Create an ordered list of equivalences and variables that \p symbol 1884 /// depends on (no caching). Include \p symbol at the end of the list. 1885 lower::pft::VariableList 1886 lower::pft::getDependentVariableList(const semantics::Symbol &symbol) { 1887 LLVM_DEBUG(llvm::dbgs() << "\ngetDependentVariableList of " << &symbol 1888 << " - " << symbol << "\n"); 1889 SymbolDependenceAnalysis sda(symbol); 1890 return sda.getVariableList(); 1891 } 1892 1893 namespace { 1894 /// Helper class to find all the symbols referenced in a FunctionLikeUnit. 1895 /// It defines a parse tree visitor doing a deep visit in all nodes with 1896 /// symbols (including evaluate::Expr). 1897 struct SymbolVisitor { 1898 template <typename A> 1899 bool Pre(const A &x) { 1900 if constexpr (Fortran::parser::HasTypedExpr<A>::value) 1901 // Some parse tree Expr may legitimately be un-analyzed after semantics 1902 // (for instance PDT component initial value in the PDT definition body). 1903 if (const auto *expr = Fortran::semantics::GetExpr(nullptr, x)) 1904 visitExpr(*expr); 1905 return true; 1906 } 1907 1908 bool Pre(const Fortran::parser::Name &name) { 1909 if (const semantics::Symbol *symbol = name.symbol) 1910 visitSymbol(*symbol); 1911 return false; 1912 } 1913 1914 template <typename T> 1915 void visitExpr(const Fortran::evaluate::Expr<T> &expr) { 1916 for (const semantics::Symbol &symbol : 1917 Fortran::evaluate::CollectSymbols(expr)) 1918 visitSymbol(symbol); 1919 } 1920 1921 void visitSymbol(const Fortran::semantics::Symbol &symbol) { 1922 callBack(symbol); 1923 // - Visit statement function body since it will be inlined in lowering. 1924 // - Visit function results specification expressions because allocations 1925 // happens on the caller side. 1926 if (const auto *subprogramDetails = 1927 symbol.detailsIf<Fortran::semantics::SubprogramDetails>()) { 1928 if (const auto &maybeExpr = subprogramDetails->stmtFunction()) { 1929 visitExpr(*maybeExpr); 1930 } else { 1931 if (subprogramDetails->isFunction()) { 1932 // Visit result extents expressions that are explicit. 1933 const Fortran::semantics::Symbol &result = 1934 subprogramDetails->result(); 1935 if (const auto *objectDetails = 1936 result.detailsIf<Fortran::semantics::ObjectEntityDetails>()) 1937 if (objectDetails->shape().IsExplicitShape()) 1938 for (const Fortran::semantics::ShapeSpec &shapeSpec : 1939 objectDetails->shape()) { 1940 visitExpr(shapeSpec.lbound().GetExplicit().value()); 1941 visitExpr(shapeSpec.ubound().GetExplicit().value()); 1942 } 1943 } 1944 } 1945 } 1946 if (Fortran::semantics::IsProcedure(symbol)) { 1947 if (auto dynamicType = Fortran::evaluate::DynamicType::From(symbol)) { 1948 // Visit result length specification expressions that are explicit. 1949 if (dynamicType->category() == 1950 Fortran::common::TypeCategory::Character) { 1951 if (std::optional<Fortran::evaluate::ExtentExpr> length = 1952 dynamicType->GetCharLength()) 1953 visitExpr(*length); 1954 } else if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec = 1955 Fortran::evaluate::GetDerivedTypeSpec(dynamicType)) { 1956 for (const auto &[_, param] : derivedTypeSpec->parameters()) 1957 if (const Fortran::semantics::MaybeIntExpr &expr = 1958 param.GetExplicit()) 1959 visitExpr(expr.value()); 1960 } 1961 } 1962 } 1963 } 1964 1965 template <typename A> 1966 constexpr void Post(const A &) {} 1967 1968 const std::function<void(const Fortran::semantics::Symbol &)> &callBack; 1969 }; 1970 } // namespace 1971 1972 void Fortran::lower::pft::visitAllSymbols( 1973 const Fortran::lower::pft::FunctionLikeUnit &funit, 1974 const std::function<void(const Fortran::semantics::Symbol &)> callBack) { 1975 SymbolVisitor visitor{callBack}; 1976 funit.visit([&](const auto &functionParserNode) { 1977 parser::Walk(functionParserNode, visitor); 1978 }); 1979 } 1980 1981 void Fortran::lower::pft::visitAllSymbols( 1982 const Fortran::lower::pft::Evaluation &eval, 1983 const std::function<void(const Fortran::semantics::Symbol &)> callBack) { 1984 SymbolVisitor visitor{callBack}; 1985 eval.visit([&](const auto &functionParserNode) { 1986 parser::Walk(functionParserNode, visitor); 1987 }); 1988 } 1989