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