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