1 //===-- PFTBuilder.cc -----------------------------------------------------===//
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 "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 static llvm::cl::opt<bool> nonRecursiveProcedures(
28     "non-recursive-procedures",
29     llvm::cl::desc("Make procedures non-recursive by default. This was the "
30                    "default for all Fortran standards prior to 2018."),
31     llvm::cl::init(/*2018 standard=*/false));
32 
33 using namespace Fortran;
34 
35 namespace {
36 /// Helpers to unveil parser node inside Fortran::parser::Statement<>,
37 /// Fortran::parser::UnlabeledStatement, and Fortran::common::Indirection<>
38 template <typename A>
39 struct RemoveIndirectionHelper {
40   using Type = A;
41 };
42 template <typename A>
43 struct RemoveIndirectionHelper<common::Indirection<A>> {
44   using Type = A;
45 };
46 
47 template <typename A>
48 struct UnwrapStmt {
49   static constexpr bool isStmt{false};
50 };
51 template <typename A>
52 struct UnwrapStmt<parser::Statement<A>> {
53   static constexpr bool isStmt{true};
54   using Type = typename RemoveIndirectionHelper<A>::Type;
55   constexpr UnwrapStmt(const parser::Statement<A> &a)
56       : unwrapped{removeIndirection(a.statement)}, position{a.source},
57         label{a.label} {}
58   const Type &unwrapped;
59   parser::CharBlock position;
60   std::optional<parser::Label> label;
61 };
62 template <typename A>
63 struct UnwrapStmt<parser::UnlabeledStatement<A>> {
64   static constexpr bool isStmt{true};
65   using Type = typename RemoveIndirectionHelper<A>::Type;
66   constexpr UnwrapStmt(const parser::UnlabeledStatement<A> &a)
67       : unwrapped{removeIndirection(a.statement)}, position{a.source} {}
68   const Type &unwrapped;
69   parser::CharBlock position;
70   std::optional<parser::Label> label;
71 };
72 
73 /// The instantiation of a parse tree visitor (Pre and Post) is extremely
74 /// expensive in terms of compile and link time.  So one goal here is to
75 /// limit the bridge to one such instantiation.
76 class PFTBuilder {
77 public:
78   PFTBuilder(const semantics::SemanticsContext &semanticsContext)
79       : pgm{std::make_unique<lower::pft::Program>()}, semanticsContext{
80                                                           semanticsContext} {
81     lower::pft::PftNode pftRoot{*pgm.get()};
82     pftParentStack.push_back(pftRoot);
83   }
84 
85   /// Get the result
86   std::unique_ptr<lower::pft::Program> result() { return std::move(pgm); }
87 
88   template <typename A>
89   constexpr bool Pre(const A &a) {
90     if constexpr (lower::pft::isFunctionLike<A>) {
91       return enterFunction(a, semanticsContext);
92     } else if constexpr (lower::pft::isConstruct<A> ||
93                          lower::pft::isDirective<A>) {
94       return enterConstructOrDirective(a);
95     } else if constexpr (UnwrapStmt<A>::isStmt) {
96       using T = typename UnwrapStmt<A>::Type;
97       // Node "a" being visited has one of the following types:
98       // Statement<T>, Statement<Indirection<T>>, UnlabeledStatement<T>,
99       // or UnlabeledStatement<Indirection<T>>
100       auto stmt{UnwrapStmt<A>(a)};
101       if constexpr (lower::pft::isConstructStmt<T> ||
102                     lower::pft::isOtherStmt<T>) {
103         addEvaluation(lower::pft::Evaluation{
104             stmt.unwrapped, pftParentStack.back(), stmt.position, stmt.label});
105         return false;
106       } else if constexpr (std::is_same_v<T, parser::ActionStmt>) {
107         return std::visit(
108             common::visitors{
109                 [&](const common::Indirection<parser::IfStmt> &x) {
110                   convertIfStmt(x.value(), stmt.position, stmt.label);
111                   return false;
112                 },
113                 [&](const auto &x) {
114                   addEvaluation(lower::pft::Evaluation{
115                       removeIndirection(x), pftParentStack.back(),
116                       stmt.position, stmt.label});
117                   return true;
118                 },
119             },
120             stmt.unwrapped.u);
121       }
122     }
123     return true;
124   }
125 
126   /// Convert an IfStmt into an IfConstruct, retaining the IfStmt as the
127   /// first statement of the construct.
128   void convertIfStmt(const parser::IfStmt &ifStmt, parser::CharBlock position,
129                      std::optional<parser::Label> label) {
130     // Generate a skeleton IfConstruct parse node.  Its components are never
131     // referenced.  The actual components are available via the IfConstruct
132     // evaluation's nested evaluationList, with the ifStmt in the position of
133     // the otherwise normal IfThenStmt.  Caution: All other PFT nodes reference
134     // front end generated parse nodes; this is an exceptional case.
135     static const auto ifConstruct = parser::IfConstruct{
136         parser::Statement<parser::IfThenStmt>{
137             std::nullopt,
138             parser::IfThenStmt{
139                 std::optional<parser::Name>{},
140                 parser::ScalarLogicalExpr{parser::LogicalExpr{parser::Expr{
141                     parser::LiteralConstant{parser::LogicalLiteralConstant{
142                         false, std::optional<parser::KindParam>{}}}}}}}},
143         parser::Block{}, std::list<parser::IfConstruct::ElseIfBlock>{},
144         std::optional<parser::IfConstruct::ElseBlock>{},
145         parser::Statement<parser::EndIfStmt>{std::nullopt,
146                                              parser::EndIfStmt{std::nullopt}}};
147     enterConstructOrDirective(ifConstruct);
148     addEvaluation(
149         lower::pft::Evaluation{ifStmt, pftParentStack.back(), position, label});
150     Pre(std::get<parser::UnlabeledStatement<parser::ActionStmt>>(ifStmt.t));
151     static const auto endIfStmt = parser::EndIfStmt{std::nullopt};
152     addEvaluation(
153         lower::pft::Evaluation{endIfStmt, pftParentStack.back(), {}, {}});
154     exitConstructOrDirective();
155   }
156 
157   template <typename A>
158   constexpr void Post(const A &) {
159     if constexpr (lower::pft::isFunctionLike<A>) {
160       exitFunction();
161     } else if constexpr (lower::pft::isConstruct<A> ||
162                          lower::pft::isDirective<A>) {
163       exitConstructOrDirective();
164     }
165   }
166 
167   // Module like
168   bool Pre(const parser::Module &node) { return enterModule(node); }
169   bool Pre(const parser::Submodule &node) { return enterModule(node); }
170 
171   void Post(const parser::Module &) { exitModule(); }
172   void Post(const parser::Submodule &) { exitModule(); }
173 
174   // Block data
175   bool Pre(const parser::BlockData &node) {
176     addUnit(lower::pft::BlockDataUnit{node, pftParentStack.back(),
177                                       semanticsContext});
178     return false;
179   }
180 
181   // Get rid of production wrapper
182   bool Pre(const parser::Statement<parser::ForallAssignmentStmt> &statement) {
183     addEvaluation(std::visit(
184         [&](const auto &x) {
185           return lower::pft::Evaluation{x, pftParentStack.back(),
186                                         statement.source, statement.label};
187         },
188         statement.statement.u));
189     return false;
190   }
191   bool Pre(const parser::WhereBodyConstruct &whereBody) {
192     return std::visit(
193         common::visitors{
194             [&](const parser::Statement<parser::AssignmentStmt> &stmt) {
195               // Not caught as other AssignmentStmt because it is not
196               // wrapped in a parser::ActionStmt.
197               addEvaluation(lower::pft::Evaluation{stmt.statement,
198                                                    pftParentStack.back(),
199                                                    stmt.source, stmt.label});
200               return false;
201             },
202             [&](const auto &) { return true; },
203         },
204         whereBody.u);
205   }
206 
207   // CompilerDirective have special handling in case they are top level
208   // directives (i.e. they do not belong to a ProgramUnit).
209   bool Pre(const parser::CompilerDirective &directive) {
210     assert(pftParentStack.size() > 0 &&
211            "At least the Program must be a parent");
212     if (pftParentStack.back().isA<lower::pft::Program>()) {
213       addUnit(
214           lower::pft::CompilerDirectiveUnit(directive, pftParentStack.back()));
215       return false;
216     }
217     return enterConstructOrDirective(directive);
218   }
219 
220 private:
221   /// Initialize a new module-like unit and make it the builder's focus.
222   template <typename A>
223   bool enterModule(const A &func) {
224     auto &unit =
225         addUnit(lower::pft::ModuleLikeUnit{func, pftParentStack.back()});
226     functionList = &unit.nestedFunctions;
227     pftParentStack.emplace_back(unit);
228     return true;
229   }
230 
231   void exitModule() {
232     pftParentStack.pop_back();
233     resetFunctionState();
234   }
235 
236   /// Add the end statement Evaluation of a sub/program to the PFT.
237   /// There may be intervening internal subprogram definitions between
238   /// prior statements and this end statement.
239   void endFunctionBody() {
240     if (evaluationListStack.empty())
241       return;
242     auto evaluationList = evaluationListStack.back();
243     if (evaluationList->empty() || !evaluationList->back().isEndStmt()) {
244       const auto &endStmt =
245           pftParentStack.back().get<lower::pft::FunctionLikeUnit>().endStmt;
246       endStmt.visit(common::visitors{
247           [&](const parser::Statement<parser::EndProgramStmt> &s) {
248             addEvaluation(lower::pft::Evaluation{
249                 s.statement, pftParentStack.back(), s.source, s.label});
250           },
251           [&](const parser::Statement<parser::EndFunctionStmt> &s) {
252             addEvaluation(lower::pft::Evaluation{
253                 s.statement, pftParentStack.back(), s.source, s.label});
254           },
255           [&](const parser::Statement<parser::EndSubroutineStmt> &s) {
256             addEvaluation(lower::pft::Evaluation{
257                 s.statement, pftParentStack.back(), s.source, s.label});
258           },
259           [&](const parser::Statement<parser::EndMpSubprogramStmt> &s) {
260             addEvaluation(lower::pft::Evaluation{
261                 s.statement, pftParentStack.back(), s.source, s.label});
262           },
263           [&](const auto &s) {
264             llvm::report_fatal_error("missing end statement or unexpected "
265                                      "begin statement reference");
266           },
267       });
268     }
269     lastLexicalEvaluation = nullptr;
270   }
271 
272   /// Initialize a new function-like unit and make it the builder's focus.
273   template <typename A>
274   bool enterFunction(const A &func,
275                      const semantics::SemanticsContext &semanticsContext) {
276     endFunctionBody(); // enclosing host subprogram body, if any
277     auto &unit = addFunction(lower::pft::FunctionLikeUnit{
278         func, pftParentStack.back(), semanticsContext});
279     labelEvaluationMap = &unit.labelEvaluationMap;
280     assignSymbolLabelMap = &unit.assignSymbolLabelMap;
281     functionList = &unit.nestedFunctions;
282     pushEvaluationList(&unit.evaluationList);
283     pftParentStack.emplace_back(unit);
284     return true;
285   }
286 
287   void exitFunction() {
288     rewriteIfGotos();
289     endFunctionBody();
290     analyzeBranches(nullptr, *evaluationListStack.back()); // add branch links
291     processEntryPoints();
292     popEvaluationList();
293     labelEvaluationMap = nullptr;
294     assignSymbolLabelMap = nullptr;
295     pftParentStack.pop_back();
296     resetFunctionState();
297   }
298 
299   /// Initialize a new construct and make it the builder's focus.
300   template <typename A>
301   bool enterConstructOrDirective(const A &construct) {
302     auto &eval =
303         addEvaluation(lower::pft::Evaluation{construct, pftParentStack.back()});
304     eval.evaluationList.reset(new lower::pft::EvaluationList);
305     pushEvaluationList(eval.evaluationList.get());
306     pftParentStack.emplace_back(eval);
307     constructAndDirectiveStack.emplace_back(&eval);
308     return true;
309   }
310 
311   void exitConstructOrDirective() {
312     rewriteIfGotos();
313     popEvaluationList();
314     pftParentStack.pop_back();
315     constructAndDirectiveStack.pop_back();
316   }
317 
318   /// Reset function state to that of an enclosing host function.
319   void resetFunctionState() {
320     if (!pftParentStack.empty()) {
321       pftParentStack.back().visit(common::visitors{
322           [&](lower::pft::FunctionLikeUnit &p) {
323             functionList = &p.nestedFunctions;
324             labelEvaluationMap = &p.labelEvaluationMap;
325             assignSymbolLabelMap = &p.assignSymbolLabelMap;
326           },
327           [&](lower::pft::ModuleLikeUnit &p) {
328             functionList = &p.nestedFunctions;
329           },
330           [&](auto &) { functionList = nullptr; },
331       });
332     }
333   }
334 
335   template <typename A>
336   A &addUnit(A &&unit) {
337     pgm->getUnits().emplace_back(std::move(unit));
338     return std::get<A>(pgm->getUnits().back());
339   }
340 
341   template <typename A>
342   A &addFunction(A &&func) {
343     if (functionList) {
344       functionList->emplace_back(std::move(func));
345       return functionList->back();
346     }
347     return addUnit(std::move(func));
348   }
349 
350   // ActionStmt has a couple of non-conforming cases, explicitly handled here.
351   // The other cases use an Indirection, which are discarded in the PFT.
352   lower::pft::Evaluation
353   makeEvaluationAction(const parser::ActionStmt &statement,
354                        parser::CharBlock position,
355                        std::optional<parser::Label> label) {
356     return std::visit(
357         common::visitors{
358             [&](const auto &x) {
359               return lower::pft::Evaluation{
360                   removeIndirection(x), pftParentStack.back(), position, label};
361             },
362         },
363         statement.u);
364   }
365 
366   /// Append an Evaluation to the end of the current list.
367   lower::pft::Evaluation &addEvaluation(lower::pft::Evaluation &&eval) {
368     assert(functionList && "not in a function");
369     assert(!evaluationListStack.empty() && "empty evaluation list stack");
370     if (!constructAndDirectiveStack.empty())
371       eval.parentConstruct = constructAndDirectiveStack.back();
372     auto &entryPointList = eval.getOwningProcedure()->entryPointList;
373     evaluationListStack.back()->emplace_back(std::move(eval));
374     lower::pft::Evaluation *p = &evaluationListStack.back()->back();
375     if (p->isActionStmt() || p->isConstructStmt() || p->isEndStmt()) {
376       if (lastLexicalEvaluation) {
377         lastLexicalEvaluation->lexicalSuccessor = p;
378         p->printIndex = lastLexicalEvaluation->printIndex + 1;
379       } else {
380         p->printIndex = 1;
381       }
382       lastLexicalEvaluation = p;
383       for (auto entryIndex = entryPointList.size() - 1;
384            entryIndex && !entryPointList[entryIndex].second->lexicalSuccessor;
385            --entryIndex)
386         // Link to the entry's first executable statement.
387         entryPointList[entryIndex].second->lexicalSuccessor = p;
388     } else if (const auto *entryStmt = p->getIf<parser::EntryStmt>()) {
389       const auto *sym = std::get<parser::Name>(entryStmt->t).symbol;
390       assert(sym->has<semantics::SubprogramDetails>() &&
391              "entry must be a subprogram");
392       entryPointList.push_back(std::pair{sym, p});
393     }
394     if (p->label.has_value())
395       labelEvaluationMap->try_emplace(*p->label, p);
396     return evaluationListStack.back()->back();
397   }
398 
399   /// push a new list on the stack of Evaluation lists
400   void pushEvaluationList(lower::pft::EvaluationList *evaluationList) {
401     assert(functionList && "not in a function");
402     assert(evaluationList && evaluationList->empty() &&
403            "evaluation list isn't correct");
404     evaluationListStack.emplace_back(evaluationList);
405   }
406 
407   /// pop the current list and return to the last Evaluation list
408   void popEvaluationList() {
409     assert(functionList && "not in a function");
410     evaluationListStack.pop_back();
411   }
412 
413   /// Rewrite IfConstructs containing a GotoStmt to eliminate an unstructured
414   /// branch and a trivial basic block.  The pre-branch-analysis code:
415   ///
416   ///       <<IfConstruct>>
417   ///         1 If[Then]Stmt: if(cond) goto L
418   ///         2 GotoStmt: goto L
419   ///         3 EndIfStmt
420   ///       <<End IfConstruct>>
421   ///       4 Statement: ...
422   ///       5 Statement: ...
423   ///       6 Statement: L ...
424   ///
425   /// becomes:
426   ///
427   ///       <<IfConstruct>>
428   ///         1 If[Then]Stmt [negate]: if(cond) goto L
429   ///         4 Statement: ...
430   ///         5 Statement: ...
431   ///         3 EndIfStmt
432   ///       <<End IfConstruct>>
433   ///       6 Statement: L ...
434   ///
435   /// The If[Then]Stmt condition is implicitly negated.  It is not modified
436   /// in the PFT.  It must be negated when generating FIR.  The GotoStmt is
437   /// deleted.
438   ///
439   /// The transformation is only valid for forward branch targets at the same
440   /// construct nesting level as the IfConstruct.  The result must not violate
441   /// construct nesting requirements or contain an EntryStmt.  The result
442   /// is subject to normal un/structured code classification analysis.  The
443   /// result is allowed to violate the F18 Clause 11.1.2.1 prohibition on
444   /// transfer of control into the interior of a construct block, as that does
445   /// not compromise correct code generation.  When two transformation
446   /// candidates overlap, at least one must be disallowed.  In such cases,
447   /// the current heuristic favors simple code generation, which happens to
448   /// favor later candidates over earlier candidates.  That choice is probably
449   /// not significant, but could be changed.
450   ///
451   void rewriteIfGotos() {
452     using T = struct {
453       lower::pft::EvaluationList::iterator ifConstructIt;
454       parser::Label ifTargetLabel;
455     };
456     llvm::SmallVector<T, 8> ifExpansionStack;
457     auto &evaluationList = *evaluationListStack.back();
458     for (auto it = evaluationList.begin(), end = evaluationList.end();
459          it != end; ++it) {
460       auto &eval = *it;
461       if (eval.isA<parser::EntryStmt>()) {
462         ifExpansionStack.clear();
463         continue;
464       }
465       auto firstStmt = [](lower::pft::Evaluation *e) {
466         return e->isConstruct() ? &*e->evaluationList->begin() : e;
467       };
468       auto &targetEval = *firstStmt(&eval);
469       if (targetEval.label) {
470         while (!ifExpansionStack.empty() &&
471                ifExpansionStack.back().ifTargetLabel == *targetEval.label) {
472           auto ifConstructIt = ifExpansionStack.back().ifConstructIt;
473           auto successorIt = std::next(ifConstructIt);
474           if (successorIt != it) {
475             auto &ifBodyList = *ifConstructIt->evaluationList;
476             auto gotoStmtIt = std::next(ifBodyList.begin());
477             assert(gotoStmtIt->isA<parser::GotoStmt>() && "expected GotoStmt");
478             ifBodyList.erase(gotoStmtIt);
479             auto &ifStmt = *ifBodyList.begin();
480             ifStmt.negateCondition = true;
481             ifStmt.lexicalSuccessor = firstStmt(&*successorIt);
482             auto endIfStmtIt = std::prev(ifBodyList.end());
483             std::prev(it)->lexicalSuccessor = &*endIfStmtIt;
484             endIfStmtIt->lexicalSuccessor = firstStmt(&*it);
485             ifBodyList.splice(endIfStmtIt, evaluationList, successorIt, it);
486             for (; successorIt != endIfStmtIt; ++successorIt)
487               successorIt->parentConstruct = &*ifConstructIt;
488           }
489           ifExpansionStack.pop_back();
490         }
491       }
492       if (eval.isA<parser::IfConstruct>() && eval.evaluationList->size() == 3) {
493         if (auto *gotoStmt = std::next(eval.evaluationList->begin())
494                                  ->getIf<parser::GotoStmt>())
495           ifExpansionStack.push_back({it, gotoStmt->v});
496       }
497     }
498   }
499 
500   /// Mark I/O statement ERR, EOR, and END specifier branch targets.
501   /// Mark an I/O statement with an assigned format as unstructured.
502   template <typename A>
503   void analyzeIoBranches(lower::pft::Evaluation &eval, const A &stmt) {
504     auto analyzeFormatSpec = [&](const parser::Format &format) {
505       if (const auto *expr = std::get_if<parser::Expr>(&format.u)) {
506         if (semantics::ExprHasTypeCategory(*semantics::GetExpr(*expr),
507                                            common::TypeCategory::Integer))
508           eval.isUnstructured = true;
509       }
510     };
511     auto analyzeSpecs{[&](const auto &specList) {
512       for (const auto &spec : specList) {
513         std::visit(
514             Fortran::common::visitors{
515                 [&](const Fortran::parser::Format &format) {
516                   analyzeFormatSpec(format);
517                 },
518                 [&](const auto &label) {
519                   using LabelNodes =
520                       std::tuple<parser::ErrLabel, parser::EorLabel,
521                                  parser::EndLabel>;
522                   if constexpr (common::HasMember<decltype(label), LabelNodes>)
523                     markBranchTarget(eval, label.v);
524                 }},
525             spec.u);
526       }
527     }};
528 
529     using OtherIOStmts =
530         std::tuple<parser::BackspaceStmt, parser::CloseStmt,
531                    parser::EndfileStmt, parser::FlushStmt, parser::OpenStmt,
532                    parser::RewindStmt, parser::WaitStmt>;
533 
534     if constexpr (std::is_same_v<A, parser::ReadStmt> ||
535                   std::is_same_v<A, parser::WriteStmt>) {
536       if (stmt.format)
537         analyzeFormatSpec(*stmt.format);
538       analyzeSpecs(stmt.controls);
539     } else if constexpr (std::is_same_v<A, parser::PrintStmt>) {
540       analyzeFormatSpec(std::get<parser::Format>(stmt.t));
541     } else if constexpr (std::is_same_v<A, parser::InquireStmt>) {
542       if (const auto *specList =
543               std::get_if<std::list<parser::InquireSpec>>(&stmt.u))
544         analyzeSpecs(*specList);
545     } else if constexpr (common::HasMember<A, OtherIOStmts>) {
546       analyzeSpecs(stmt.v);
547     } else {
548       // Always crash if this is instantiated
549       static_assert(!std::is_same_v<A, parser::ReadStmt>,
550                     "Unexpected IO statement");
551     }
552   }
553 
554   /// Set the exit of a construct, possibly from multiple enclosing constructs.
555   void setConstructExit(lower::pft::Evaluation &eval) {
556     eval.constructExit = &eval.evaluationList->back().nonNopSuccessor();
557   }
558 
559   /// Mark the target of a branch as a new block.
560   void markBranchTarget(lower::pft::Evaluation &sourceEvaluation,
561                         lower::pft::Evaluation &targetEvaluation) {
562     sourceEvaluation.isUnstructured = true;
563     if (!sourceEvaluation.controlSuccessor)
564       sourceEvaluation.controlSuccessor = &targetEvaluation;
565     targetEvaluation.isNewBlock = true;
566     // If this is a branch into the body of a construct (usually illegal,
567     // but allowed in some legacy cases), then the targetEvaluation and its
568     // ancestors must be marked as unstructured.
569     auto *sourceConstruct = sourceEvaluation.parentConstruct;
570     auto *targetConstruct = targetEvaluation.parentConstruct;
571     if (targetConstruct &&
572         &targetConstruct->getFirstNestedEvaluation() == &targetEvaluation)
573       // A branch to an initial constructStmt is a branch to the construct.
574       targetConstruct = targetConstruct->parentConstruct;
575     if (targetConstruct) {
576       while (sourceConstruct && sourceConstruct != targetConstruct)
577         sourceConstruct = sourceConstruct->parentConstruct;
578       if (sourceConstruct != targetConstruct)
579         for (auto *eval = &targetEvaluation; eval; eval = eval->parentConstruct)
580           eval->isUnstructured = true;
581     }
582   }
583   void markBranchTarget(lower::pft::Evaluation &sourceEvaluation,
584                         parser::Label label) {
585     assert(label && "missing branch target label");
586     lower::pft::Evaluation *targetEvaluation{
587         labelEvaluationMap->find(label)->second};
588     assert(targetEvaluation && "missing branch target evaluation");
589     markBranchTarget(sourceEvaluation, *targetEvaluation);
590   }
591 
592   /// Mark the successor of an Evaluation as a new block.
593   void markSuccessorAsNewBlock(lower::pft::Evaluation &eval) {
594     eval.nonNopSuccessor().isNewBlock = true;
595   }
596 
597   template <typename A>
598   inline std::string getConstructName(const A &stmt) {
599     using MaybeConstructNameWrapper =
600         std::tuple<parser::BlockStmt, parser::CycleStmt, parser::ElseStmt,
601                    parser::ElsewhereStmt, parser::EndAssociateStmt,
602                    parser::EndBlockStmt, parser::EndCriticalStmt,
603                    parser::EndDoStmt, parser::EndForallStmt, parser::EndIfStmt,
604                    parser::EndSelectStmt, parser::EndWhereStmt,
605                    parser::ExitStmt>;
606     if constexpr (common::HasMember<A, MaybeConstructNameWrapper>) {
607       if (stmt.v)
608         return stmt.v->ToString();
609     }
610 
611     using MaybeConstructNameInTuple = std::tuple<
612         parser::AssociateStmt, parser::CaseStmt, parser::ChangeTeamStmt,
613         parser::CriticalStmt, parser::ElseIfStmt, parser::EndChangeTeamStmt,
614         parser::ForallConstructStmt, parser::IfThenStmt, parser::LabelDoStmt,
615         parser::MaskedElsewhereStmt, parser::NonLabelDoStmt,
616         parser::SelectCaseStmt, parser::SelectRankCaseStmt,
617         parser::TypeGuardStmt, parser::WhereConstructStmt>;
618 
619     if constexpr (common::HasMember<A, MaybeConstructNameInTuple>) {
620       if (auto name = std::get<std::optional<parser::Name>>(stmt.t))
621         return name->ToString();
622     }
623 
624     // These statements have several std::optional<parser::Name>
625     if constexpr (std::is_same_v<A, parser::SelectRankStmt> ||
626                   std::is_same_v<A, parser::SelectTypeStmt>) {
627       if (auto name = std::get<0>(stmt.t))
628         return name->ToString();
629     }
630     return {};
631   }
632 
633   /// \p parentConstruct can be null if this statement is at the highest
634   /// level of a program.
635   template <typename A>
636   void insertConstructName(const A &stmt,
637                            lower::pft::Evaluation *parentConstruct) {
638     std::string name = getConstructName(stmt);
639     if (!name.empty())
640       constructNameMap[name] = parentConstruct;
641   }
642 
643   /// Insert branch links for a list of Evaluations.
644   /// \p parentConstruct can be null if the evaluationList contains the
645   /// top-level statements of a program.
646   void analyzeBranches(lower::pft::Evaluation *parentConstruct,
647                        std::list<lower::pft::Evaluation> &evaluationList) {
648     lower::pft::Evaluation *lastConstructStmtEvaluation{};
649     for (auto &eval : evaluationList) {
650       eval.visit(common::visitors{
651           // Action statements (except I/O statements)
652           [&](const parser::CallStmt &s) {
653             // Look for alternate return specifiers.
654             const auto &args =
655                 std::get<std::list<parser::ActualArgSpec>>(s.v.t);
656             for (const auto &arg : args) {
657               const auto &actual = std::get<parser::ActualArg>(arg.t);
658               if (const auto *altReturn =
659                       std::get_if<parser::AltReturnSpec>(&actual.u))
660                 markBranchTarget(eval, altReturn->v);
661             }
662           },
663           [&](const parser::CycleStmt &s) {
664             std::string name = getConstructName(s);
665             lower::pft::Evaluation *construct{name.empty()
666                                                   ? doConstructStack.back()
667                                                   : constructNameMap[name]};
668             assert(construct && "missing CYCLE construct");
669             markBranchTarget(eval, construct->evaluationList->back());
670           },
671           [&](const parser::ExitStmt &s) {
672             std::string name = getConstructName(s);
673             lower::pft::Evaluation *construct{name.empty()
674                                                   ? doConstructStack.back()
675                                                   : constructNameMap[name]};
676             assert(construct && "missing EXIT construct");
677             markBranchTarget(eval, *construct->constructExit);
678           },
679           [&](const parser::GotoStmt &s) { markBranchTarget(eval, s.v); },
680           [&](const parser::IfStmt &) {
681             eval.lexicalSuccessor->isNewBlock = true;
682             lastConstructStmtEvaluation = &eval;
683           },
684           [&](const parser::ReturnStmt &) {
685             eval.isUnstructured = true;
686             if (eval.lexicalSuccessor->lexicalSuccessor)
687               markSuccessorAsNewBlock(eval);
688           },
689           [&](const parser::StopStmt &) {
690             eval.isUnstructured = true;
691             if (eval.lexicalSuccessor->lexicalSuccessor)
692               markSuccessorAsNewBlock(eval);
693           },
694           [&](const parser::ComputedGotoStmt &s) {
695             for (auto &label : std::get<std::list<parser::Label>>(s.t))
696               markBranchTarget(eval, label);
697           },
698           [&](const parser::ArithmeticIfStmt &s) {
699             markBranchTarget(eval, std::get<1>(s.t));
700             markBranchTarget(eval, std::get<2>(s.t));
701             markBranchTarget(eval, std::get<3>(s.t));
702           },
703           [&](const parser::AssignStmt &s) { // legacy label assignment
704             auto &label = std::get<parser::Label>(s.t);
705             const auto *sym = std::get<parser::Name>(s.t).symbol;
706             assert(sym && "missing AssignStmt symbol");
707             lower::pft::Evaluation *target{
708                 labelEvaluationMap->find(label)->second};
709             assert(target && "missing branch target evaluation");
710             if (!target->isA<parser::FormatStmt>())
711               target->isNewBlock = true;
712             auto iter = assignSymbolLabelMap->find(*sym);
713             if (iter == assignSymbolLabelMap->end()) {
714               lower::pft::LabelSet labelSet{};
715               labelSet.insert(label);
716               assignSymbolLabelMap->try_emplace(*sym, labelSet);
717             } else {
718               iter->second.insert(label);
719             }
720           },
721           [&](const parser::AssignedGotoStmt &) {
722             // Although this statement is a branch, it doesn't have any
723             // explicit control successors.  So the code at the end of the
724             // loop won't mark the successor.  Do that here.
725             eval.isUnstructured = true;
726             markSuccessorAsNewBlock(eval);
727           },
728 
729           // Construct statements
730           [&](const parser::AssociateStmt &s) {
731             insertConstructName(s, parentConstruct);
732           },
733           [&](const parser::BlockStmt &s) {
734             insertConstructName(s, parentConstruct);
735           },
736           [&](const parser::SelectCaseStmt &s) {
737             insertConstructName(s, parentConstruct);
738             lastConstructStmtEvaluation = &eval;
739           },
740           [&](const parser::CaseStmt &) {
741             eval.isNewBlock = true;
742             lastConstructStmtEvaluation->controlSuccessor = &eval;
743             lastConstructStmtEvaluation = &eval;
744           },
745           [&](const parser::EndSelectStmt &) {
746             eval.nonNopSuccessor().isNewBlock = true;
747             lastConstructStmtEvaluation = nullptr;
748           },
749           [&](const parser::ChangeTeamStmt &s) {
750             insertConstructName(s, parentConstruct);
751           },
752           [&](const parser::CriticalStmt &s) {
753             insertConstructName(s, parentConstruct);
754           },
755           [&](const parser::NonLabelDoStmt &s) {
756             insertConstructName(s, parentConstruct);
757             doConstructStack.push_back(parentConstruct);
758             const auto &loopControl =
759                 std::get<std::optional<parser::LoopControl>>(s.t);
760             if (!loopControl.has_value()) {
761               eval.isUnstructured = true; // infinite loop
762               return;
763             }
764             eval.nonNopSuccessor().isNewBlock = true;
765             eval.controlSuccessor = &evaluationList.back();
766             if (const auto *bounds =
767                     std::get_if<parser::LoopControl::Bounds>(&loopControl->u)) {
768               if (bounds->name.thing.symbol->GetType()->IsNumeric(
769                       common::TypeCategory::Real))
770                 eval.isUnstructured = true; // real-valued loop control
771             } else if (std::get_if<parser::ScalarLogicalExpr>(
772                            &loopControl->u)) {
773               eval.isUnstructured = true; // while loop
774             }
775           },
776           [&](const parser::EndDoStmt &) {
777             lower::pft::Evaluation &doEval = evaluationList.front();
778             eval.controlSuccessor = &doEval;
779             doConstructStack.pop_back();
780             if (parentConstruct->lowerAsStructured())
781               return;
782             // The loop is unstructured, which wasn't known for all cases when
783             // visiting the NonLabelDoStmt.
784             parentConstruct->constructExit->isNewBlock = true;
785             const auto &doStmt = *doEval.getIf<parser::NonLabelDoStmt>();
786             const auto &loopControl =
787                 std::get<std::optional<parser::LoopControl>>(doStmt.t);
788             if (!loopControl.has_value())
789               return; // infinite loop
790             if (const auto *concurrent =
791                     std::get_if<parser::LoopControl::Concurrent>(
792                         &loopControl->u)) {
793               // If there is a mask, the EndDoStmt starts a new block.
794               const auto &header =
795                   std::get<parser::ConcurrentHeader>(concurrent->t);
796               eval.isNewBlock |=
797                   std::get<std::optional<parser::ScalarLogicalExpr>>(header.t)
798                       .has_value();
799             }
800           },
801           [&](const parser::IfThenStmt &s) {
802             insertConstructName(s, parentConstruct);
803             eval.lexicalSuccessor->isNewBlock = true;
804             lastConstructStmtEvaluation = &eval;
805           },
806           [&](const parser::ElseIfStmt &) {
807             eval.isNewBlock = true;
808             eval.lexicalSuccessor->isNewBlock = true;
809             lastConstructStmtEvaluation->controlSuccessor = &eval;
810             lastConstructStmtEvaluation = &eval;
811           },
812           [&](const parser::ElseStmt &) {
813             eval.isNewBlock = true;
814             lastConstructStmtEvaluation->controlSuccessor = &eval;
815             lastConstructStmtEvaluation = nullptr;
816           },
817           [&](const parser::EndIfStmt &) {
818             if (parentConstruct->lowerAsUnstructured())
819               parentConstruct->constructExit->isNewBlock = true;
820             if (lastConstructStmtEvaluation) {
821               lastConstructStmtEvaluation->controlSuccessor =
822                   parentConstruct->constructExit;
823               lastConstructStmtEvaluation = nullptr;
824             }
825           },
826           [&](const parser::SelectRankStmt &s) {
827             insertConstructName(s, parentConstruct);
828           },
829           [&](const parser::SelectRankCaseStmt &) { eval.isNewBlock = true; },
830           [&](const parser::SelectTypeStmt &s) {
831             insertConstructName(s, parentConstruct);
832           },
833           [&](const parser::TypeGuardStmt &) { eval.isNewBlock = true; },
834 
835           // Constructs - set (unstructured) construct exit targets
836           [&](const parser::AssociateConstruct &) { setConstructExit(eval); },
837           [&](const parser::BlockConstruct &) {
838             // EndBlockStmt may have code.
839             eval.constructExit = &eval.evaluationList->back();
840           },
841           [&](const parser::CaseConstruct &) {
842             setConstructExit(eval);
843             eval.isUnstructured = true;
844           },
845           [&](const parser::ChangeTeamConstruct &) {
846             // EndChangeTeamStmt may have code.
847             eval.constructExit = &eval.evaluationList->back();
848           },
849           [&](const parser::CriticalConstruct &) {
850             // EndCriticalStmt may have code.
851             eval.constructExit = &eval.evaluationList->back();
852           },
853           [&](const parser::DoConstruct &) { setConstructExit(eval); },
854           [&](const parser::IfConstruct &) { setConstructExit(eval); },
855           [&](const parser::SelectRankConstruct &) {
856             setConstructExit(eval);
857             eval.isUnstructured = true;
858           },
859           [&](const parser::SelectTypeConstruct &) {
860             setConstructExit(eval);
861             eval.isUnstructured = true;
862           },
863 
864           // Default - Common analysis for I/O statements; otherwise nop.
865           [&](const auto &stmt) {
866             using A = std::decay_t<decltype(stmt)>;
867             using IoStmts = std::tuple<
868                 parser::BackspaceStmt, parser::CloseStmt, parser::EndfileStmt,
869                 parser::FlushStmt, parser::InquireStmt, parser::OpenStmt,
870                 parser::PrintStmt, parser::ReadStmt, parser::RewindStmt,
871                 parser::WaitStmt, parser::WriteStmt>;
872             if constexpr (common::HasMember<A, IoStmts>)
873               analyzeIoBranches(eval, stmt);
874           },
875       });
876 
877       // Analyze construct evaluations.
878       if (eval.evaluationList)
879         analyzeBranches(&eval, *eval.evaluationList);
880 
881       // Set the successor of the last statement in an IF or SELECT block.
882       if (!eval.controlSuccessor && eval.lexicalSuccessor &&
883           eval.lexicalSuccessor->isIntermediateConstructStmt()) {
884         eval.controlSuccessor = parentConstruct->constructExit;
885         eval.lexicalSuccessor->isNewBlock = true;
886       }
887 
888       // Propagate isUnstructured flag to enclosing construct.
889       if (parentConstruct && eval.isUnstructured)
890         parentConstruct->isUnstructured = true;
891 
892       // The successor of a branch starts a new block.
893       if (eval.controlSuccessor && eval.isActionStmt() &&
894           eval.lowerAsUnstructured())
895         markSuccessorAsNewBlock(eval);
896     }
897   }
898 
899   /// For multiple entry subprograms, build a list of the dummy arguments that
900   /// appear in some, but not all entry points.  For those that are functions,
901   /// also find one of the largest function results, since a single result
902   /// container holds the result for all entries.
903   void processEntryPoints() {
904     auto *unit = evaluationListStack.back()->front().getOwningProcedure();
905     int entryCount = unit->entryPointList.size();
906     if (entryCount == 1)
907       return;
908     llvm::DenseMap<semantics::Symbol *, int> dummyCountMap;
909     for (int entryIndex = 0; entryIndex < entryCount; ++entryIndex) {
910       unit->setActiveEntry(entryIndex);
911       const auto &details =
912           unit->getSubprogramSymbol().get<semantics::SubprogramDetails>();
913       for (auto *arg : details.dummyArgs()) {
914         if (!arg)
915           continue; // alternate return specifier (no actual argument)
916         const auto iter = dummyCountMap.find(arg);
917         if (iter == dummyCountMap.end())
918           dummyCountMap.try_emplace(arg, 1);
919         else
920           ++iter->second;
921       }
922       if (details.isFunction()) {
923         const auto *resultSym = &details.result();
924         assert(resultSym && "missing result symbol");
925         if (!unit->primaryResult ||
926             unit->primaryResult->size() < resultSym->size())
927           unit->primaryResult = resultSym;
928       }
929     }
930     unit->setActiveEntry(0);
931     for (auto arg : dummyCountMap)
932       if (arg.second < entryCount)
933         unit->nonUniversalDummyArguments.push_back(arg.first);
934   }
935 
936   std::unique_ptr<lower::pft::Program> pgm;
937   std::vector<lower::pft::PftNode> pftParentStack;
938   const semantics::SemanticsContext &semanticsContext;
939 
940   /// functionList points to the internal or module procedure function list
941   /// of a FunctionLikeUnit or a ModuleLikeUnit.  It may be null.
942   std::list<lower::pft::FunctionLikeUnit> *functionList{};
943   std::vector<lower::pft::Evaluation *> constructAndDirectiveStack{};
944   std::vector<lower::pft::Evaluation *> doConstructStack{};
945   /// evaluationListStack is the current nested construct evaluationList state.
946   std::vector<lower::pft::EvaluationList *> evaluationListStack{};
947   llvm::DenseMap<parser::Label, lower::pft::Evaluation *> *labelEvaluationMap{};
948   lower::pft::SymbolLabelMap *assignSymbolLabelMap{};
949   std::map<std::string, lower::pft::Evaluation *> constructNameMap{};
950   lower::pft::Evaluation *lastLexicalEvaluation{};
951 };
952 
953 class PFTDumper {
954 public:
955   void dumpPFT(llvm::raw_ostream &outputStream,
956                const lower::pft::Program &pft) {
957     for (auto &unit : pft.getUnits()) {
958       std::visit(common::visitors{
959                      [&](const lower::pft::BlockDataUnit &unit) {
960                        outputStream << getNodeIndex(unit) << " ";
961                        outputStream << "BlockData: ";
962                        outputStream << "\nEnd BlockData\n\n";
963                      },
964                      [&](const lower::pft::FunctionLikeUnit &func) {
965                        dumpFunctionLikeUnit(outputStream, func);
966                      },
967                      [&](const lower::pft::ModuleLikeUnit &unit) {
968                        dumpModuleLikeUnit(outputStream, unit);
969                      },
970                      [&](const lower::pft::CompilerDirectiveUnit &unit) {
971                        dumpCompilerDirectiveUnit(outputStream, unit);
972                      },
973                  },
974                  unit);
975     }
976   }
977 
978   llvm::StringRef evaluationName(const lower::pft::Evaluation &eval) {
979     return eval.visit([](const auto &parseTreeNode) {
980       return parser::ParseTreeDumper::GetNodeName(parseTreeNode);
981     });
982   }
983 
984   void dumpEvaluation(llvm::raw_ostream &outputStream,
985                       const lower::pft::Evaluation &eval,
986                       const std::string &indentString, int indent = 1) {
987     llvm::StringRef name = evaluationName(eval);
988     std::string bang = eval.isUnstructured ? "!" : "";
989     if (eval.isConstruct() || eval.isDirective()) {
990       outputStream << indentString << "<<" << name << bang << ">>";
991       if (eval.constructExit)
992         outputStream << " -> " << eval.constructExit->printIndex;
993       outputStream << '\n';
994       dumpEvaluationList(outputStream, *eval.evaluationList, indent + 1);
995       outputStream << indentString << "<<End " << name << bang << ">>\n";
996       return;
997     }
998     outputStream << indentString;
999     if (eval.printIndex)
1000       outputStream << eval.printIndex << ' ';
1001     if (eval.isNewBlock)
1002       outputStream << '^';
1003     outputStream << name << bang;
1004     if (eval.isActionStmt() || eval.isConstructStmt()) {
1005       if (eval.negateCondition)
1006         outputStream << " [negate]";
1007       if (eval.controlSuccessor)
1008         outputStream << " -> " << eval.controlSuccessor->printIndex;
1009     } else if (eval.isA<parser::EntryStmt>() && eval.lexicalSuccessor) {
1010       outputStream << " -> " << eval.lexicalSuccessor->printIndex;
1011     }
1012     if (!eval.position.empty())
1013       outputStream << ": " << eval.position.ToString();
1014     outputStream << '\n';
1015   }
1016 
1017   void dumpEvaluation(llvm::raw_ostream &ostream,
1018                       const lower::pft::Evaluation &eval) {
1019     dumpEvaluation(ostream, eval, "");
1020   }
1021 
1022   void dumpEvaluationList(llvm::raw_ostream &outputStream,
1023                           const lower::pft::EvaluationList &evaluationList,
1024                           int indent = 1) {
1025     static const auto white = "                                      ++"s;
1026     auto indentString = white.substr(0, indent * 2);
1027     for (const auto &eval : evaluationList)
1028       dumpEvaluation(outputStream, eval, indentString, indent);
1029   }
1030 
1031   void
1032   dumpFunctionLikeUnit(llvm::raw_ostream &outputStream,
1033                        const lower::pft::FunctionLikeUnit &functionLikeUnit) {
1034     outputStream << getNodeIndex(functionLikeUnit) << " ";
1035     llvm::StringRef unitKind;
1036     llvm::StringRef name;
1037     llvm::StringRef header;
1038     if (functionLikeUnit.beginStmt) {
1039       functionLikeUnit.beginStmt->visit(common::visitors{
1040           [&](const parser::Statement<parser::ProgramStmt> &stmt) {
1041             unitKind = "Program";
1042             name = toStringRef(stmt.statement.v.source);
1043           },
1044           [&](const parser::Statement<parser::FunctionStmt> &stmt) {
1045             unitKind = "Function";
1046             name = toStringRef(std::get<parser::Name>(stmt.statement.t).source);
1047             header = toStringRef(stmt.source);
1048           },
1049           [&](const parser::Statement<parser::SubroutineStmt> &stmt) {
1050             unitKind = "Subroutine";
1051             name = toStringRef(std::get<parser::Name>(stmt.statement.t).source);
1052             header = toStringRef(stmt.source);
1053           },
1054           [&](const parser::Statement<parser::MpSubprogramStmt> &stmt) {
1055             unitKind = "MpSubprogram";
1056             name = toStringRef(stmt.statement.v.source);
1057             header = toStringRef(stmt.source);
1058           },
1059           [&](const auto &) { llvm_unreachable("not a valid begin stmt"); },
1060       });
1061     } else {
1062       unitKind = "Program";
1063       name = "<anonymous>";
1064     }
1065     outputStream << unitKind << ' ' << name;
1066     if (!header.empty())
1067       outputStream << ": " << header;
1068     outputStream << '\n';
1069     dumpEvaluationList(outputStream, functionLikeUnit.evaluationList);
1070     if (!functionLikeUnit.nestedFunctions.empty()) {
1071       outputStream << "\nContains\n";
1072       for (auto &func : functionLikeUnit.nestedFunctions)
1073         dumpFunctionLikeUnit(outputStream, func);
1074       outputStream << "End Contains\n";
1075     }
1076     outputStream << "End " << unitKind << ' ' << name << "\n\n";
1077   }
1078 
1079   void dumpModuleLikeUnit(llvm::raw_ostream &outputStream,
1080                           const lower::pft::ModuleLikeUnit &moduleLikeUnit) {
1081     outputStream << getNodeIndex(moduleLikeUnit) << " ";
1082     outputStream << "ModuleLike: ";
1083     outputStream << "\nContains\n";
1084     for (auto &func : moduleLikeUnit.nestedFunctions)
1085       dumpFunctionLikeUnit(outputStream, func);
1086     outputStream << "End Contains\nEnd ModuleLike\n\n";
1087   }
1088 
1089   // Top level directives
1090   void dumpCompilerDirectiveUnit(
1091       llvm::raw_ostream &outputStream,
1092       const lower::pft::CompilerDirectiveUnit &directive) {
1093     outputStream << getNodeIndex(directive) << " ";
1094     outputStream << "CompilerDirective: !";
1095     outputStream << directive.get<Fortran::parser::CompilerDirective>()
1096                         .source.ToString();
1097     outputStream << "\nEnd CompilerDirective\n\n";
1098   }
1099 
1100   template <typename T>
1101   std::size_t getNodeIndex(const T &node) {
1102     auto addr = static_cast<const void *>(&node);
1103     auto it = nodeIndexes.find(addr);
1104     if (it != nodeIndexes.end())
1105       return it->second;
1106     nodeIndexes.try_emplace(addr, nextIndex);
1107     return nextIndex++;
1108   }
1109   std::size_t getNodeIndex(const lower::pft::Program &) { return 0; }
1110 
1111 private:
1112   llvm::DenseMap<const void *, std::size_t> nodeIndexes;
1113   std::size_t nextIndex{1}; // 0 is the root
1114 };
1115 
1116 } // namespace
1117 
1118 template <typename A, typename T>
1119 static lower::pft::FunctionLikeUnit::FunctionStatement
1120 getFunctionStmt(const T &func) {
1121   lower::pft::FunctionLikeUnit::FunctionStatement result{
1122       std::get<parser::Statement<A>>(func.t)};
1123   return result;
1124 }
1125 template <typename A, typename T>
1126 static lower::pft::ModuleLikeUnit::ModuleStatement getModuleStmt(const T &mod) {
1127   lower::pft::ModuleLikeUnit::ModuleStatement result{
1128       std::get<parser::Statement<A>>(mod.t)};
1129   return result;
1130 }
1131 
1132 template <typename A>
1133 static const semantics::Symbol *getSymbol(A &beginStmt) {
1134   const auto *symbol = beginStmt.visit(common::visitors{
1135       [](const parser::Statement<parser::ProgramStmt> &stmt)
1136           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1137       [](const parser::Statement<parser::FunctionStmt> &stmt)
1138           -> const semantics::Symbol * {
1139         return std::get<parser::Name>(stmt.statement.t).symbol;
1140       },
1141       [](const parser::Statement<parser::SubroutineStmt> &stmt)
1142           -> const semantics::Symbol * {
1143         return std::get<parser::Name>(stmt.statement.t).symbol;
1144       },
1145       [](const parser::Statement<parser::MpSubprogramStmt> &stmt)
1146           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1147       [](const parser::Statement<parser::ModuleStmt> &stmt)
1148           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1149       [](const parser::Statement<parser::SubmoduleStmt> &stmt)
1150           -> const semantics::Symbol * {
1151         return std::get<parser::Name>(stmt.statement.t).symbol;
1152       },
1153       [](const auto &) -> const semantics::Symbol * {
1154         llvm_unreachable("unknown FunctionLike or ModuleLike beginStmt");
1155         return nullptr;
1156       }});
1157   assert(symbol && "parser::Name must have resolved symbol");
1158   return symbol;
1159 }
1160 
1161 bool Fortran::lower::pft::Evaluation::lowerAsStructured() const {
1162   return !lowerAsUnstructured();
1163 }
1164 
1165 bool Fortran::lower::pft::Evaluation::lowerAsUnstructured() const {
1166   return isUnstructured || clDisableStructuredFir;
1167 }
1168 
1169 lower::pft::FunctionLikeUnit *
1170 Fortran::lower::pft::Evaluation::getOwningProcedure() const {
1171   return parent.visit(common::visitors{
1172       [](lower::pft::FunctionLikeUnit &c) { return &c; },
1173       [&](lower::pft::Evaluation &c) { return c.getOwningProcedure(); },
1174       [](auto &) -> lower::pft::FunctionLikeUnit * { return nullptr; },
1175   });
1176 }
1177 
1178 bool Fortran::lower::definedInCommonBlock(const semantics::Symbol &sym) {
1179   return semantics::FindCommonBlockContaining(sym);
1180 }
1181 
1182 /// Is the symbol `sym` a global?
1183 static bool symbolIsGlobal(const semantics::Symbol &sym) {
1184   if (const auto *details = sym.detailsIf<semantics::ObjectEntityDetails>())
1185     if (details->init())
1186       return true;
1187   return semantics::IsSaved(sym) || lower::definedInCommonBlock(sym);
1188 }
1189 
1190 namespace {
1191 /// This helper class is for sorting the symbols in the symbol table. We want
1192 /// the symbols in an order such that a symbol will be visited after those it
1193 /// depends upon. Otherwise this sort is stable and preserves the order of the
1194 /// symbol table, which is sorted by name.
1195 struct SymbolDependenceDepth {
1196   explicit SymbolDependenceDepth(
1197       std::vector<std::vector<lower::pft::Variable>> &vars, bool reentrant)
1198       : vars{vars}, reentrant{reentrant} {}
1199 
1200   void analyzeAliasesInCurrentScope(const semantics::Scope &scope) {
1201     for (const auto &iter : scope) {
1202       const auto &ultimate = iter.second.get().GetUltimate();
1203       if (skipSymbol(ultimate))
1204         continue;
1205       bool isDeclaration = scope != ultimate.owner();
1206       analyzeAliases(ultimate.owner(), isDeclaration);
1207     }
1208     // add all aggregate stores to the front of the work list
1209     adjustSize(1);
1210     // The copy in the loop matters, 'stores' will still be used.
1211     for (auto st : stores) {
1212       vars[0].emplace_back(std::move(st));
1213     }
1214   }
1215   // Analyze the equivalence sets. This analysis need not be performed when the
1216   // scope has no equivalence sets.
1217   void analyzeAliases(const semantics::Scope &scope, bool isDeclaration) {
1218     if (scope.equivalenceSets().empty())
1219       return;
1220     if (scopeAnlyzedForAliases.find(&scope) != scopeAnlyzedForAliases.end())
1221       return;
1222     scopeAnlyzedForAliases.insert(&scope);
1223     Fortran::lower::IntervalSet intervals;
1224     llvm::DenseMap<std::size_t, llvm::SmallVector<const semantics::Symbol *, 8>>
1225         aliasSets;
1226     llvm::DenseMap<std::size_t, const semantics::Symbol *> setIsGlobal;
1227 
1228     // 1. Construct the intervals. Determine each entity's interval, merging
1229     // overlapping intervals into aggregates.
1230     for (const auto &pair : scope) {
1231       const auto &sym = pair.second.get();
1232       if (skipSymbol(sym))
1233         continue;
1234       LLVM_DEBUG(llvm::dbgs() << "symbol: " << sym << '\n');
1235       intervals.merge(sym.offset(), sym.offset() + sym.size() - 1);
1236     }
1237 
1238     // 2. Compute alias sets. Adds each entity to a set for the interval it
1239     // appears to be mapped into.
1240     for (const auto &pair : scope) {
1241       const auto &sym = pair.second.get();
1242       if (skipSymbol(sym))
1243         continue;
1244       auto iter = intervals.find(sym.offset());
1245       if (iter != intervals.end()) {
1246         LLVM_DEBUG(llvm::dbgs()
1247                    << "symbol: " << toStringRef(sym.name()) << " on ["
1248                    << iter->first << ".." << iter->second << "]\n");
1249         aliasSets[iter->first].push_back(&sym);
1250         if (symbolIsGlobal(sym))
1251           setIsGlobal.insert({iter->first, &sym});
1252       }
1253     }
1254 
1255     // 3. For each alias set with more than 1 member, add an Interval to the
1256     // stores. The Interval will be lowered into a single memory allocation,
1257     // with the co-located, overlapping variables mapped into that memory range.
1258     for (const auto &pair : aliasSets) {
1259       if (pair.second.size() > 1) {
1260         // Set contains more than 1 aliasing variable.
1261         // 1. Mark the symbols as aliasing for lowering.
1262         for (auto *sym : pair.second)
1263           aliasSyms.insert(sym);
1264         auto gvarIter = setIsGlobal.find(pair.first);
1265         auto iter = intervals.find(pair.first);
1266         auto ibgn = iter->first;
1267         auto ilen = iter->second - ibgn + 1;
1268         // 2. Add an Interval to the list of stores allocated for this unit.
1269         lower::pft::Variable::Interval interval(ibgn, ilen);
1270         if (gvarIter != setIsGlobal.end()) {
1271           LLVM_DEBUG(llvm::dbgs()
1272                      << "interval [" << ibgn << ".." << ibgn + ilen
1273                      << ") added as global " << *gvarIter->second << '\n');
1274           stores.emplace_back(std::move(interval), scope, pair.second,
1275                               isDeclaration);
1276         } else {
1277           LLVM_DEBUG(llvm::dbgs() << "interval [" << ibgn << ".." << ibgn + ilen
1278                                   << ") added\n");
1279           stores.emplace_back(std::move(interval), scope, isDeclaration);
1280         }
1281       }
1282     }
1283   }
1284 
1285   // Recursively visit each symbol to determine the height of its dependence on
1286   // other symbols.
1287   int analyze(const semantics::Symbol &sym) {
1288     auto done = seen.insert(&sym);
1289     LLVM_DEBUG(llvm::dbgs() << "analyze symbol: " << sym << '\n');
1290     if (!done.second)
1291       return 0;
1292     if (semantics::IsProcedure(sym)) {
1293       // TODO: add declaration?
1294       return 0;
1295     }
1296     auto ultimate = sym.GetUltimate();
1297     if (!ultimate.has<semantics::ObjectEntityDetails>() &&
1298         !ultimate.has<semantics::ProcEntityDetails>())
1299       return 0;
1300 
1301     if (sym.has<semantics::DerivedTypeDetails>())
1302       llvm_unreachable("not yet implemented - derived type analysis");
1303 
1304     // Symbol must be something lowering will have to allocate.
1305     bool global = semantics::IsSaved(sym);
1306     int depth = 0;
1307     const auto *symTy = sym.GetType();
1308     assert(symTy && "symbol must have a type");
1309 
1310     // check CHARACTER's length
1311     if (symTy->category() == semantics::DeclTypeSpec::Character)
1312       if (auto e = symTy->characterTypeSpec().length().GetExplicit()) {
1313         // turn variable into a global if this unit is not reentrant
1314         global = global || !reentrant;
1315         for (const auto &s : evaluate::CollectSymbols(*e))
1316           depth = std::max(analyze(s) + 1, depth);
1317       }
1318 
1319     if (const auto *details = sym.detailsIf<semantics::ObjectEntityDetails>()) {
1320       auto doExplicit = [&](const auto &bound) {
1321         if (bound.isExplicit()) {
1322           semantics::SomeExpr e{*bound.GetExplicit()};
1323           for (const auto &s : evaluate::CollectSymbols(e))
1324             depth = std::max(analyze(s) + 1, depth);
1325         }
1326       };
1327       // handle any symbols in array bound declarations
1328       if (!details->shape().empty())
1329         global = global || !reentrant;
1330       for (const auto &subs : details->shape()) {
1331         doExplicit(subs.lbound());
1332         doExplicit(subs.ubound());
1333       }
1334       // handle any symbols in coarray bound declarations
1335       if (!details->coshape().empty())
1336         global = global || !reentrant;
1337       for (const auto &subs : details->coshape()) {
1338         doExplicit(subs.lbound());
1339         doExplicit(subs.ubound());
1340       }
1341       // handle any symbols in initialization expressions
1342       if (auto e = details->init()) {
1343         // A PARAMETER may not be marked as implicitly SAVE, so set the flag.
1344         global = true;
1345         for (const auto &s : evaluate::CollectSymbols(*e))
1346           depth = std::max(analyze(s) + 1, depth);
1347       }
1348     }
1349     adjustSize(depth + 1);
1350     vars[depth].emplace_back(sym, global, depth);
1351     if (semantics::IsAllocatable(sym))
1352       vars[depth].back().setHeapAlloc();
1353     if (semantics::IsPointer(sym))
1354       vars[depth].back().setPointer();
1355     if (ultimate.attrs().test(semantics::Attr::TARGET))
1356       vars[depth].back().setTarget();
1357 
1358     // If there are alias sets, then link the participating variables to their
1359     // aggregate stores when constructing the new variable on the list.
1360     if (auto *store = findStoreIfAlias(sym)) {
1361       vars[depth].back().setAlias(store->getOffset());
1362     }
1363     return depth;
1364   }
1365 
1366   /// Save the final list of variable allocations as a single vector and free
1367   /// the rest.
1368   void finalize() {
1369     for (int i = 1, end = vars.size(); i < end; ++i)
1370       vars[0].insert(vars[0].end(), vars[i].begin(), vars[i].end());
1371     vars.resize(1);
1372   }
1373 
1374   Fortran::lower::pft::Variable::AggregateStore *
1375   findStoreIfAlias(const Fortran::evaluate::Symbol &sym) {
1376     const auto &ultimate = sym.GetUltimate();
1377     const auto &scope = ultimate.owner();
1378     // Expect the total number of EQUIVALENCE sets to be small for a typical
1379     // Fortran program.
1380     if (aliasSyms.find(&ultimate) != aliasSyms.end()) {
1381       LLVM_DEBUG(llvm::dbgs() << "symbol: " << ultimate << '\n');
1382       LLVM_DEBUG(llvm::dbgs() << "scope: " << scope << '\n');
1383       auto off = ultimate.offset();
1384       for (auto &v : stores) {
1385         if (v.scope == &scope) {
1386           auto bot = std::get<0>(v.interval);
1387           if (off >= bot && off < bot + std::get<1>(v.interval))
1388             return &v;
1389         }
1390       }
1391       // clang-format off
1392       LLVM_DEBUG(
1393           llvm::dbgs() << "looking for " << off << "\n{\n";
1394           for (auto v : stores) {
1395             llvm::dbgs() << " in scope: " << v.scope << "\n";
1396             llvm::dbgs() << "  i = [" << std::get<0>(v.interval) << ".."
1397                 << std::get<0>(v.interval) + std::get<1>(v.interval)
1398                 << "]\n";
1399           }
1400           llvm::dbgs() << "}\n");
1401       // clang-format on
1402       llvm_unreachable("the store must be present");
1403     }
1404     return nullptr;
1405   }
1406 
1407 private:
1408   /// Skip symbol in alias analysis.
1409   bool skipSymbol(const semantics::Symbol &sym) {
1410     return !sym.has<semantics::ObjectEntityDetails>() ||
1411            lower::definedInCommonBlock(sym);
1412   }
1413 
1414   // Make sure the table is of appropriate size.
1415   void adjustSize(std::size_t size) {
1416     if (vars.size() < size)
1417       vars.resize(size);
1418   }
1419 
1420   llvm::SmallSet<const semantics::Symbol *, 32> seen;
1421   std::vector<std::vector<lower::pft::Variable>> &vars;
1422   llvm::SmallSet<const semantics::Symbol *, 32> aliasSyms;
1423   llvm::SmallSet<const semantics::Scope *, 4> scopeAnlyzedForAliases;
1424   std::vector<Fortran::lower::pft::Variable::AggregateStore> stores;
1425   bool reentrant;
1426 };
1427 } // namespace
1428 
1429 static void processSymbolTable(
1430     const semantics::Scope &scope,
1431     std::vector<std::vector<Fortran::lower::pft::Variable>> &varList,
1432     bool reentrant) {
1433   SymbolDependenceDepth sdd{varList, reentrant};
1434   sdd.analyzeAliasesInCurrentScope(scope);
1435   for (const auto &iter : scope)
1436     sdd.analyze(iter.second.get());
1437   sdd.finalize();
1438 }
1439 
1440 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1441     const parser::MainProgram &func, const lower::pft::PftNode &parent,
1442     const semantics::SemanticsContext &semanticsContext)
1443     : ProgramUnit{func, parent}, endStmt{
1444                                      getFunctionStmt<parser::EndProgramStmt>(
1445                                          func)} {
1446   const auto &programStmt =
1447       std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(func.t);
1448   if (programStmt.has_value()) {
1449     beginStmt = FunctionStatement(programStmt.value());
1450     const auto *symbol = getSymbol(*beginStmt);
1451     entryPointList[0].first = symbol;
1452     processSymbolTable(*symbol->scope(), varList, isRecursive());
1453   } else {
1454     processSymbolTable(
1455         semanticsContext.FindScope(
1456             std::get<parser::Statement<parser::EndProgramStmt>>(func.t).source),
1457         varList, isRecursive());
1458   }
1459 }
1460 
1461 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1462     const parser::FunctionSubprogram &func, const lower::pft::PftNode &parent,
1463     const semantics::SemanticsContext &)
1464     : ProgramUnit{func, parent},
1465       beginStmt{getFunctionStmt<parser::FunctionStmt>(func)},
1466       endStmt{getFunctionStmt<parser::EndFunctionStmt>(func)} {
1467   const auto *symbol = getSymbol(*beginStmt);
1468   entryPointList[0].first = symbol;
1469   processSymbolTable(*symbol->scope(), varList, isRecursive());
1470 }
1471 
1472 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1473     const parser::SubroutineSubprogram &func, const lower::pft::PftNode &parent,
1474     const semantics::SemanticsContext &)
1475     : ProgramUnit{func, parent},
1476       beginStmt{getFunctionStmt<parser::SubroutineStmt>(func)},
1477       endStmt{getFunctionStmt<parser::EndSubroutineStmt>(func)} {
1478   const auto *symbol = getSymbol(*beginStmt);
1479   entryPointList[0].first = symbol;
1480   processSymbolTable(*symbol->scope(), varList, isRecursive());
1481 }
1482 
1483 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1484     const parser::SeparateModuleSubprogram &func,
1485     const lower::pft::PftNode &parent, const semantics::SemanticsContext &)
1486     : ProgramUnit{func, parent},
1487       beginStmt{getFunctionStmt<parser::MpSubprogramStmt>(func)},
1488       endStmt{getFunctionStmt<parser::EndMpSubprogramStmt>(func)} {
1489   const auto *symbol = getSymbol(*beginStmt);
1490   entryPointList[0].first = symbol;
1491   processSymbolTable(*symbol->scope(), varList, isRecursive());
1492 }
1493 
1494 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit(
1495     const parser::Module &m, const lower::pft::PftNode &parent)
1496     : ProgramUnit{m, parent}, beginStmt{getModuleStmt<parser::ModuleStmt>(m)},
1497       endStmt{getModuleStmt<parser::EndModuleStmt>(m)} {
1498   const auto *symbol = getSymbol(beginStmt);
1499   processSymbolTable(*symbol->scope(), varList, /*reentrant=*/false);
1500 }
1501 
1502 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit(
1503     const parser::Submodule &m, const lower::pft::PftNode &parent)
1504     : ProgramUnit{m, parent}, beginStmt{getModuleStmt<parser::SubmoduleStmt>(
1505                                   m)},
1506       endStmt{getModuleStmt<parser::EndSubmoduleStmt>(m)} {
1507   const auto *symbol = getSymbol(beginStmt);
1508   processSymbolTable(*symbol->scope(), varList, /*reentrant=*/false);
1509 }
1510 
1511 Fortran::lower::pft::BlockDataUnit::BlockDataUnit(
1512     const parser::BlockData &bd, const lower::pft::PftNode &parent,
1513     const semantics::SemanticsContext &semanticsContext)
1514     : ProgramUnit{bd, parent},
1515       symTab{semanticsContext.FindScope(
1516           std::get<parser::Statement<parser::EndBlockDataStmt>>(bd.t).source)} {
1517 }
1518 
1519 std::unique_ptr<lower::pft::Program>
1520 Fortran::lower::createPFT(const parser::Program &root,
1521                           const semantics::SemanticsContext &semanticsContext) {
1522   PFTBuilder walker(semanticsContext);
1523   Walk(root, walker);
1524   return walker.result();
1525 }
1526 
1527 // FIXME: FlangDriver
1528 // This option should be integrated with the real driver as the default of
1529 // RECURSIVE vs. NON_RECURSIVE may be changed by other command line options,
1530 // etc., etc.
1531 bool Fortran::lower::defaultRecursiveFunctionSetting() {
1532   return !nonRecursiveProcedures;
1533 }
1534 
1535 void Fortran::lower::dumpPFT(llvm::raw_ostream &outputStream,
1536                              const lower::pft::Program &pft) {
1537   PFTDumper{}.dumpPFT(outputStream, pft);
1538 }
1539 
1540 void Fortran::lower::pft::Program::dump() const {
1541   dumpPFT(llvm::errs(), *this);
1542 }
1543 
1544 void Fortran::lower::pft::Evaluation::dump() const {
1545   PFTDumper{}.dumpEvaluation(llvm::errs(), *this);
1546 }
1547 
1548 void Fortran::lower::pft::Variable::dump() const {
1549   if (auto *s = std::get_if<Nominal>(&var)) {
1550     llvm::errs() << "symbol: " << s->symbol->name();
1551     llvm::errs() << " (depth: " << s->depth << ')';
1552     if (s->global)
1553       llvm::errs() << ", global";
1554     if (s->heapAlloc)
1555       llvm::errs() << ", allocatable";
1556     if (s->pointer)
1557       llvm::errs() << ", pointer";
1558     if (s->target)
1559       llvm::errs() << ", target";
1560     if (s->aliaser)
1561       llvm::errs() << ", equivalence(" << s->aliasOffset << ')';
1562   } else if (auto *s = std::get_if<AggregateStore>(&var)) {
1563     llvm::errs() << "interval[" << std::get<0>(s->interval) << ", "
1564                  << std::get<1>(s->interval) << "]:";
1565     if (s->isGlobal())
1566       llvm::errs() << ", global";
1567     if (s->vars.size()) {
1568       llvm::errs() << ", vars: {";
1569       llvm::interleaveComma(s->vars, llvm::errs(),
1570                             [](auto *y) { llvm::errs() << *y; });
1571       llvm::errs() << '}';
1572     }
1573   } else {
1574     llvm_unreachable("not a Variable");
1575   }
1576   llvm::errs() << '\n';
1577 }
1578 
1579 void Fortran::lower::pft::FunctionLikeUnit::dump() const {
1580   PFTDumper{}.dumpFunctionLikeUnit(llvm::errs(), *this);
1581 }
1582 
1583 void Fortran::lower::pft::ModuleLikeUnit::dump() const {
1584   PFTDumper{}.dumpModuleLikeUnit(llvm::errs(), *this);
1585 }
1586 
1587 /// The BlockDataUnit dump is just the associated symbol table.
1588 void Fortran::lower::pft::BlockDataUnit::dump() const {
1589   llvm::errs() << "block data {\n" << symTab << "\n}\n";
1590 }
1591