xref: /llvm-project/flang/lib/Lower/PFTBuilder.cpp (revision 87374a8cffb6b6f589e8810a4d8502623e9d0268)
1 //===-- PFTBuilder.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Lower/PFTBuilder.h"
10 #include "flang/Lower/IntervalSet.h"
11 #include "flang/Lower/Support/Utils.h"
12 #include "flang/Parser/dump-parse-tree.h"
13 #include "flang/Parser/parse-tree-visitor.h"
14 #include "flang/Semantics/semantics.h"
15 #include "flang/Semantics/tools.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include "llvm/ADT/IntervalMap.h"
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/Debug.h"
20 
21 #define DEBUG_TYPE "flang-pft"
22 
23 static llvm::cl::opt<bool> clDisableStructuredFir(
24     "no-structured-fir", llvm::cl::desc("disable generation of structured FIR"),
25     llvm::cl::init(false), llvm::cl::Hidden);
26 
27 using namespace Fortran;
28 
29 namespace {
30 /// Helpers to unveil parser node inside Fortran::parser::Statement<>,
31 /// Fortran::parser::UnlabeledStatement, and Fortran::common::Indirection<>
32 template <typename A>
33 struct RemoveIndirectionHelper {
34   using Type = A;
35 };
36 template <typename A>
37 struct RemoveIndirectionHelper<common::Indirection<A>> {
38   using Type = A;
39 };
40 
41 template <typename A>
42 struct UnwrapStmt {
43   static constexpr bool isStmt{false};
44 };
45 template <typename A>
46 struct UnwrapStmt<parser::Statement<A>> {
47   static constexpr bool isStmt{true};
48   using Type = typename RemoveIndirectionHelper<A>::Type;
49   constexpr UnwrapStmt(const parser::Statement<A> &a)
50       : unwrapped{removeIndirection(a.statement)}, position{a.source},
51         label{a.label} {}
52   const Type &unwrapped;
53   parser::CharBlock position;
54   std::optional<parser::Label> label;
55 };
56 template <typename A>
57 struct UnwrapStmt<parser::UnlabeledStatement<A>> {
58   static constexpr bool isStmt{true};
59   using Type = typename RemoveIndirectionHelper<A>::Type;
60   constexpr UnwrapStmt(const parser::UnlabeledStatement<A> &a)
61       : unwrapped{removeIndirection(a.statement)}, position{a.source} {}
62   const Type &unwrapped;
63   parser::CharBlock position;
64   std::optional<parser::Label> label;
65 };
66 
67 #ifndef NDEBUG
68 void dumpScope(const semantics::Scope *scope, int depth = -1);
69 #endif
70 
71 /// The instantiation of a parse tree visitor (Pre and Post) is extremely
72 /// expensive in terms of compile and link time. So one goal here is to
73 /// limit the bridge to one such instantiation.
74 class PFTBuilder {
75 public:
76   PFTBuilder(const semantics::SemanticsContext &semanticsContext)
77       : pgm{std::make_unique<lower::pft::Program>(
78             semanticsContext.GetCommonBlocks())},
79         semanticsContext{semanticsContext} {
80     lower::pft::PftNode pftRoot{*pgm.get()};
81     pftParentStack.push_back(pftRoot);
82   }
83 
84   /// Get the result
85   std::unique_ptr<lower::pft::Program> result() { return std::move(pgm); }
86 
87   template <typename A>
88   constexpr bool Pre(const A &a) {
89     if constexpr (lower::pft::isFunctionLike<A>) {
90       return enterFunction(a, semanticsContext);
91     } else if constexpr (lower::pft::isConstruct<A> ||
92                          lower::pft::isDirective<A>) {
93       return enterConstructOrDirective(a);
94     } else if constexpr (UnwrapStmt<A>::isStmt) {
95       using T = typename UnwrapStmt<A>::Type;
96       // Node "a" being visited has one of the following types:
97       // Statement<T>, Statement<Indirection<T>>, UnlabeledStatement<T>,
98       // or UnlabeledStatement<Indirection<T>>
99       auto stmt{UnwrapStmt<A>(a)};
100       if constexpr (lower::pft::isConstructStmt<T> ||
101                     lower::pft::isOtherStmt<T>) {
102         addEvaluation(lower::pft::Evaluation{
103             stmt.unwrapped, pftParentStack.back(), stmt.position, stmt.label});
104         return false;
105       } else if constexpr (std::is_same_v<T, parser::ActionStmt>) {
106         return std::visit(
107             common::visitors{
108                 [&](const common::Indirection<parser::CallStmt> &x) {
109                   addEvaluation(lower::pft::Evaluation{
110                       removeIndirection(x), pftParentStack.back(),
111                       stmt.position, stmt.label});
112                   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(std::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 std::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 std::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         std::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       std::visit(common::visitors{
1176                      [&](const lower::pft::BlockDataUnit &unit) {
1177                        outputStream << getNodeIndex(unit) << " ";
1178                        outputStream << "BlockData: ";
1179                        outputStream << "\nEnd BlockData\n\n";
1180                      },
1181                      [&](const lower::pft::FunctionLikeUnit &func) {
1182                        dumpFunctionLikeUnit(outputStream, func);
1183                      },
1184                      [&](const lower::pft::ModuleLikeUnit &unit) {
1185                        dumpModuleLikeUnit(outputStream, unit);
1186                      },
1187                      [&](const lower::pft::CompilerDirectiveUnit &unit) {
1188                        dumpCompilerDirectiveUnit(outputStream, unit);
1189                      },
1190                      [&](const lower::pft::OpenACCDirectiveUnit &unit) {
1191                        dumpOpenACCDirectiveUnit(outputStream, unit);
1192                      },
1193                  },
1194                  unit);
1195     }
1196   }
1197 
1198   llvm::StringRef evaluationName(const lower::pft::Evaluation &eval) {
1199     return eval.visit([](const auto &parseTreeNode) {
1200       return parser::ParseTreeDumper::GetNodeName(parseTreeNode);
1201     });
1202   }
1203 
1204   void dumpEvaluation(llvm::raw_ostream &outputStream,
1205                       const lower::pft::Evaluation &eval,
1206                       const std::string &indentString, int indent = 1) {
1207     llvm::StringRef name = evaluationName(eval);
1208     llvm::StringRef newBlock = eval.isNewBlock ? "^" : "";
1209     llvm::StringRef bang = eval.isUnstructured ? "!" : "";
1210     outputStream << indentString;
1211     if (eval.printIndex)
1212       outputStream << eval.printIndex << ' ';
1213     if (eval.hasNestedEvaluations())
1214       outputStream << "<<" << newBlock << name << bang << ">>";
1215     else
1216       outputStream << newBlock << name << bang;
1217     if (eval.negateCondition)
1218       outputStream << " [negate]";
1219     if (eval.constructExit)
1220       outputStream << " -> " << eval.constructExit->printIndex;
1221     else if (eval.controlSuccessor)
1222       outputStream << " -> " << eval.controlSuccessor->printIndex;
1223     else if (eval.isA<parser::EntryStmt>() && eval.lexicalSuccessor)
1224       outputStream << " -> " << eval.lexicalSuccessor->printIndex;
1225     bool extraNewline = false;
1226     if (!eval.position.empty())
1227       outputStream << ": " << eval.position.ToString();
1228     else if (auto *dir = eval.getIf<parser::CompilerDirective>()) {
1229       extraNewline = dir->source.ToString().back() == '\n';
1230       outputStream << ": !" << dir->source.ToString();
1231     }
1232     if (!extraNewline)
1233       outputStream << '\n';
1234     if (eval.hasNestedEvaluations()) {
1235       dumpEvaluationList(outputStream, *eval.evaluationList, indent + 1);
1236       outputStream << indentString << "<<End " << name << bang << ">>\n";
1237     }
1238   }
1239 
1240   void dumpEvaluation(llvm::raw_ostream &ostream,
1241                       const lower::pft::Evaluation &eval) {
1242     dumpEvaluation(ostream, eval, "");
1243   }
1244 
1245   void dumpEvaluationList(llvm::raw_ostream &outputStream,
1246                           const lower::pft::EvaluationList &evaluationList,
1247                           int indent = 1) {
1248     static const auto white = "                                      ++"s;
1249     auto indentString = white.substr(0, indent * 2);
1250     for (const lower::pft::Evaluation &eval : evaluationList)
1251       dumpEvaluation(outputStream, eval, indentString, indent);
1252   }
1253 
1254   void
1255   dumpFunctionLikeUnit(llvm::raw_ostream &outputStream,
1256                        const lower::pft::FunctionLikeUnit &functionLikeUnit) {
1257     outputStream << getNodeIndex(functionLikeUnit) << " ";
1258     llvm::StringRef unitKind;
1259     llvm::StringRef name;
1260     llvm::StringRef header;
1261     if (functionLikeUnit.beginStmt) {
1262       functionLikeUnit.beginStmt->visit(common::visitors{
1263           [&](const parser::Statement<parser::ProgramStmt> &stmt) {
1264             unitKind = "Program";
1265             name = toStringRef(stmt.statement.v.source);
1266           },
1267           [&](const parser::Statement<parser::FunctionStmt> &stmt) {
1268             unitKind = "Function";
1269             name = toStringRef(std::get<parser::Name>(stmt.statement.t).source);
1270             header = toStringRef(stmt.source);
1271           },
1272           [&](const parser::Statement<parser::SubroutineStmt> &stmt) {
1273             unitKind = "Subroutine";
1274             name = toStringRef(std::get<parser::Name>(stmt.statement.t).source);
1275             header = toStringRef(stmt.source);
1276           },
1277           [&](const parser::Statement<parser::MpSubprogramStmt> &stmt) {
1278             unitKind = "MpSubprogram";
1279             name = toStringRef(stmt.statement.v.source);
1280             header = toStringRef(stmt.source);
1281           },
1282           [&](const auto &) { llvm_unreachable("not a valid begin stmt"); },
1283       });
1284     } else {
1285       unitKind = "Program";
1286       name = "<anonymous>";
1287     }
1288     outputStream << unitKind << ' ' << name;
1289     if (!header.empty())
1290       outputStream << ": " << header;
1291     outputStream << '\n';
1292     dumpEvaluationList(outputStream, functionLikeUnit.evaluationList);
1293     dumpContainedUnitList(outputStream, functionLikeUnit.containedUnitList);
1294     outputStream << "End " << unitKind << ' ' << name << "\n\n";
1295   }
1296 
1297   void dumpModuleLikeUnit(llvm::raw_ostream &outputStream,
1298                           const lower::pft::ModuleLikeUnit &moduleLikeUnit) {
1299     outputStream << getNodeIndex(moduleLikeUnit) << " ";
1300     llvm::StringRef unitKind;
1301     llvm::StringRef name;
1302     llvm::StringRef header;
1303     moduleLikeUnit.beginStmt.visit(common::visitors{
1304         [&](const parser::Statement<parser::ModuleStmt> &stmt) {
1305           unitKind = "Module";
1306           name = toStringRef(stmt.statement.v.source);
1307           header = toStringRef(stmt.source);
1308         },
1309         [&](const parser::Statement<parser::SubmoduleStmt> &stmt) {
1310           unitKind = "Submodule";
1311           name = toStringRef(std::get<parser::Name>(stmt.statement.t).source);
1312           header = toStringRef(stmt.source);
1313         },
1314         [&](const auto &) {
1315           llvm_unreachable("not a valid module begin stmt");
1316         },
1317     });
1318     outputStream << unitKind << ' ' << name << ": " << header << '\n';
1319     dumpEvaluationList(outputStream, moduleLikeUnit.evaluationList);
1320     dumpContainedUnitList(outputStream, moduleLikeUnit.containedUnitList);
1321     outputStream << "End " << unitKind << ' ' << name << "\n\n";
1322   }
1323 
1324   // Top level directives
1325   void dumpCompilerDirectiveUnit(
1326       llvm::raw_ostream &outputStream,
1327       const lower::pft::CompilerDirectiveUnit &directive) {
1328     outputStream << getNodeIndex(directive) << " ";
1329     outputStream << "CompilerDirective: !";
1330     bool extraNewline =
1331         directive.get<parser::CompilerDirective>().source.ToString().back() ==
1332         '\n';
1333     outputStream
1334         << directive.get<parser::CompilerDirective>().source.ToString();
1335     if (!extraNewline)
1336       outputStream << "\n";
1337     outputStream << "\n";
1338   }
1339 
1340   void dumpContainedUnitList(
1341       llvm::raw_ostream &outputStream,
1342       const lower::pft::ContainedUnitList &containedUnitList) {
1343     if (containedUnitList.empty())
1344       return;
1345     outputStream << "\nContains\n";
1346     for (const lower::pft::ContainedUnit &unit : containedUnitList)
1347       if (const auto *func = std::get_if<lower::pft::FunctionLikeUnit>(&unit)) {
1348         dumpFunctionLikeUnit(outputStream, *func);
1349       } else if (const auto *dir =
1350                      std::get_if<lower::pft::CompilerDirectiveUnit>(&unit)) {
1351         outputStream << getNodeIndex(*dir) << " ";
1352         dumpEvaluation(outputStream,
1353                        lower::pft::Evaluation{
1354                            dir->get<parser::CompilerDirective>(), dir->parent});
1355         outputStream << "\n";
1356       }
1357     outputStream << "End Contains\n";
1358   }
1359 
1360   void
1361   dumpOpenACCDirectiveUnit(llvm::raw_ostream &outputStream,
1362                            const lower::pft::OpenACCDirectiveUnit &directive) {
1363     outputStream << getNodeIndex(directive) << " ";
1364     outputStream << "OpenACCDirective: !$acc ";
1365     outputStream
1366         << directive.get<parser::OpenACCRoutineConstruct>().source.ToString();
1367     outputStream << "\nEnd OpenACCDirective\n\n";
1368   }
1369 
1370   template <typename T>
1371   std::size_t getNodeIndex(const T &node) {
1372     auto addr = static_cast<const void *>(&node);
1373     auto it = nodeIndexes.find(addr);
1374     if (it != nodeIndexes.end())
1375       return it->second;
1376     nodeIndexes.try_emplace(addr, nextIndex);
1377     return nextIndex++;
1378   }
1379   std::size_t getNodeIndex(const lower::pft::Program &) { return 0; }
1380 
1381 private:
1382   llvm::DenseMap<const void *, std::size_t> nodeIndexes;
1383   std::size_t nextIndex{1}; // 0 is the root
1384 };
1385 
1386 } // namespace
1387 
1388 template <typename A, typename T>
1389 static lower::pft::FunctionLikeUnit::FunctionStatement
1390 getFunctionStmt(const T &func) {
1391   lower::pft::FunctionLikeUnit::FunctionStatement result{
1392       std::get<parser::Statement<A>>(func.t)};
1393   return result;
1394 }
1395 
1396 template <typename A, typename T>
1397 static lower::pft::ModuleLikeUnit::ModuleStatement getModuleStmt(const T &mod) {
1398   lower::pft::ModuleLikeUnit::ModuleStatement result{
1399       std::get<parser::Statement<A>>(mod.t)};
1400   return result;
1401 }
1402 
1403 template <typename A>
1404 static const semantics::Symbol *getSymbol(A &beginStmt) {
1405   const auto *symbol = beginStmt.visit(common::visitors{
1406       [](const parser::Statement<parser::ProgramStmt> &stmt)
1407           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1408       [](const parser::Statement<parser::FunctionStmt> &stmt)
1409           -> const semantics::Symbol * {
1410         return std::get<parser::Name>(stmt.statement.t).symbol;
1411       },
1412       [](const parser::Statement<parser::SubroutineStmt> &stmt)
1413           -> const semantics::Symbol * {
1414         return std::get<parser::Name>(stmt.statement.t).symbol;
1415       },
1416       [](const parser::Statement<parser::MpSubprogramStmt> &stmt)
1417           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1418       [](const parser::Statement<parser::ModuleStmt> &stmt)
1419           -> const semantics::Symbol * { return stmt.statement.v.symbol; },
1420       [](const parser::Statement<parser::SubmoduleStmt> &stmt)
1421           -> const semantics::Symbol * {
1422         return std::get<parser::Name>(stmt.statement.t).symbol;
1423       },
1424       [](const auto &) -> const semantics::Symbol * {
1425         llvm_unreachable("unknown FunctionLike or ModuleLike beginStmt");
1426         return nullptr;
1427       }});
1428   assert(symbol && "parser::Name must have resolved symbol");
1429   return symbol;
1430 }
1431 
1432 bool Fortran::lower::pft::Evaluation::lowerAsStructured() const {
1433   return !lowerAsUnstructured();
1434 }
1435 
1436 bool Fortran::lower::pft::Evaluation::lowerAsUnstructured() const {
1437   return isUnstructured || clDisableStructuredFir;
1438 }
1439 
1440 bool Fortran::lower::pft::Evaluation::forceAsUnstructured() const {
1441   return clDisableStructuredFir;
1442 }
1443 
1444 lower::pft::FunctionLikeUnit *
1445 Fortran::lower::pft::Evaluation::getOwningProcedure() const {
1446   return parent.visit(common::visitors{
1447       [](lower::pft::FunctionLikeUnit &c) { return &c; },
1448       [&](lower::pft::Evaluation &c) { return c.getOwningProcedure(); },
1449       [](auto &) -> lower::pft::FunctionLikeUnit * { return nullptr; },
1450   });
1451 }
1452 
1453 bool Fortran::lower::definedInCommonBlock(const semantics::Symbol &sym) {
1454   return semantics::FindCommonBlockContaining(sym);
1455 }
1456 
1457 /// Is the symbol `sym` a global?
1458 bool Fortran::lower::symbolIsGlobal(const semantics::Symbol &sym) {
1459   return semantics::IsSaved(sym) || lower::definedInCommonBlock(sym) ||
1460          semantics::IsNamedConstant(sym);
1461 }
1462 
1463 namespace {
1464 /// This helper class sorts the symbols in a scope such that a symbol will
1465 /// be placed after those it depends upon. Otherwise the sort is stable and
1466 /// preserves the order of the symbol table, which is sorted by name. This
1467 /// analysis may also be done for an individual symbol.
1468 struct SymbolDependenceAnalysis {
1469   explicit SymbolDependenceAnalysis(const semantics::Scope &scope) {
1470     analyzeEquivalenceSets(scope);
1471     for (const auto &iter : scope)
1472       analyze(iter.second.get());
1473     finalize();
1474   }
1475   explicit SymbolDependenceAnalysis(const semantics::Symbol &symbol) {
1476     analyzeEquivalenceSets(symbol.owner());
1477     analyze(symbol);
1478     finalize();
1479   }
1480   Fortran::lower::pft::VariableList getVariableList() {
1481     return std::move(layeredVarList[0]);
1482   }
1483 
1484 private:
1485   /// Analyze the equivalence sets defined in \p scope, plus the equivalence
1486   /// sets in host module, submodule, and procedure scopes that may define
1487   /// symbols referenced in \p scope. This analysis excludes equivalence sets
1488   /// involving common blocks, which are handled elsewhere.
1489   void analyzeEquivalenceSets(const semantics::Scope &scope) {
1490     // FIXME: When this function is called on the scope of an internal
1491     // procedure whose parent contains an EQUIVALENCE set and the internal
1492     // procedure uses variables from that EQUIVALENCE set, we end up creating
1493     // an AggregateStore for those variables unnecessarily.
1494 
1495     // A function defined in a [sub]module has no explicit USE of its ancestor
1496     // [sub]modules. Analyze those scopes here to accommodate references to
1497     // symbols in them.
1498     for (auto *scp = &scope.parent(); !scp->IsGlobal(); scp = &scp->parent())
1499       if (scp->kind() == Fortran::semantics::Scope::Kind::Module)
1500         analyzeLocalEquivalenceSets(*scp);
1501     // Analyze local, USEd, and host procedure scope equivalences.
1502     for (const auto &iter : scope) {
1503       const semantics::Symbol &ultimate = iter.second.get().GetUltimate();
1504       if (!skipSymbol(ultimate))
1505         analyzeLocalEquivalenceSets(ultimate.owner());
1506     }
1507     // Add all aggregate stores to the front of the variable list.
1508     adjustSize(1);
1509     // The copy in the loop matters, 'stores' will still be used.
1510     for (auto st : stores)
1511       layeredVarList[0].emplace_back(std::move(st));
1512   }
1513 
1514   /// Analyze the equivalence sets defined locally in \p scope that don't
1515   /// involve common blocks.
1516   void analyzeLocalEquivalenceSets(const semantics::Scope &scope) {
1517     if (scope.equivalenceSets().empty())
1518       return; // no equivalence sets to analyze
1519     if (analyzedScopes.contains(&scope))
1520       return; // equivalence sets already analyzed
1521 
1522     analyzedScopes.insert(&scope);
1523     std::list<std::list<semantics::SymbolRef>> aggregates =
1524         Fortran::semantics::GetStorageAssociations(scope);
1525     for (std::list<semantics::SymbolRef> aggregate : aggregates) {
1526       const Fortran::semantics::Symbol *aggregateSym = nullptr;
1527       bool isGlobal = false;
1528       const semantics::Symbol &first = *aggregate.front();
1529       // Exclude equivalence sets involving common blocks.
1530       // Those are handled in instantiateCommon.
1531       if (lower::definedInCommonBlock(first))
1532         continue;
1533       std::size_t start = first.offset();
1534       std::size_t end = first.offset() + first.size();
1535       const Fortran::semantics::Symbol *namingSym = nullptr;
1536       for (semantics::SymbolRef symRef : aggregate) {
1537         const semantics::Symbol &sym = *symRef;
1538         aliasSyms.insert(&sym);
1539         if (sym.test(Fortran::semantics::Symbol::Flag::CompilerCreated)) {
1540           aggregateSym = &sym;
1541         } else {
1542           isGlobal |= lower::symbolIsGlobal(sym);
1543           start = std::min(sym.offset(), start);
1544           end = std::max(sym.offset() + sym.size(), end);
1545           if (!namingSym || (sym.name() < namingSym->name()))
1546             namingSym = &sym;
1547         }
1548       }
1549       assert(namingSym && "must contain at least one user symbol");
1550       if (!aggregateSym) {
1551         stores.emplace_back(
1552             Fortran::lower::pft::Variable::Interval{start, end - start},
1553             *namingSym, isGlobal);
1554       } else {
1555         stores.emplace_back(*aggregateSym, *namingSym, isGlobal);
1556       }
1557     }
1558   }
1559 
1560   // Recursively visit each symbol to determine the height of its dependence on
1561   // other symbols.
1562   int analyze(const semantics::Symbol &sym) {
1563     auto done = seen.insert(&sym);
1564     if (!done.second)
1565       return 0;
1566     LLVM_DEBUG(llvm::dbgs() << "analyze symbol " << &sym << " in <"
1567                             << &sym.owner() << ">: " << sym << '\n');
1568     const bool isProcedurePointerOrDummy =
1569         semantics::IsProcedurePointer(sym) ||
1570         (semantics::IsProcedure(sym) && IsDummy(sym));
1571     // A procedure argument in a subprogram with multiple entry points might
1572     // need a layeredVarList entry to trigger creation of a symbol map entry
1573     // in some cases. Non-dummy procedures don't.
1574     if (semantics::IsProcedure(sym) && !isProcedurePointerOrDummy)
1575       return 0;
1576     // Derived type component symbols may be collected by "CollectSymbols"
1577     // below when processing something like "real :: x(derived%component)". The
1578     // symbol "component" has "ObjectEntityDetails", but it should not be
1579     // instantiated: it is part of "derived" that should be the only one to
1580     // be instantiated.
1581     if (sym.owner().IsDerivedType())
1582       return 0;
1583 
1584     semantics::Symbol ultimate = sym.GetUltimate();
1585     if (const auto *details =
1586             ultimate.detailsIf<semantics::NamelistDetails>()) {
1587       // handle namelist group symbols
1588       for (const semantics::SymbolRef &s : details->objects())
1589         analyze(s);
1590       return 0;
1591     }
1592     if (!ultimate.has<semantics::ObjectEntityDetails>() &&
1593         !isProcedurePointerOrDummy)
1594       return 0;
1595 
1596     if (sym.has<semantics::DerivedTypeDetails>())
1597       llvm_unreachable("not yet implemented - derived type analysis");
1598 
1599     // Symbol must be something lowering will have to allocate.
1600     int depth = 0;
1601     // Analyze symbols appearing in object entity specification expressions.
1602     // This ensures these symbols will be instantiated before the current one.
1603     // This is not done for object entities that are host associated because
1604     // they must be instantiated from the value of the host symbols.
1605     // (The specification expressions should not be re-evaluated.)
1606     if (const auto *details = sym.detailsIf<semantics::ObjectEntityDetails>()) {
1607       const semantics::DeclTypeSpec *symTy = sym.GetType();
1608       assert(symTy && "symbol must have a type");
1609       // check CHARACTER's length
1610       if (symTy->category() == semantics::DeclTypeSpec::Character)
1611         if (auto e = symTy->characterTypeSpec().length().GetExplicit())
1612           for (const auto &s : evaluate::CollectSymbols(*e))
1613             depth = std::max(analyze(s) + 1, depth);
1614 
1615       auto doExplicit = [&](const auto &bound) {
1616         if (bound.isExplicit()) {
1617           semantics::SomeExpr e{*bound.GetExplicit()};
1618           for (const auto &s : evaluate::CollectSymbols(e))
1619             depth = std::max(analyze(s) + 1, depth);
1620         }
1621       };
1622       // Handle any symbols in array bound declarations.
1623       for (const semantics::ShapeSpec &subs : details->shape()) {
1624         doExplicit(subs.lbound());
1625         doExplicit(subs.ubound());
1626       }
1627       // Handle any symbols in coarray bound declarations.
1628       for (const semantics::ShapeSpec &subs : details->coshape()) {
1629         doExplicit(subs.lbound());
1630         doExplicit(subs.ubound());
1631       }
1632       // Handle any symbols in initialization expressions.
1633       if (auto e = details->init())
1634         for (const auto &s : evaluate::CollectSymbols(*e))
1635           if (!s->has<semantics::DerivedTypeDetails>())
1636             depth = std::max(analyze(s) + 1, depth);
1637     }
1638 
1639     // Make sure cray pointer is instantiated even if it is not visible.
1640     if (ultimate.test(Fortran::semantics::Symbol::Flag::CrayPointee))
1641       depth = std::max(
1642           analyze(Fortran::semantics::GetCrayPointer(ultimate)) + 1, depth);
1643     adjustSize(depth + 1);
1644     bool global = lower::symbolIsGlobal(sym);
1645     layeredVarList[depth].emplace_back(sym, global, depth);
1646     if (semantics::IsAllocatable(sym))
1647       layeredVarList[depth].back().setHeapAlloc();
1648     if (semantics::IsPointer(sym))
1649       layeredVarList[depth].back().setPointer();
1650     if (ultimate.attrs().test(semantics::Attr::TARGET))
1651       layeredVarList[depth].back().setTarget();
1652 
1653     // If there are alias sets, then link the participating variables to their
1654     // aggregate stores when constructing the new variable on the list.
1655     if (lower::pft::Variable::AggregateStore *store = findStoreIfAlias(sym))
1656       layeredVarList[depth].back().setAlias(store->getOffset());
1657     return depth;
1658   }
1659 
1660   /// Skip symbol in alias analysis.
1661   bool skipSymbol(const semantics::Symbol &sym) {
1662     // Common block equivalences are largely managed by the front end.
1663     // Compiler generated symbols ('.' names) cannot be equivalenced.
1664     // FIXME: Equivalence code generation may need to be revisited.
1665     return !sym.has<semantics::ObjectEntityDetails>() ||
1666            lower::definedInCommonBlock(sym) || sym.name()[0] == '.';
1667   }
1668 
1669   // Make sure the table is of appropriate size.
1670   void adjustSize(std::size_t size) {
1671     if (layeredVarList.size() < size)
1672       layeredVarList.resize(size);
1673   }
1674 
1675   Fortran::lower::pft::Variable::AggregateStore *
1676   findStoreIfAlias(const Fortran::evaluate::Symbol &sym) {
1677     const semantics::Symbol &ultimate = sym.GetUltimate();
1678     const semantics::Scope &scope = ultimate.owner();
1679     // Expect the total number of EQUIVALENCE sets to be small for a typical
1680     // Fortran program.
1681     if (aliasSyms.contains(&ultimate)) {
1682       LLVM_DEBUG(llvm::dbgs() << "found aggregate containing " << &ultimate
1683                               << " " << ultimate.name() << " in <" << &scope
1684                               << "> " << scope.GetName() << '\n');
1685       std::size_t off = ultimate.offset();
1686       std::size_t symSize = ultimate.size();
1687       for (lower::pft::Variable::AggregateStore &v : stores) {
1688         if (&v.getOwningScope() == &scope) {
1689           auto intervalOff = std::get<0>(v.interval);
1690           auto intervalSize = std::get<1>(v.interval);
1691           if (off >= intervalOff && off < intervalOff + intervalSize)
1692             return &v;
1693           // Zero sized symbol in zero sized equivalence.
1694           if (off == intervalOff && symSize == 0)
1695             return &v;
1696         }
1697       }
1698       // clang-format off
1699       LLVM_DEBUG(
1700           llvm::dbgs() << "looking for " << off << "\n{\n";
1701           for (lower::pft::Variable::AggregateStore &v : stores) {
1702             llvm::dbgs() << " in scope: " << &v.getOwningScope() << "\n";
1703             llvm::dbgs() << "  i = [" << std::get<0>(v.interval) << ".."
1704                 << std::get<0>(v.interval) + std::get<1>(v.interval)
1705                 << "]\n";
1706           }
1707           llvm::dbgs() << "}\n");
1708       // clang-format on
1709       llvm_unreachable("the store must be present");
1710     }
1711     return nullptr;
1712   }
1713 
1714   /// Flatten the result VariableList.
1715   void finalize() {
1716     for (int i = 1, end = layeredVarList.size(); i < end; ++i)
1717       layeredVarList[0].insert(layeredVarList[0].end(),
1718                                layeredVarList[i].begin(),
1719                                layeredVarList[i].end());
1720   }
1721 
1722   llvm::SmallSet<const semantics::Symbol *, 32> seen;
1723   std::vector<Fortran::lower::pft::VariableList> layeredVarList;
1724   llvm::SmallSet<const semantics::Symbol *, 32> aliasSyms;
1725   /// Set of scopes that have been analyzed for aliases.
1726   llvm::SmallSet<const semantics::Scope *, 4> analyzedScopes;
1727   std::vector<Fortran::lower::pft::Variable::AggregateStore> stores;
1728 };
1729 } // namespace
1730 
1731 //===----------------------------------------------------------------------===//
1732 // FunctionLikeUnit implementation
1733 //===----------------------------------------------------------------------===//
1734 
1735 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1736     const parser::MainProgram &func, const lower::pft::PftNode &parent,
1737     const semantics::SemanticsContext &semanticsContext)
1738     : ProgramUnit{func, parent},
1739       endStmt{getFunctionStmt<parser::EndProgramStmt>(func)} {
1740   const auto &programStmt =
1741       std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(func.t);
1742   if (programStmt.has_value()) {
1743     beginStmt = FunctionStatement(programStmt.value());
1744     const semantics::Symbol *symbol = getSymbol(*beginStmt);
1745     entryPointList[0].first = symbol;
1746     scope = symbol->scope();
1747   } else {
1748     scope = &semanticsContext.FindScope(
1749         std::get<parser::Statement<parser::EndProgramStmt>>(func.t).source);
1750   }
1751 }
1752 
1753 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1754     const parser::FunctionSubprogram &func, const lower::pft::PftNode &parent,
1755     const semantics::SemanticsContext &)
1756     : ProgramUnit{func, parent},
1757       beginStmt{getFunctionStmt<parser::FunctionStmt>(func)},
1758       endStmt{getFunctionStmt<parser::EndFunctionStmt>(func)} {
1759   const semantics::Symbol *symbol = getSymbol(*beginStmt);
1760   entryPointList[0].first = symbol;
1761   scope = symbol->scope();
1762 }
1763 
1764 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1765     const parser::SubroutineSubprogram &func, const lower::pft::PftNode &parent,
1766     const semantics::SemanticsContext &)
1767     : ProgramUnit{func, parent},
1768       beginStmt{getFunctionStmt<parser::SubroutineStmt>(func)},
1769       endStmt{getFunctionStmt<parser::EndSubroutineStmt>(func)} {
1770   const semantics::Symbol *symbol = getSymbol(*beginStmt);
1771   entryPointList[0].first = symbol;
1772   scope = symbol->scope();
1773 }
1774 
1775 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1776     const parser::SeparateModuleSubprogram &func,
1777     const lower::pft::PftNode &parent, const semantics::SemanticsContext &)
1778     : ProgramUnit{func, parent},
1779       beginStmt{getFunctionStmt<parser::MpSubprogramStmt>(func)},
1780       endStmt{getFunctionStmt<parser::EndMpSubprogramStmt>(func)} {
1781   const semantics::Symbol *symbol = getSymbol(*beginStmt);
1782   entryPointList[0].first = symbol;
1783   scope = symbol->scope();
1784 }
1785 
1786 Fortran::lower::HostAssociations &
1787 Fortran::lower::pft::FunctionLikeUnit::parentHostAssoc() {
1788   if (auto *par = parent.getIf<FunctionLikeUnit>())
1789     return par->hostAssociations;
1790   llvm::report_fatal_error("parent is not a function");
1791 }
1792 
1793 bool Fortran::lower::pft::FunctionLikeUnit::parentHasTupleHostAssoc() {
1794   if (auto *par = parent.getIf<FunctionLikeUnit>())
1795     return par->hostAssociations.hasTupleAssociations();
1796   return false;
1797 }
1798 
1799 bool Fortran::lower::pft::FunctionLikeUnit::parentHasHostAssoc() {
1800   if (auto *par = parent.getIf<FunctionLikeUnit>())
1801     return !par->hostAssociations.empty();
1802   return false;
1803 }
1804 
1805 parser::CharBlock
1806 Fortran::lower::pft::FunctionLikeUnit::getStartingSourceLoc() const {
1807   if (beginStmt)
1808     return stmtSourceLoc(*beginStmt);
1809   return scope->sourceRange();
1810 }
1811 
1812 //===----------------------------------------------------------------------===//
1813 // ModuleLikeUnit implementation
1814 //===----------------------------------------------------------------------===//
1815 
1816 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit(
1817     const parser::Module &m, const lower::pft::PftNode &parent)
1818     : ProgramUnit{m, parent}, beginStmt{getModuleStmt<parser::ModuleStmt>(m)},
1819       endStmt{getModuleStmt<parser::EndModuleStmt>(m)} {}
1820 
1821 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit(
1822     const parser::Submodule &m, const lower::pft::PftNode &parent)
1823     : ProgramUnit{m, parent},
1824       beginStmt{getModuleStmt<parser::SubmoduleStmt>(m)},
1825       endStmt{getModuleStmt<parser::EndSubmoduleStmt>(m)} {}
1826 
1827 parser::CharBlock
1828 Fortran::lower::pft::ModuleLikeUnit::getStartingSourceLoc() const {
1829   return stmtSourceLoc(beginStmt);
1830 }
1831 const Fortran::semantics::Scope &
1832 Fortran::lower::pft::ModuleLikeUnit::getScope() const {
1833   const Fortran::semantics::Symbol *symbol = getSymbol(beginStmt);
1834   assert(symbol && symbol->scope() &&
1835          "Module statement must have a symbol with a scope");
1836   return *symbol->scope();
1837 }
1838 
1839 //===----------------------------------------------------------------------===//
1840 // BlockDataUnit implementation
1841 //===----------------------------------------------------------------------===//
1842 
1843 Fortran::lower::pft::BlockDataUnit::BlockDataUnit(
1844     const parser::BlockData &bd, const lower::pft::PftNode &parent,
1845     const semantics::SemanticsContext &semanticsContext)
1846     : ProgramUnit{bd, parent},
1847       symTab{semanticsContext.FindScope(
1848           std::get<parser::Statement<parser::EndBlockDataStmt>>(bd.t).source)} {
1849 }
1850 
1851 //===----------------------------------------------------------------------===//
1852 // Variable implementation
1853 //===----------------------------------------------------------------------===//
1854 
1855 bool Fortran::lower::pft::Variable::isRuntimeTypeInfoData() const {
1856   // So far, use flags to detect if this symbol were generated during
1857   // semantics::BuildRuntimeDerivedTypeTables(). Scope cannot be used since the
1858   // symbols are injected in the user scopes defining the described derived
1859   // types. A robustness improvement for this test could be to get hands on the
1860   // semantics::RuntimeDerivedTypeTables and to check if the symbol names
1861   // belongs to this structure.
1862   using Flags = Fortran::semantics::Symbol::Flag;
1863   const auto *nominal = std::get_if<Nominal>(&var);
1864   return nominal && nominal->symbol->test(Flags::CompilerCreated) &&
1865          nominal->symbol->test(Flags::ReadOnly);
1866 }
1867 
1868 //===----------------------------------------------------------------------===//
1869 // API implementation
1870 //===----------------------------------------------------------------------===//
1871 
1872 std::unique_ptr<lower::pft::Program>
1873 Fortran::lower::createPFT(const parser::Program &root,
1874                           const semantics::SemanticsContext &semanticsContext) {
1875   PFTBuilder walker(semanticsContext);
1876   Walk(root, walker);
1877   return walker.result();
1878 }
1879 
1880 void Fortran::lower::dumpPFT(llvm::raw_ostream &outputStream,
1881                              const lower::pft::Program &pft) {
1882   PFTDumper{}.dumpPFT(outputStream, pft);
1883 }
1884 
1885 void Fortran::lower::pft::Program::dump() const {
1886   dumpPFT(llvm::errs(), *this);
1887 }
1888 
1889 void Fortran::lower::pft::Evaluation::dump() const {
1890   PFTDumper{}.dumpEvaluation(llvm::errs(), *this);
1891 }
1892 
1893 void Fortran::lower::pft::Variable::dump() const {
1894   if (auto *s = std::get_if<Nominal>(&var)) {
1895     llvm::errs() << s->symbol << " " << *s->symbol;
1896     llvm::errs() << " (depth: " << s->depth << ')';
1897     if (s->global)
1898       llvm::errs() << ", global";
1899     if (s->heapAlloc)
1900       llvm::errs() << ", allocatable";
1901     if (s->pointer)
1902       llvm::errs() << ", pointer";
1903     if (s->target)
1904       llvm::errs() << ", target";
1905     if (s->aliaser)
1906       llvm::errs() << ", equivalence(" << s->aliasOffset << ')';
1907   } else if (auto *s = std::get_if<AggregateStore>(&var)) {
1908     llvm::errs() << "interval[" << std::get<0>(s->interval) << ", "
1909                  << std::get<1>(s->interval) << "]:";
1910     llvm::errs() << " name: " << toStringRef(s->getNamingSymbol().name());
1911     if (s->isGlobal())
1912       llvm::errs() << ", global";
1913     if (s->initialValueSymbol)
1914       llvm::errs() << ", initial value: {" << *s->initialValueSymbol << "}";
1915   } else {
1916     llvm_unreachable("not a Variable");
1917   }
1918   llvm::errs() << '\n';
1919 }
1920 
1921 void Fortran::lower::pft::dump(Fortran::lower::pft::VariableList &variableList,
1922                                std::string s) {
1923   llvm::errs() << (s.empty() ? "VariableList" : s) << " " << &variableList
1924                << " size=" << variableList.size() << "\n";
1925   for (auto var : variableList) {
1926     llvm::errs() << "  ";
1927     var.dump();
1928   }
1929 }
1930 
1931 void Fortran::lower::pft::FunctionLikeUnit::dump() const {
1932   PFTDumper{}.dumpFunctionLikeUnit(llvm::errs(), *this);
1933 }
1934 
1935 void Fortran::lower::pft::ModuleLikeUnit::dump() const {
1936   PFTDumper{}.dumpModuleLikeUnit(llvm::errs(), *this);
1937 }
1938 
1939 /// The BlockDataUnit dump is just the associated symbol table.
1940 void Fortran::lower::pft::BlockDataUnit::dump() const {
1941   llvm::errs() << "block data {\n" << symTab << "\n}\n";
1942 }
1943 
1944 /// Find or create an ordered list of equivalences and variables in \p scope.
1945 /// The result is cached in \p map.
1946 const lower::pft::VariableList &
1947 lower::pft::getScopeVariableList(const semantics::Scope &scope,
1948                                  ScopeVariableListMap &map) {
1949   LLVM_DEBUG(llvm::dbgs() << "\ngetScopeVariableList of [sub]module scope <"
1950                           << &scope << "> " << scope.GetName() << "\n");
1951   auto iter = map.find(&scope);
1952   if (iter == map.end()) {
1953     SymbolDependenceAnalysis sda(scope);
1954     map.emplace(&scope, sda.getVariableList());
1955     iter = map.find(&scope);
1956   }
1957   return iter->second;
1958 }
1959 
1960 /// Create an ordered list of equivalences and variables in \p scope.
1961 /// The result is not cached.
1962 lower::pft::VariableList
1963 lower::pft::getScopeVariableList(const semantics::Scope &scope) {
1964   LLVM_DEBUG(
1965       llvm::dbgs() << "\ngetScopeVariableList of [sub]program|block scope <"
1966                    << &scope << "> " << scope.GetName() << "\n");
1967   SymbolDependenceAnalysis sda(scope);
1968   return sda.getVariableList();
1969 }
1970 
1971 /// Create an ordered list of equivalences and variables that \p symbol
1972 /// depends on (no caching). Include \p symbol at the end of the list.
1973 lower::pft::VariableList
1974 lower::pft::getDependentVariableList(const semantics::Symbol &symbol) {
1975   LLVM_DEBUG(llvm::dbgs() << "\ngetDependentVariableList of " << &symbol
1976                           << " - " << symbol << "\n");
1977   SymbolDependenceAnalysis sda(symbol);
1978   return sda.getVariableList();
1979 }
1980 
1981 namespace {
1982 /// Helper class to find all the symbols referenced in a FunctionLikeUnit.
1983 /// It defines a parse tree visitor doing a deep visit in all nodes with
1984 /// symbols (including evaluate::Expr).
1985 struct SymbolVisitor {
1986   template <typename A>
1987   bool Pre(const A &x) {
1988     if constexpr (Fortran::parser::HasTypedExpr<A>::value)
1989       // Some parse tree Expr may legitimately be un-analyzed after semantics
1990       // (for instance PDT component initial value in the PDT definition body).
1991       if (const auto *expr = Fortran::semantics::GetExpr(nullptr, x))
1992         visitExpr(*expr);
1993     return true;
1994   }
1995 
1996   bool Pre(const Fortran::parser::Name &name) {
1997     if (const semantics::Symbol *symbol = name.symbol)
1998       visitSymbol(*symbol);
1999     return false;
2000   }
2001 
2002   template <typename T>
2003   void visitExpr(const Fortran::evaluate::Expr<T> &expr) {
2004     for (const semantics::Symbol &symbol :
2005          Fortran::evaluate::CollectSymbols(expr))
2006       visitSymbol(symbol);
2007   }
2008 
2009   void visitSymbol(const Fortran::semantics::Symbol &symbol) {
2010     callBack(symbol);
2011     // - Visit statement function body since it will be inlined in lowering.
2012     // - Visit function results specification expressions because allocations
2013     //   happens on the caller side.
2014     if (const auto *subprogramDetails =
2015             symbol.detailsIf<Fortran::semantics::SubprogramDetails>()) {
2016       if (const auto &maybeExpr = subprogramDetails->stmtFunction()) {
2017         visitExpr(*maybeExpr);
2018       } else {
2019         if (subprogramDetails->isFunction()) {
2020           // Visit result extents expressions that are explicit.
2021           const Fortran::semantics::Symbol &result =
2022               subprogramDetails->result();
2023           if (const auto *objectDetails =
2024                   result.detailsIf<Fortran::semantics::ObjectEntityDetails>())
2025             if (objectDetails->shape().IsExplicitShape())
2026               for (const Fortran::semantics::ShapeSpec &shapeSpec :
2027                    objectDetails->shape()) {
2028                 visitExpr(shapeSpec.lbound().GetExplicit().value());
2029                 visitExpr(shapeSpec.ubound().GetExplicit().value());
2030               }
2031         }
2032       }
2033     }
2034     if (Fortran::semantics::IsProcedure(symbol)) {
2035       if (auto dynamicType = Fortran::evaluate::DynamicType::From(symbol)) {
2036         // Visit result length specification expressions that are explicit.
2037         if (dynamicType->category() ==
2038             Fortran::common::TypeCategory::Character) {
2039           if (std::optional<Fortran::evaluate::ExtentExpr> length =
2040                   dynamicType->GetCharLength())
2041             visitExpr(*length);
2042         } else if (const Fortran::semantics::DerivedTypeSpec *derivedTypeSpec =
2043                        Fortran::evaluate::GetDerivedTypeSpec(dynamicType)) {
2044           for (const auto &[_, param] : derivedTypeSpec->parameters())
2045             if (const Fortran::semantics::MaybeIntExpr &expr =
2046                     param.GetExplicit())
2047               visitExpr(expr.value());
2048         }
2049       }
2050     }
2051     // - CrayPointer needs to be available whenever a CrayPointee is used.
2052     if (symbol.GetUltimate().test(
2053             Fortran::semantics::Symbol::Flag::CrayPointee))
2054       visitSymbol(Fortran::semantics::GetCrayPointer(symbol));
2055   }
2056 
2057   template <typename A>
2058   constexpr void Post(const A &) {}
2059 
2060   const std::function<void(const Fortran::semantics::Symbol &)> &callBack;
2061 };
2062 } // namespace
2063 
2064 void Fortran::lower::pft::visitAllSymbols(
2065     const Fortran::lower::pft::FunctionLikeUnit &funit,
2066     const std::function<void(const Fortran::semantics::Symbol &)> callBack) {
2067   SymbolVisitor visitor{callBack};
2068   funit.visit([&](const auto &functionParserNode) {
2069     parser::Walk(functionParserNode, visitor);
2070   });
2071 }
2072 
2073 void Fortran::lower::pft::visitAllSymbols(
2074     const Fortran::lower::pft::Evaluation &eval,
2075     const std::function<void(const Fortran::semantics::Symbol &)> callBack) {
2076   SymbolVisitor visitor{callBack};
2077   eval.visit([&](const auto &functionParserNode) {
2078     parser::Walk(functionParserNode, visitor);
2079   });
2080 }
2081