xref: /llvm-project/flang/lib/Lower/PFTBuilder.cpp (revision 3f55311a0afff6278571922e1c23bf5c71dd2d0b)
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       LLVM_DEBUG(llvm::dbgs() << "[anonymous]\n");
1063     }
1064   }
1065   for (const auto &scp : scope->children())
1066     if (!scp.symbol())
1067       dumpScope(&scp, depth + 1);
1068   for (auto iter = scope->begin(); iter != scope->end(); ++iter) {
1069     common::Reference<semantics::Symbol> sym = iter->second;
1070     if (auto scp = sym->scope())
1071       dumpScope(scp, depth + 1);
1072     else
1073       LLVM_DEBUG(llvm::dbgs() << w + "  " << &*sym << "   " << *sym << "\n");
1074   }
1075 }
1076 #endif // NDEBUG
1077 
1078 class PFTDumper {
1079 public:
1080   void dumpPFT(llvm::raw_ostream &outputStream,
1081                const lower::pft::Program &pft) {
1082     for (auto &unit : pft.getUnits()) {
1083       std::visit(common::visitors{
1084                      [&](const lower::pft::BlockDataUnit &unit) {
1085                        outputStream << getNodeIndex(unit) << " ";
1086                        outputStream << "BlockData: ";
1087                        outputStream << "\nEnd BlockData\n\n";
1088                      },
1089                      [&](const lower::pft::FunctionLikeUnit &func) {
1090                        dumpFunctionLikeUnit(outputStream, func);
1091                      },
1092                      [&](const lower::pft::ModuleLikeUnit &unit) {
1093                        dumpModuleLikeUnit(outputStream, unit);
1094                      },
1095                      [&](const lower::pft::CompilerDirectiveUnit &unit) {
1096                        dumpCompilerDirectiveUnit(outputStream, unit);
1097                      },
1098                  },
1099                  unit);
1100     }
1101   }
1102 
1103   llvm::StringRef evaluationName(const lower::pft::Evaluation &eval) {
1104     return eval.visit([](const auto &parseTreeNode) {
1105       return parser::ParseTreeDumper::GetNodeName(parseTreeNode);
1106     });
1107   }
1108 
1109   void dumpEvaluation(llvm::raw_ostream &outputStream,
1110                       const lower::pft::Evaluation &eval,
1111                       const std::string &indentString, int indent = 1) {
1112     llvm::StringRef name = evaluationName(eval);
1113     llvm::StringRef newBlock = eval.isNewBlock ? "^" : "";
1114     llvm::StringRef bang = eval.isUnstructured ? "!" : "";
1115     outputStream << indentString;
1116     if (eval.printIndex)
1117       outputStream << eval.printIndex << ' ';
1118     if (eval.hasNestedEvaluations())
1119       outputStream << "<<" << newBlock << name << bang << ">>";
1120     else
1121       outputStream << newBlock << name << bang;
1122     if (eval.negateCondition)
1123       outputStream << " [negate]";
1124     if (eval.constructExit)
1125       outputStream << " -> " << eval.constructExit->printIndex;
1126     else if (eval.controlSuccessor)
1127       outputStream << " -> " << eval.controlSuccessor->printIndex;
1128     else if (eval.isA<parser::EntryStmt>() && eval.lexicalSuccessor)
1129       outputStream << " -> " << eval.lexicalSuccessor->printIndex;
1130     if (!eval.position.empty())
1131       outputStream << ": " << eval.position.ToString();
1132     else if (auto *dir = eval.getIf<Fortran::parser::CompilerDirective>())
1133       outputStream << ": !" << dir->source.ToString();
1134     outputStream << '\n';
1135     if (eval.hasNestedEvaluations()) {
1136       dumpEvaluationList(outputStream, *eval.evaluationList, indent + 1);
1137       outputStream << indentString << "<<End " << name << bang << ">>\n";
1138     }
1139   }
1140 
1141   void dumpEvaluation(llvm::raw_ostream &ostream,
1142                       const lower::pft::Evaluation &eval) {
1143     dumpEvaluation(ostream, eval, "");
1144   }
1145 
1146   void dumpEvaluationList(llvm::raw_ostream &outputStream,
1147                           const lower::pft::EvaluationList &evaluationList,
1148                           int indent = 1) {
1149     static const auto white = "                                      ++"s;
1150     auto indentString = white.substr(0, indent * 2);
1151     for (const lower::pft::Evaluation &eval : evaluationList)
1152       dumpEvaluation(outputStream, eval, indentString, indent);
1153   }
1154 
1155   void
1156   dumpFunctionLikeUnit(llvm::raw_ostream &outputStream,
1157                        const lower::pft::FunctionLikeUnit &functionLikeUnit) {
1158     outputStream << getNodeIndex(functionLikeUnit) << " ";
1159     llvm::StringRef unitKind;
1160     llvm::StringRef name;
1161     llvm::StringRef header;
1162     if (functionLikeUnit.beginStmt) {
1163       functionLikeUnit.beginStmt->visit(common::visitors{
1164           [&](const parser::Statement<parser::ProgramStmt> &stmt) {
1165             unitKind = "Program";
1166             name = toStringRef(stmt.statement.v.source);
1167           },
1168           [&](const parser::Statement<parser::FunctionStmt> &stmt) {
1169             unitKind = "Function";
1170             name = toStringRef(std::get<parser::Name>(stmt.statement.t).source);
1171             header = toStringRef(stmt.source);
1172           },
1173           [&](const parser::Statement<parser::SubroutineStmt> &stmt) {
1174             unitKind = "Subroutine";
1175             name = toStringRef(std::get<parser::Name>(stmt.statement.t).source);
1176             header = toStringRef(stmt.source);
1177           },
1178           [&](const parser::Statement<parser::MpSubprogramStmt> &stmt) {
1179             unitKind = "MpSubprogram";
1180             name = toStringRef(stmt.statement.v.source);
1181             header = toStringRef(stmt.source);
1182           },
1183           [&](const auto &) { llvm_unreachable("not a valid begin stmt"); },
1184       });
1185     } else {
1186       unitKind = "Program";
1187       name = "<anonymous>";
1188     }
1189     outputStream << unitKind << ' ' << name;
1190     if (!header.empty())
1191       outputStream << ": " << header;
1192     outputStream << '\n';
1193     dumpEvaluationList(outputStream, functionLikeUnit.evaluationList);
1194     if (!functionLikeUnit.nestedFunctions.empty()) {
1195       outputStream << "\nContains\n";
1196       for (const lower::pft::FunctionLikeUnit &func :
1197            functionLikeUnit.nestedFunctions)
1198         dumpFunctionLikeUnit(outputStream, func);
1199       outputStream << "End Contains\n";
1200     }
1201     outputStream << "End " << unitKind << ' ' << name << "\n\n";
1202   }
1203 
1204   void dumpModuleLikeUnit(llvm::raw_ostream &outputStream,
1205                           const lower::pft::ModuleLikeUnit &moduleLikeUnit) {
1206     outputStream << getNodeIndex(moduleLikeUnit) << " ";
1207     llvm::StringRef unitKind;
1208     llvm::StringRef name;
1209     llvm::StringRef header;
1210     moduleLikeUnit.beginStmt.visit(common::visitors{
1211         [&](const parser::Statement<parser::ModuleStmt> &stmt) {
1212           unitKind = "Module";
1213           name = toStringRef(stmt.statement.v.source);
1214           header = toStringRef(stmt.source);
1215         },
1216         [&](const parser::Statement<parser::SubmoduleStmt> &stmt) {
1217           unitKind = "Submodule";
1218           name = toStringRef(std::get<parser::Name>(stmt.statement.t).source);
1219           header = toStringRef(stmt.source);
1220         },
1221         [&](const auto &) {
1222           llvm_unreachable("not a valid module begin stmt");
1223         },
1224     });
1225     outputStream << unitKind << ' ' << name << ": " << header << '\n';
1226     dumpEvaluationList(outputStream, moduleLikeUnit.evaluationList);
1227     outputStream << "Contains\n";
1228     for (const lower::pft::FunctionLikeUnit &func :
1229          moduleLikeUnit.nestedFunctions)
1230       dumpFunctionLikeUnit(outputStream, func);
1231     outputStream << "End Contains\nEnd " << unitKind << ' ' << name << "\n\n";
1232   }
1233 
1234   // Top level directives
1235   void dumpCompilerDirectiveUnit(
1236       llvm::raw_ostream &outputStream,
1237       const lower::pft::CompilerDirectiveUnit &directive) {
1238     outputStream << getNodeIndex(directive) << " ";
1239     outputStream << "CompilerDirective: !";
1240     outputStream << directive.get<Fortran::parser::CompilerDirective>()
1241                         .source.ToString();
1242     outputStream << "\nEnd CompilerDirective\n\n";
1243   }
1244 
1245   template <typename T>
1246   std::size_t getNodeIndex(const T &node) {
1247     auto addr = static_cast<const void *>(&node);
1248     auto it = nodeIndexes.find(addr);
1249     if (it != nodeIndexes.end())
1250       return it->second;
1251     nodeIndexes.try_emplace(addr, nextIndex);
1252     return nextIndex++;
1253   }
1254   std::size_t getNodeIndex(const lower::pft::Program &) { return 0; }
1255 
1256 private:
1257   llvm::DenseMap<const void *, std::size_t> nodeIndexes;
1258   std::size_t nextIndex{1}; // 0 is the root
1259 };
1260 
1261 } // namespace
1262 
1263 template <typename A, typename T>
1264 static lower::pft::FunctionLikeUnit::FunctionStatement
1265 getFunctionStmt(const T &func) {
1266   lower::pft::FunctionLikeUnit::FunctionStatement result{
1267       std::get<parser::Statement<A>>(func.t)};
1268   return result;
1269 }
1270 
1271 template <typename A, typename T>
1272 static lower::pft::ModuleLikeUnit::ModuleStatement getModuleStmt(const T &mod) {
1273   lower::pft::ModuleLikeUnit::ModuleStatement result{
1274       std::get<parser::Statement<A>>(mod.t)};
1275   return result;
1276 }
1277 
1278 template <typename A>
1279 static const semantics::Symbol *getSymbol(A &beginStmt) {
1280   const auto *symbol = beginStmt.visit(common::visitors{
1281       [](const parser::Statement<parser::ProgramStmt> &stmt)
1282           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1283       [](const parser::Statement<parser::FunctionStmt> &stmt)
1284           -> const semantics::Symbol * {
1285         return std::get<parser::Name>(stmt.statement.t).symbol;
1286       },
1287       [](const parser::Statement<parser::SubroutineStmt> &stmt)
1288           -> const semantics::Symbol * {
1289         return std::get<parser::Name>(stmt.statement.t).symbol;
1290       },
1291       [](const parser::Statement<parser::MpSubprogramStmt> &stmt)
1292           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1293       [](const parser::Statement<parser::ModuleStmt> &stmt)
1294           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1295       [](const parser::Statement<parser::SubmoduleStmt> &stmt)
1296           -> const semantics::Symbol * {
1297         return std::get<parser::Name>(stmt.statement.t).symbol;
1298       },
1299       [](const auto &) -> const semantics::Symbol * {
1300         llvm_unreachable("unknown FunctionLike or ModuleLike beginStmt");
1301         return nullptr;
1302       }});
1303   assert(symbol && "parser::Name must have resolved symbol");
1304   return symbol;
1305 }
1306 
1307 bool Fortran::lower::pft::Evaluation::lowerAsStructured() const {
1308   return !lowerAsUnstructured();
1309 }
1310 
1311 bool Fortran::lower::pft::Evaluation::lowerAsUnstructured() const {
1312   return isUnstructured || clDisableStructuredFir;
1313 }
1314 
1315 lower::pft::FunctionLikeUnit *
1316 Fortran::lower::pft::Evaluation::getOwningProcedure() const {
1317   return parent.visit(common::visitors{
1318       [](lower::pft::FunctionLikeUnit &c) { return &c; },
1319       [&](lower::pft::Evaluation &c) { return c.getOwningProcedure(); },
1320       [](auto &) -> lower::pft::FunctionLikeUnit * { return nullptr; },
1321   });
1322 }
1323 
1324 bool Fortran::lower::definedInCommonBlock(const semantics::Symbol &sym) {
1325   return semantics::FindCommonBlockContaining(sym);
1326 }
1327 
1328 /// Is the symbol `sym` a global?
1329 bool Fortran::lower::symbolIsGlobal(const semantics::Symbol &sym) {
1330   return semantics::IsSaved(sym) || lower::definedInCommonBlock(sym) ||
1331          semantics::IsNamedConstant(sym);
1332 }
1333 
1334 namespace {
1335 /// This helper class sorts the symbols in a scope such that a symbol will
1336 /// be placed after those it depends upon. Otherwise the sort is stable and
1337 /// preserves the order of the symbol table, which is sorted by name. This
1338 /// analysis may also be done for an individual symbol.
1339 struct SymbolDependenceAnalysis {
1340   explicit SymbolDependenceAnalysis(const semantics::Scope &scope) {
1341     analyzeEquivalenceSets(scope);
1342     for (const auto &iter : scope)
1343       analyze(iter.second.get());
1344     finalize();
1345   }
1346   explicit SymbolDependenceAnalysis(const semantics::Symbol &symbol) {
1347     analyzeEquivalenceSets(symbol.owner());
1348     analyze(symbol);
1349     finalize();
1350   }
1351   Fortran::lower::pft::VariableList getVariableList() {
1352     return std::move(layeredVarList[0]);
1353   }
1354 
1355 private:
1356   /// Analyze the equivalence sets defined in \p scope, plus the equivalence
1357   /// sets in host module, submodule, and procedure scopes that may define
1358   /// symbols referenced in \p scope. This analysis excludes equivalence sets
1359   /// involving common blocks, which are handled elsewhere.
1360   void analyzeEquivalenceSets(const semantics::Scope &scope) {
1361     // FIXME: When this function is called on the scope of an internal
1362     // procedure whose parent contains an EQUIVALENCE set and the internal
1363     // procedure uses variables from that EQUIVALENCE set, we end up creating
1364     // an AggregateStore for those variables unnecessarily.
1365 
1366     // A function defined in a [sub]module has no explicit USE of its ancestor
1367     // [sub]modules. Analyze those scopes here to accommodate references to
1368     // symbols in them.
1369     for (auto *scp = &scope.parent(); !scp->IsGlobal(); scp = &scp->parent())
1370       if (scp->kind() == Fortran::semantics::Scope::Kind::Module)
1371         analyzeLocalEquivalenceSets(*scp);
1372     // Analyze local, USEd, and host procedure scope equivalences.
1373     for (const auto &iter : scope) {
1374       const semantics::Symbol &ultimate = iter.second.get().GetUltimate();
1375       if (!skipSymbol(ultimate))
1376         analyzeLocalEquivalenceSets(ultimate.owner());
1377     }
1378     // Add all aggregate stores to the front of the variable list.
1379     adjustSize(1);
1380     // The copy in the loop matters, 'stores' will still be used.
1381     for (auto st : stores)
1382       layeredVarList[0].emplace_back(std::move(st));
1383   }
1384 
1385   /// Analyze the equivalence sets defined locally in \p scope that don't
1386   /// involve common blocks.
1387   void analyzeLocalEquivalenceSets(const semantics::Scope &scope) {
1388     if (scope.equivalenceSets().empty())
1389       return; // no equivalence sets to analyze
1390     if (analyzedScopes.find(&scope) != analyzedScopes.end())
1391       return; // equivalence sets already analyzed
1392 
1393     analyzedScopes.insert(&scope);
1394     std::list<std::list<semantics::SymbolRef>> aggregates =
1395         Fortran::semantics::GetStorageAssociations(scope);
1396     for (std::list<semantics::SymbolRef> aggregate : aggregates) {
1397       const Fortran::semantics::Symbol *aggregateSym = nullptr;
1398       bool isGlobal = false;
1399       const semantics::Symbol &first = *aggregate.front();
1400       // Exclude equivalence sets involving common blocks.
1401       // Those are handled in instantiateCommon.
1402       if (lower::definedInCommonBlock(first))
1403         continue;
1404       std::size_t start = first.offset();
1405       std::size_t end = first.offset() + first.size();
1406       const Fortran::semantics::Symbol *namingSym = nullptr;
1407       for (semantics::SymbolRef symRef : aggregate) {
1408         const semantics::Symbol &sym = *symRef;
1409         aliasSyms.insert(&sym);
1410         if (sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated)) {
1411           aggregateSym = &sym;
1412         } else {
1413           isGlobal |= lower::symbolIsGlobal(sym);
1414           start = std::min(sym.offset(), start);
1415           end = std::max(sym.offset() + sym.size(), end);
1416           if (!namingSym || (sym.name() < namingSym->name()))
1417             namingSym = &sym;
1418         }
1419       }
1420       assert(namingSym && "must contain at least one user symbol");
1421       if (!aggregateSym) {
1422         stores.emplace_back(
1423             Fortran::lower::pft::Variable::Interval{start, end - start},
1424             *namingSym, isGlobal);
1425       } else {
1426         stores.emplace_back(*aggregateSym, *namingSym, isGlobal);
1427       }
1428     }
1429   }
1430 
1431   // Recursively visit each symbol to determine the height of its dependence on
1432   // other symbols.
1433   int analyze(const semantics::Symbol &sym) {
1434     auto done = seen.insert(&sym);
1435     if (!done.second)
1436       return 0;
1437     LLVM_DEBUG(llvm::dbgs() << "analyze symbol " << &sym << " in <"
1438                             << &sym.owner() << ">: " << sym << '\n');
1439     const bool isProcedurePointerOrDummy =
1440         semantics::IsProcedurePointer(sym) ||
1441         (semantics::IsProcedure(sym) && IsDummy(sym));
1442     // A procedure argument in a subprogram with multiple entry points might
1443     // need a layeredVarList entry to trigger creation of a symbol map entry
1444     // in some cases.  Non-dummy procedures don't.
1445     if (semantics::IsProcedure(sym) && !isProcedurePointerOrDummy)
1446       return 0;
1447     semantics::Symbol ultimate = sym.GetUltimate();
1448     if (const auto *details =
1449             ultimate.detailsIf<semantics::NamelistDetails>()) {
1450       // handle namelist group symbols
1451       for (const semantics::SymbolRef &s : details->objects())
1452         analyze(s);
1453       return 0;
1454     }
1455     if (!ultimate.has<semantics::ObjectEntityDetails>() &&
1456         !isProcedurePointerOrDummy)
1457       return 0;
1458 
1459     if (sym.has<semantics::DerivedTypeDetails>())
1460       llvm_unreachable("not yet implemented - derived type analysis");
1461 
1462     // Symbol must be something lowering will have to allocate.
1463     int depth = 0;
1464     // Analyze symbols appearing in object entity specification expressions.
1465     // This ensures these symbols will be instantiated before the current one.
1466     // This is not done for object entities that are host associated because
1467     // they must be instantiated from the value of the host symbols.
1468     // (The specification expressions should not be re-evaluated.)
1469     if (const auto *details = sym.detailsIf<semantics::ObjectEntityDetails>()) {
1470       const semantics::DeclTypeSpec *symTy = sym.GetType();
1471       assert(symTy && "symbol must have a type");
1472       // check CHARACTER's length
1473       if (symTy->category() == semantics::DeclTypeSpec::Character)
1474         if (auto e = symTy->characterTypeSpec().length().GetExplicit())
1475           for (const auto &s : evaluate::CollectSymbols(*e))
1476             depth = std::max(analyze(s) + 1, depth);
1477 
1478       auto doExplicit = [&](const auto &bound) {
1479         if (bound.isExplicit()) {
1480           semantics::SomeExpr e{*bound.GetExplicit()};
1481           for (const auto &s : evaluate::CollectSymbols(e))
1482             depth = std::max(analyze(s) + 1, depth);
1483         }
1484       };
1485       // Handle any symbols in array bound declarations.
1486       for (const semantics::ShapeSpec &subs : details->shape()) {
1487         doExplicit(subs.lbound());
1488         doExplicit(subs.ubound());
1489       }
1490       // Handle any symbols in coarray bound declarations.
1491       for (const semantics::ShapeSpec &subs : details->coshape()) {
1492         doExplicit(subs.lbound());
1493         doExplicit(subs.ubound());
1494       }
1495       // Handle any symbols in initialization expressions.
1496       if (auto e = details->init())
1497         for (const auto &s : evaluate::CollectSymbols(*e))
1498           depth = std::max(analyze(s) + 1, depth);
1499     }
1500     adjustSize(depth + 1);
1501     bool global = lower::symbolIsGlobal(sym);
1502     layeredVarList[depth].emplace_back(sym, global, depth);
1503     if (semantics::IsAllocatable(sym))
1504       layeredVarList[depth].back().setHeapAlloc();
1505     if (semantics::IsPointer(sym))
1506       layeredVarList[depth].back().setPointer();
1507     if (ultimate.attrs().test(semantics::Attr::TARGET))
1508       layeredVarList[depth].back().setTarget();
1509 
1510     // If there are alias sets, then link the participating variables to their
1511     // aggregate stores when constructing the new variable on the list.
1512     if (lower::pft::Variable::AggregateStore *store = findStoreIfAlias(sym))
1513       layeredVarList[depth].back().setAlias(store->getOffset());
1514     return depth;
1515   }
1516 
1517   /// Skip symbol in alias analysis.
1518   bool skipSymbol(const semantics::Symbol &sym) {
1519     // Common block equivalences are largely managed by the front end.
1520     // Compiler generated symbols ('.' names) cannot be equivalenced.
1521     // FIXME: Equivalence code generation may need to be revisited.
1522     return !sym.has<semantics::ObjectEntityDetails>() ||
1523            lower::definedInCommonBlock(sym) || sym.name()[0] == '.';
1524   }
1525 
1526   // Make sure the table is of appropriate size.
1527   void adjustSize(std::size_t size) {
1528     if (layeredVarList.size() < size)
1529       layeredVarList.resize(size);
1530   }
1531 
1532   Fortran::lower::pft::Variable::AggregateStore *
1533   findStoreIfAlias(const Fortran::evaluate::Symbol &sym) {
1534     const semantics::Symbol &ultimate = sym.GetUltimate();
1535     const semantics::Scope &scope = ultimate.owner();
1536     // Expect the total number of EQUIVALENCE sets to be small for a typical
1537     // Fortran program.
1538     if (aliasSyms.find(&ultimate) != aliasSyms.end()) {
1539       LLVM_DEBUG(llvm::dbgs() << "found aggregate containing " << &ultimate
1540                               << " " << ultimate.name() << " in <" << &scope
1541                               << "> " << scope.GetName() << '\n');
1542       std::size_t off = ultimate.offset();
1543       std::size_t symSize = ultimate.size();
1544       for (lower::pft::Variable::AggregateStore &v : stores) {
1545         if (&v.getOwningScope() == &scope) {
1546           auto intervalOff = std::get<0>(v.interval);
1547           auto intervalSize = std::get<1>(v.interval);
1548           if (off >= intervalOff && off < intervalOff + intervalSize)
1549             return &v;
1550           // Zero sized symbol in zero sized equivalence.
1551           if (off == intervalOff && symSize == 0)
1552             return &v;
1553         }
1554       }
1555       // clang-format off
1556       LLVM_DEBUG(
1557           llvm::dbgs() << "looking for " << off << "\n{\n";
1558           for (lower::pft::Variable::AggregateStore &v : stores) {
1559             llvm::dbgs() << " in scope: " << &v.getOwningScope() << "\n";
1560             llvm::dbgs() << "  i = [" << std::get<0>(v.interval) << ".."
1561                 << std::get<0>(v.interval) + std::get<1>(v.interval)
1562                 << "]\n";
1563           }
1564           llvm::dbgs() << "}\n");
1565       // clang-format on
1566       llvm_unreachable("the store must be present");
1567     }
1568     return nullptr;
1569   }
1570 
1571   /// Flatten the result VariableList.
1572   void finalize() {
1573     for (int i = 1, end = layeredVarList.size(); i < end; ++i)
1574       layeredVarList[0].insert(layeredVarList[0].end(),
1575                                layeredVarList[i].begin(),
1576                                layeredVarList[i].end());
1577   }
1578 
1579   llvm::SmallSet<const semantics::Symbol *, 32> seen;
1580   std::vector<Fortran::lower::pft::VariableList> layeredVarList;
1581   llvm::SmallSet<const semantics::Symbol *, 32> aliasSyms;
1582   /// Set of scopes that have been analyzed for aliases.
1583   llvm::SmallSet<const semantics::Scope *, 4> analyzedScopes;
1584   std::vector<Fortran::lower::pft::Variable::AggregateStore> stores;
1585 };
1586 } // namespace
1587 
1588 //===----------------------------------------------------------------------===//
1589 // FunctionLikeUnit implementation
1590 //===----------------------------------------------------------------------===//
1591 
1592 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1593     const parser::MainProgram &func, const lower::pft::PftNode &parent,
1594     const semantics::SemanticsContext &semanticsContext)
1595     : ProgramUnit{func, parent}, endStmt{
1596                                      getFunctionStmt<parser::EndProgramStmt>(
1597                                          func)} {
1598   const auto &programStmt =
1599       std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(func.t);
1600   if (programStmt.has_value()) {
1601     beginStmt = FunctionStatement(programStmt.value());
1602     const semantics::Symbol *symbol = getSymbol(*beginStmt);
1603     entryPointList[0].first = symbol;
1604     scope = symbol->scope();
1605   } else {
1606     scope = &semanticsContext.FindScope(
1607         std::get<parser::Statement<parser::EndProgramStmt>>(func.t).source);
1608   }
1609 }
1610 
1611 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1612     const parser::FunctionSubprogram &func, const lower::pft::PftNode &parent,
1613     const semantics::SemanticsContext &)
1614     : ProgramUnit{func, parent},
1615       beginStmt{getFunctionStmt<parser::FunctionStmt>(func)},
1616       endStmt{getFunctionStmt<parser::EndFunctionStmt>(func)} {
1617   const semantics::Symbol *symbol = getSymbol(*beginStmt);
1618   entryPointList[0].first = symbol;
1619   scope = symbol->scope();
1620 }
1621 
1622 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1623     const parser::SubroutineSubprogram &func, const lower::pft::PftNode &parent,
1624     const semantics::SemanticsContext &)
1625     : ProgramUnit{func, parent},
1626       beginStmt{getFunctionStmt<parser::SubroutineStmt>(func)},
1627       endStmt{getFunctionStmt<parser::EndSubroutineStmt>(func)} {
1628   const semantics::Symbol *symbol = getSymbol(*beginStmt);
1629   entryPointList[0].first = symbol;
1630   scope = symbol->scope();
1631 }
1632 
1633 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1634     const parser::SeparateModuleSubprogram &func,
1635     const lower::pft::PftNode &parent, const semantics::SemanticsContext &)
1636     : ProgramUnit{func, parent},
1637       beginStmt{getFunctionStmt<parser::MpSubprogramStmt>(func)},
1638       endStmt{getFunctionStmt<parser::EndMpSubprogramStmt>(func)} {
1639   const semantics::Symbol *symbol = getSymbol(*beginStmt);
1640   entryPointList[0].first = symbol;
1641   scope = symbol->scope();
1642 }
1643 
1644 Fortran::lower::HostAssociations &
1645 Fortran::lower::pft::FunctionLikeUnit::parentHostAssoc() {
1646   if (auto *par = parent.getIf<FunctionLikeUnit>())
1647     return par->hostAssociations;
1648   llvm::report_fatal_error("parent is not a function");
1649 }
1650 
1651 bool Fortran::lower::pft::FunctionLikeUnit::parentHasTupleHostAssoc() {
1652   if (auto *par = parent.getIf<FunctionLikeUnit>())
1653     return par->hostAssociations.hasTupleAssociations();
1654   return false;
1655 }
1656 
1657 bool Fortran::lower::pft::FunctionLikeUnit::parentHasHostAssoc() {
1658   if (auto *par = parent.getIf<FunctionLikeUnit>())
1659     return !par->hostAssociations.empty();
1660   return false;
1661 }
1662 
1663 parser::CharBlock
1664 Fortran::lower::pft::FunctionLikeUnit::getStartingSourceLoc() const {
1665   if (beginStmt)
1666     return stmtSourceLoc(*beginStmt);
1667   if (!evaluationList.empty())
1668     return evaluationList.front().position;
1669   return stmtSourceLoc(endStmt);
1670 }
1671 
1672 //===----------------------------------------------------------------------===//
1673 // ModuleLikeUnit implementation
1674 //===----------------------------------------------------------------------===//
1675 
1676 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit(
1677     const parser::Module &m, const lower::pft::PftNode &parent)
1678     : ProgramUnit{m, parent}, beginStmt{getModuleStmt<parser::ModuleStmt>(m)},
1679       endStmt{getModuleStmt<parser::EndModuleStmt>(m)} {}
1680 
1681 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit(
1682     const parser::Submodule &m, const lower::pft::PftNode &parent)
1683     : ProgramUnit{m, parent}, beginStmt{getModuleStmt<parser::SubmoduleStmt>(
1684                                   m)},
1685       endStmt{getModuleStmt<parser::EndSubmoduleStmt>(m)} {}
1686 
1687 parser::CharBlock
1688 Fortran::lower::pft::ModuleLikeUnit::getStartingSourceLoc() const {
1689   return stmtSourceLoc(beginStmt);
1690 }
1691 const Fortran::semantics::Scope &
1692 Fortran::lower::pft::ModuleLikeUnit::getScope() const {
1693   const Fortran::semantics::Symbol *symbol = getSymbol(beginStmt);
1694   assert(symbol && symbol->scope() &&
1695          "Module statement must have a symbol with a scope");
1696   return *symbol->scope();
1697 }
1698 
1699 //===----------------------------------------------------------------------===//
1700 // BlockDataUnit implementation
1701 //===----------------------------------------------------------------------===//
1702 
1703 Fortran::lower::pft::BlockDataUnit::BlockDataUnit(
1704     const parser::BlockData &bd, const lower::pft::PftNode &parent,
1705     const semantics::SemanticsContext &semanticsContext)
1706     : ProgramUnit{bd, parent},
1707       symTab{semanticsContext.FindScope(
1708           std::get<parser::Statement<parser::EndBlockDataStmt>>(bd.t).source)} {
1709 }
1710 
1711 std::unique_ptr<lower::pft::Program>
1712 Fortran::lower::createPFT(const parser::Program &root,
1713                           const semantics::SemanticsContext &semanticsContext) {
1714   PFTBuilder walker(semanticsContext);
1715   Walk(root, walker);
1716   return walker.result();
1717 }
1718 
1719 void Fortran::lower::dumpPFT(llvm::raw_ostream &outputStream,
1720                              const lower::pft::Program &pft) {
1721   PFTDumper{}.dumpPFT(outputStream, pft);
1722 }
1723 
1724 void Fortran::lower::pft::Program::dump() const {
1725   dumpPFT(llvm::errs(), *this);
1726 }
1727 
1728 void Fortran::lower::pft::Evaluation::dump() const {
1729   PFTDumper{}.dumpEvaluation(llvm::errs(), *this);
1730 }
1731 
1732 void Fortran::lower::pft::Variable::dump() const {
1733   if (auto *s = std::get_if<Nominal>(&var)) {
1734     llvm::errs() << s->symbol << " " << *s->symbol;
1735     llvm::errs() << " (depth: " << s->depth << ')';
1736     if (s->global)
1737       llvm::errs() << ", global";
1738     if (s->heapAlloc)
1739       llvm::errs() << ", allocatable";
1740     if (s->pointer)
1741       llvm::errs() << ", pointer";
1742     if (s->target)
1743       llvm::errs() << ", target";
1744     if (s->aliaser)
1745       llvm::errs() << ", equivalence(" << s->aliasOffset << ')';
1746   } else if (auto *s = std::get_if<AggregateStore>(&var)) {
1747     llvm::errs() << "interval[" << std::get<0>(s->interval) << ", "
1748                  << std::get<1>(s->interval) << "]:";
1749     llvm::errs() << " name: " << toStringRef(s->getNamingSymbol().name());
1750     if (s->isGlobal())
1751       llvm::errs() << ", global";
1752     if (s->initialValueSymbol)
1753       llvm::errs() << ", initial value: {" << *s->initialValueSymbol << "}";
1754   } else {
1755     llvm_unreachable("not a Variable");
1756   }
1757   llvm::errs() << '\n';
1758 }
1759 
1760 void Fortran::lower::pft::dump(Fortran::lower::pft::VariableList &variableList,
1761                                std::string s) {
1762   llvm::errs() << (s.empty() ? "VariableList" : s) << " " << &variableList
1763                << " size=" << variableList.size() << "\n";
1764   for (auto var : variableList) {
1765     llvm::errs() << "  ";
1766     var.dump();
1767   }
1768 }
1769 
1770 void Fortran::lower::pft::FunctionLikeUnit::dump() const {
1771   PFTDumper{}.dumpFunctionLikeUnit(llvm::errs(), *this);
1772 }
1773 
1774 void Fortran::lower::pft::ModuleLikeUnit::dump() const {
1775   PFTDumper{}.dumpModuleLikeUnit(llvm::errs(), *this);
1776 }
1777 
1778 /// The BlockDataUnit dump is just the associated symbol table.
1779 void Fortran::lower::pft::BlockDataUnit::dump() const {
1780   llvm::errs() << "block data {\n" << symTab << "\n}\n";
1781 }
1782 
1783 /// Find or create an ordered list of equivalences and variables in \p scope.
1784 /// The result is cached in \p map.
1785 const lower::pft::VariableList &
1786 lower::pft::getScopeVariableList(const semantics::Scope &scope,
1787                                  ScopeVariableListMap &map) {
1788   LLVM_DEBUG(llvm::dbgs() << "\ngetScopeVariableList of [sub]module scope <"
1789                           << &scope << "> " << scope.GetName() << "\n");
1790   auto iter = map.find(&scope);
1791   if (iter == map.end()) {
1792     SymbolDependenceAnalysis sda(scope);
1793     map.emplace(&scope, sda.getVariableList());
1794     iter = map.find(&scope);
1795   }
1796   return iter->second;
1797 }
1798 
1799 /// Create an ordered list of equivalences and variables in \p scope.
1800 /// The result is not cached.
1801 lower::pft::VariableList
1802 lower::pft::getScopeVariableList(const semantics::Scope &scope) {
1803   LLVM_DEBUG(
1804       llvm::dbgs() << "\ngetScopeVariableList of [sub]program|block scope <"
1805                    << &scope << "> " << scope.GetName() << "\n");
1806   SymbolDependenceAnalysis sda(scope);
1807   return sda.getVariableList();
1808 }
1809 
1810 /// Create an ordered list of equivalences and variables that \p symbol
1811 /// depends on (no caching). Include \p symbol at the end of the list.
1812 lower::pft::VariableList
1813 lower::pft::getDependentVariableList(const semantics::Symbol &symbol) {
1814   LLVM_DEBUG(llvm::dbgs() << "\ngetDependentVariableList of " << &symbol
1815                           << " - " << symbol << "\n");
1816   SymbolDependenceAnalysis sda(symbol);
1817   return sda.getVariableList();
1818 }
1819 
1820 namespace {
1821 /// Helper class to find all the symbols referenced in a FunctionLikeUnit.
1822 /// It defines a parse tree visitor doing a deep visit in all nodes with
1823 /// symbols (including evaluate::Expr).
1824 struct SymbolVisitor {
1825   template <typename A>
1826   bool Pre(const A &x) {
1827     if constexpr (Fortran::parser::HasTypedExpr<A>::value)
1828       // Some parse tree Expr may legitimately be un-analyzed after semantics
1829       // (for instance PDT component initial value in the PDT definition body).
1830       if (const auto *expr = Fortran::semantics::GetExpr(nullptr, x))
1831         visitExpr(*expr);
1832     return true;
1833   }
1834 
1835   bool Pre(const Fortran::parser::Name &name) {
1836     if (const semantics::Symbol *symbol = name.symbol)
1837       visitSymbol(*symbol);
1838     return false;
1839   }
1840 
1841   template <typename T>
1842   void visitExpr(const Fortran::evaluate::Expr<T> &expr) {
1843     for (const semantics::Symbol &symbol :
1844          Fortran::evaluate::CollectSymbols(expr))
1845       visitSymbol(symbol);
1846   }
1847 
1848   void visitSymbol(const Fortran::semantics::Symbol &symbol) {
1849     callBack(symbol);
1850     // - Visit statement function body since it will be inlined in lowering.
1851     // - Visit function results specification expressions because allocations
1852     //   happens on the caller side.
1853     if (const auto *subprogramDetails =
1854             symbol.detailsIf<Fortran::semantics::SubprogramDetails>()) {
1855       if (const auto &maybeExpr = subprogramDetails->stmtFunction()) {
1856         visitExpr(*maybeExpr);
1857       } else {
1858         if (subprogramDetails->isFunction()) {
1859           // Visit result extents expressions that are explicit.
1860           const Fortran::semantics::Symbol &result =
1861               subprogramDetails->result();
1862           if (const auto *objectDetails =
1863                   result.detailsIf<Fortran::semantics::ObjectEntityDetails>())
1864             if (objectDetails->shape().IsExplicitShape())
1865               for (const Fortran::semantics::ShapeSpec &shapeSpec :
1866                    objectDetails->shape()) {
1867                 visitExpr(shapeSpec.lbound().GetExplicit().value());
1868                 visitExpr(shapeSpec.ubound().GetExplicit().value());
1869               }
1870         }
1871       }
1872     }
1873     if (Fortran::semantics::IsProcedure(symbol)) {
1874       if (auto dynamicType = Fortran::evaluate::DynamicType::From(symbol)) {
1875         // Visit result length specification expressions that are explicit.
1876         if (dynamicType->category() ==
1877             Fortran::common::TypeCategory::Character) {
1878           if (std::optional<Fortran::evaluate::ExtentExpr> length =
1879                   dynamicType->GetCharLength())
1880             visitExpr(*length);
1881         } else if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
1882                        Fortran::evaluate::GetDerivedTypeSpec(dynamicType)) {
1883           for (const auto &[_, param] : derivedTypeSpec->parameters())
1884             if (const Fortran::semantics::MaybeIntExpr &expr =
1885                     param.GetExplicit())
1886               visitExpr(expr.value());
1887         }
1888       }
1889     }
1890   }
1891 
1892   template <typename A>
1893   constexpr void Post(const A &) {}
1894 
1895   const std::function<void(const Fortran::semantics::Symbol &)> &callBack;
1896 };
1897 } // namespace
1898 
1899 void Fortran::lower::pft::visitAllSymbols(
1900     const Fortran::lower::pft::FunctionLikeUnit &funit,
1901     const std::function<void(const Fortran::semantics::Symbol &)> callBack) {
1902   SymbolVisitor visitor{callBack};
1903   funit.visit([&](const auto &functionParserNode) {
1904     parser::Walk(functionParserNode, visitor);
1905   });
1906 }
1907 
1908 void Fortran::lower::pft::visitAllSymbols(
1909     const Fortran::lower::pft::Evaluation &eval,
1910     const std::function<void(const Fortran::semantics::Symbol &)> callBack) {
1911   SymbolVisitor visitor{callBack};
1912   eval.visit([&](const auto &functionParserNode) {
1913     parser::Walk(functionParserNode, visitor);
1914   });
1915 }
1916