1 //===-- PFTBuilder.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
21 #define DEBUG_TYPE "flang-pft"
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
);
27 using namespace Fortran
;
30 /// Helpers to unveil parser node inside Fortran::parser::Statement<>,
31 /// Fortran::parser::UnlabeledStatement, and Fortran::common::Indirection<>
33 struct RemoveIndirectionHelper
{
37 struct RemoveIndirectionHelper
<common::Indirection
<A
>> {
43 static constexpr bool isStmt
{false};
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
},
52 const Type
&unwrapped
;
53 parser::CharBlock position
;
54 std::optional
<parser::Label
> label
;
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
;
68 void dumpScope(const semantics::Scope
*scope
, int depth
= -1);
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.
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
);
85 std::unique_ptr
<lower::pft::Program
> result() { return std::move(pgm
); }
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
});
105 } else if constexpr (std::is_same_v
<T
, parser::ActionStmt
>) {
106 return Fortran::common::visit(
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());
115 [&](const common::Indirection
<parser::IfStmt
> &x
) {
116 convertIfStmt(x
.value(), stmt
.position
, stmt
.label
);
120 addEvaluation(lower::pft::Evaluation
{
121 removeIndirection(x
), pftParentStack
.back(),
122 stmt
.position
, stmt
.label
});
132 /// Check for calls that could modify the floating point environment.
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
);
143 const Fortran::semantics::Symbol
&procSym
= callName
->symbol
->GetUltimate();
144 if (!procSym
.owner().IsModule())
146 const Fortran::semantics::Symbol
&modSym
= *procSym
.owner().symbol();
147 if (!modSym
.attrs().test(Fortran::semantics::Attr::INTRINSIC
))
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_"))
154 llvm::StringRef procName
= toStringRef(procSym
.name());
155 if (!procName
.starts_with("ieee_"))
157 lower::pft::FunctionLikeUnit
*proc
=
158 evaluationListStack
.back()->back().getOwningProcedure();
159 proc
->hasIeeeAccess
= true;
160 if (!procName
.starts_with("ieee_set_"))
162 if (procName
.starts_with("ieee_set_modes_") ||
163 procName
.starts_with("ieee_set_status_"))
164 proc
->mayModifyHaltingMode
= proc
->mayModifyRoundingMode
=
165 proc
->mayModifyUnderflowMode
= true;
166 else if (procName
.starts_with("ieee_set_halting_mode_"))
167 proc
->mayModifyHaltingMode
= true;
168 else if (procName
.starts_with("ieee_set_rounding_mode_"))
169 proc
->mayModifyRoundingMode
= true;
170 else if (procName
.starts_with("ieee_set_underflow_mode_"))
171 proc
->mayModifyUnderflowMode
= true;
174 /// Convert an IfStmt into an IfConstruct, retaining the IfStmt as the
175 /// first statement of the construct.
176 void convertIfStmt(const parser::IfStmt
&ifStmt
, parser::CharBlock position
,
177 std::optional
<parser::Label
> label
) {
178 // Generate a skeleton IfConstruct parse node. Its components are never
179 // referenced. The actual components are available via the IfConstruct
180 // evaluation's nested evaluationList, with the ifStmt in the position of
181 // the otherwise normal IfThenStmt. Caution: All other PFT nodes reference
182 // front end generated parse nodes; this is an exceptional case.
183 static const auto ifConstruct
= parser::IfConstruct
{
184 parser::Statement
<parser::IfThenStmt
>{
187 std::optional
<parser::Name
>{},
188 parser::ScalarLogicalExpr
{parser::LogicalExpr
{parser::Expr
{
189 parser::LiteralConstant
{parser::LogicalLiteralConstant
{
190 false, std::optional
<parser::KindParam
>{}}}}}}}},
191 parser::Block
{}, std::list
<parser::IfConstruct::ElseIfBlock
>{},
192 std::optional
<parser::IfConstruct::ElseBlock
>{},
193 parser::Statement
<parser::EndIfStmt
>{std::nullopt
,
194 parser::EndIfStmt
{std::nullopt
}}};
195 enterConstructOrDirective(ifConstruct
);
197 lower::pft::Evaluation
{ifStmt
, pftParentStack
.back(), position
, label
});
198 Pre(std::get
<parser::UnlabeledStatement
<parser::ActionStmt
>>(ifStmt
.t
));
199 static const auto endIfStmt
= parser::EndIfStmt
{std::nullopt
};
201 lower::pft::Evaluation
{endIfStmt
, pftParentStack
.back(), {}, {}});
202 exitConstructOrDirective();
205 template <typename A
>
206 constexpr void Post(const A
&) {
207 if constexpr (lower::pft::isFunctionLike
<A
>) {
209 } else if constexpr (lower::pft::isConstruct
<A
> ||
210 lower::pft::isDirective
<A
>) {
211 exitConstructOrDirective();
215 bool Pre(const parser::SpecificationPart
&) {
216 ++specificationPartLevel
;
219 void Post(const parser::SpecificationPart
&) { --specificationPartLevel
; }
221 bool Pre(const parser::ContainsStmt
&) {
222 if (!specificationPartLevel
) {
223 assert(containsStmtStack
.size() && "empty contains stack");
224 containsStmtStack
.back() = true;
230 bool Pre(const parser::Module
&node
) { return enterModule(node
); }
231 bool Pre(const parser::Submodule
&node
) { return enterModule(node
); }
233 void Post(const parser::Module
&) { exitModule(); }
234 void Post(const parser::Submodule
&) { exitModule(); }
237 bool Pre(const parser::BlockData
&node
) {
238 addUnit(lower::pft::BlockDataUnit
{node
, pftParentStack
.back(),
243 // Get rid of production wrapper
244 bool Pre(const parser::Statement
<parser::ForallAssignmentStmt
> &statement
) {
245 addEvaluation(Fortran::common::visit(
247 return lower::pft::Evaluation
{x
, pftParentStack
.back(),
248 statement
.source
, statement
.label
};
250 statement
.statement
.u
));
253 bool Pre(const parser::WhereBodyConstruct
&whereBody
) {
254 return Fortran::common::visit(
256 [&](const parser::Statement
<parser::AssignmentStmt
> &stmt
) {
257 // Not caught as other AssignmentStmt because it is not
258 // wrapped in a parser::ActionStmt.
259 addEvaluation(lower::pft::Evaluation
{stmt
.statement
,
260 pftParentStack
.back(),
261 stmt
.source
, stmt
.label
});
264 [&](const auto &) { return true; },
269 // A CompilerDirective may appear outside any program unit, after a module
270 // or function contains statement, or inside a module or function.
271 bool Pre(const parser::CompilerDirective
&directive
) {
272 assert(pftParentStack
.size() > 0 && "no program");
273 lower::pft::PftNode
&node
= pftParentStack
.back();
274 if (node
.isA
<lower::pft::Program
>()) {
275 addUnit(lower::pft::CompilerDirectiveUnit(directive
, node
));
277 } else if ((node
.isA
<lower::pft::ModuleLikeUnit
>() ||
278 node
.isA
<lower::pft::FunctionLikeUnit
>())) {
279 assert(containsStmtStack
.size() && "empty contains stack");
280 if (containsStmtStack
.back()) {
281 addContainedUnit(lower::pft::CompilerDirectiveUnit
{directive
, node
});
285 return enterConstructOrDirective(directive
);
288 bool Pre(const parser::OpenACCRoutineConstruct
&directive
) {
289 assert(pftParentStack
.size() > 0 &&
290 "At least the Program must be a parent");
291 if (pftParentStack
.back().isA
<lower::pft::Program
>()) {
293 lower::pft::OpenACCDirectiveUnit(directive
, pftParentStack
.back()));
296 return enterConstructOrDirective(directive
);
300 /// Initialize a new module-like unit and make it the builder's focus.
301 template <typename A
>
302 bool enterModule(const A
&mod
) {
303 lower::pft::ModuleLikeUnit
&unit
=
304 addUnit(lower::pft::ModuleLikeUnit
{mod
, pftParentStack
.back()});
305 containsStmtStack
.push_back(false);
306 containedUnitList
= &unit
.containedUnitList
;
307 pushEvaluationList(&unit
.evaluationList
);
308 pftParentStack
.emplace_back(unit
);
309 LLVM_DEBUG(dumpScope(&unit
.getScope()));
314 containsStmtStack
.pop_back();
315 if (!evaluationListStack
.empty())
317 pftParentStack
.pop_back();
318 resetFunctionState();
321 /// Add the end statement Evaluation of a sub/program to the PFT.
322 /// There may be intervening internal subprogram definitions between
323 /// prior statements and this end statement.
324 void endFunctionBody() {
325 if (evaluationListStack
.empty())
327 auto evaluationList
= evaluationListStack
.back();
328 if (evaluationList
->empty() || !evaluationList
->back().isEndStmt()) {
329 const auto &endStmt
=
330 pftParentStack
.back().get
<lower::pft::FunctionLikeUnit
>().endStmt
;
331 endStmt
.visit(common::visitors
{
332 [&](const parser::Statement
<parser::EndProgramStmt
> &s
) {
333 addEvaluation(lower::pft::Evaluation
{
334 s
.statement
, pftParentStack
.back(), s
.source
, s
.label
});
336 [&](const parser::Statement
<parser::EndFunctionStmt
> &s
) {
337 addEvaluation(lower::pft::Evaluation
{
338 s
.statement
, pftParentStack
.back(), s
.source
, s
.label
});
340 [&](const parser::Statement
<parser::EndSubroutineStmt
> &s
) {
341 addEvaluation(lower::pft::Evaluation
{
342 s
.statement
, pftParentStack
.back(), s
.source
, s
.label
});
344 [&](const parser::Statement
<parser::EndMpSubprogramStmt
> &s
) {
345 addEvaluation(lower::pft::Evaluation
{
346 s
.statement
, pftParentStack
.back(), s
.source
, s
.label
});
349 llvm::report_fatal_error("missing end statement or unexpected "
350 "begin statement reference");
354 lastLexicalEvaluation
= nullptr;
357 /// Pop the ModuleLikeUnit evaluationList when entering the first module
359 void cleanModuleEvaluationList() {
360 if (evaluationListStack
.empty())
362 if (pftParentStack
.back().isA
<lower::pft::ModuleLikeUnit
>())
366 /// Initialize a new function-like unit and make it the builder's focus.
367 template <typename A
>
368 bool enterFunction(const A
&func
,
369 const semantics::SemanticsContext
&semanticsContext
) {
370 cleanModuleEvaluationList();
371 endFunctionBody(); // enclosing host subprogram body, if any
372 lower::pft::FunctionLikeUnit
&unit
=
373 addContainedUnit(lower::pft::FunctionLikeUnit
{
374 func
, pftParentStack
.back(), semanticsContext
});
375 labelEvaluationMap
= &unit
.labelEvaluationMap
;
376 assignSymbolLabelMap
= &unit
.assignSymbolLabelMap
;
377 containsStmtStack
.push_back(false);
378 containedUnitList
= &unit
.containedUnitList
;
379 pushEvaluationList(&unit
.evaluationList
);
380 pftParentStack
.emplace_back(unit
);
381 LLVM_DEBUG(dumpScope(&unit
.getScope()));
385 void exitFunction() {
388 analyzeBranches(nullptr, *evaluationListStack
.back()); // add branch links
389 processEntryPoints();
390 containsStmtStack
.pop_back();
392 labelEvaluationMap
= nullptr;
393 assignSymbolLabelMap
= nullptr;
394 pftParentStack
.pop_back();
395 resetFunctionState();
398 /// Initialize a new construct or directive and make it the builder's focus.
399 template <typename A
>
400 bool enterConstructOrDirective(const A
&constructOrDirective
) {
401 lower::pft::Evaluation
&eval
= addEvaluation(
402 lower::pft::Evaluation
{constructOrDirective
, pftParentStack
.back()});
403 eval
.evaluationList
.reset(new lower::pft::EvaluationList
);
404 pushEvaluationList(eval
.evaluationList
.get());
405 pftParentStack
.emplace_back(eval
);
406 constructAndDirectiveStack
.emplace_back(&eval
);
410 void exitConstructOrDirective() {
411 auto isOpenMPLoopConstruct
= [](lower::pft::Evaluation
*eval
) {
412 if (const auto *ompConstruct
= eval
->getIf
<parser::OpenMPConstruct
>())
413 if (std::holds_alternative
<parser::OpenMPLoopConstruct
>(
420 auto *eval
= constructAndDirectiveStack
.back();
421 if (eval
->isExecutableDirective() && !isOpenMPLoopConstruct(eval
)) {
422 // A construct at the end of an (unstructured) OpenACC or OpenMP
423 // construct region must have an exit target inside the region.
424 // This is not applicable to the OpenMP loop construct since the
425 // end of the loop is an available target inside the region.
426 lower::pft::EvaluationList
&evaluationList
= *eval
->evaluationList
;
427 if (!evaluationList
.empty() && evaluationList
.back().isConstruct()) {
428 static const parser::ContinueStmt exitTarget
{};
430 lower::pft::Evaluation
{exitTarget
, pftParentStack
.back(), {}, {}});
434 pftParentStack
.pop_back();
435 constructAndDirectiveStack
.pop_back();
438 /// Reset function state to that of an enclosing host function.
439 void resetFunctionState() {
440 if (!pftParentStack
.empty()) {
441 pftParentStack
.back().visit(common::visitors
{
442 [&](lower::pft::ModuleLikeUnit
&p
) {
443 containedUnitList
= &p
.containedUnitList
;
445 [&](lower::pft::FunctionLikeUnit
&p
) {
446 containedUnitList
= &p
.containedUnitList
;
447 labelEvaluationMap
= &p
.labelEvaluationMap
;
448 assignSymbolLabelMap
= &p
.assignSymbolLabelMap
;
450 [&](auto &) { containedUnitList
= nullptr; },
455 template <typename A
>
456 A
&addUnit(A
&&unit
) {
457 pgm
->getUnits().emplace_back(std::move(unit
));
458 return std::get
<A
>(pgm
->getUnits().back());
461 template <typename A
>
462 A
&addContainedUnit(A
&&unit
) {
463 if (!containedUnitList
)
464 return addUnit(std::move(unit
));
465 containedUnitList
->emplace_back(std::move(unit
));
466 return std::get
<A
>(containedUnitList
->back());
469 // ActionStmt has a couple of non-conforming cases, explicitly handled here.
470 // The other cases use an Indirection, which are discarded in the PFT.
471 lower::pft::Evaluation
472 makeEvaluationAction(const parser::ActionStmt
&statement
,
473 parser::CharBlock position
,
474 std::optional
<parser::Label
> label
) {
475 return Fortran::common::visit(
478 return lower::pft::Evaluation
{
479 removeIndirection(x
), pftParentStack
.back(), position
, label
};
485 /// Append an Evaluation to the end of the current list.
486 lower::pft::Evaluation
&addEvaluation(lower::pft::Evaluation
&&eval
) {
487 assert(!evaluationListStack
.empty() && "empty evaluation list stack");
488 if (!constructAndDirectiveStack
.empty())
489 eval
.parentConstruct
= constructAndDirectiveStack
.back();
490 lower::pft::FunctionLikeUnit
*owningProcedure
= eval
.getOwningProcedure();
491 evaluationListStack
.back()->emplace_back(std::move(eval
));
492 lower::pft::Evaluation
*p
= &evaluationListStack
.back()->back();
493 if (p
->isActionStmt() || p
->isConstructStmt() || p
->isEndStmt() ||
494 p
->isExecutableDirective()) {
495 if (lastLexicalEvaluation
) {
496 lastLexicalEvaluation
->lexicalSuccessor
= p
;
497 p
->printIndex
= lastLexicalEvaluation
->printIndex
+ 1;
501 lastLexicalEvaluation
= p
;
502 if (owningProcedure
) {
503 auto &entryPointList
= owningProcedure
->entryPointList
;
504 for (std::size_t entryIndex
= entryPointList
.size() - 1;
505 entryIndex
&& !entryPointList
[entryIndex
].second
->lexicalSuccessor
;
507 // Link to the entry's first executable statement.
508 entryPointList
[entryIndex
].second
->lexicalSuccessor
= p
;
510 } else if (const auto *entryStmt
= p
->getIf
<parser::EntryStmt
>()) {
511 const semantics::Symbol
*sym
=
512 std::get
<parser::Name
>(entryStmt
->t
).symbol
;
513 if (auto *details
= sym
->detailsIf
<semantics::GenericDetails
>())
514 sym
= details
->specific();
515 assert(sym
->has
<semantics::SubprogramDetails
>() &&
516 "entry must be a subprogram");
517 owningProcedure
->entryPointList
.push_back(std::pair
{sym
, p
});
519 if (p
->label
.has_value())
520 labelEvaluationMap
->try_emplace(*p
->label
, p
);
521 return evaluationListStack
.back()->back();
524 /// push a new list on the stack of Evaluation lists
525 void pushEvaluationList(lower::pft::EvaluationList
*evaluationList
) {
526 assert(evaluationList
&& evaluationList
->empty() &&
527 "invalid evaluation list");
528 evaluationListStack
.emplace_back(evaluationList
);
531 /// pop the current list and return to the last Evaluation list
532 void popEvaluationList() {
533 assert(!evaluationListStack
.empty() &&
534 "trying to pop an empty evaluationListStack");
535 evaluationListStack
.pop_back();
538 /// Rewrite IfConstructs containing a GotoStmt or CycleStmt to eliminate an
539 /// unstructured branch and a trivial basic block. The pre-branch-analysis
543 /// 1 If[Then]Stmt: if(cond) goto L
544 /// 2 GotoStmt: goto L
546 /// <<End IfConstruct>>
549 /// 6 Statement: L ...
554 /// 1 If[Then]Stmt [negate]: if(cond) goto L
558 /// <<End IfConstruct>>
559 /// 6 Statement: L ...
561 /// The If[Then]Stmt condition is implicitly negated. It is not modified
562 /// in the PFT. It must be negated when generating FIR. The GotoStmt or
563 /// CycleStmt is deleted.
565 /// The transformation is only valid for forward branch targets at the same
566 /// construct nesting level as the IfConstruct. The result must not violate
567 /// construct nesting requirements or contain an EntryStmt. The result
568 /// is subject to normal un/structured code classification analysis. Except
569 /// for a branch to the EndIfStmt, the result is allowed to violate the F18
570 /// Clause 11.1.2.1 prohibition on transfer of control into the interior of
571 /// a construct block, as that does not compromise correct code generation.
572 /// When two transformation candidates overlap, at least one must be
573 /// disallowed. In such cases, the current heuristic favors simple code
574 /// generation, which happens to favor later candidates over earlier
575 /// candidates. That choice is probably not significant, but could be
577 void rewriteIfGotos() {
578 auto &evaluationList
= *evaluationListStack
.back();
579 if (!evaluationList
.size())
582 lower::pft::EvaluationList::iterator ifConstructIt
;
583 parser::Label ifTargetLabel
;
584 bool isCycleStmt
= false;
586 llvm::SmallVector
<T
> ifCandidateStack
;
588 evaluationList
.begin()->getIf
<parser::NonLabelDoStmt
>();
589 std::string doName
= doStmt
? getConstructName(*doStmt
) : std::string
{};
590 for (auto it
= evaluationList
.begin(), end
= evaluationList
.end();
593 if (eval
.isA
<parser::EntryStmt
>() || eval
.isIntermediateConstructStmt()) {
594 ifCandidateStack
.clear();
597 auto firstStmt
= [](lower::pft::Evaluation
*e
) {
598 return e
->isConstruct() ? &*e
->evaluationList
->begin() : e
;
600 const Fortran::lower::pft::Evaluation
&targetEval
= *firstStmt(&eval
);
601 bool targetEvalIsEndDoStmt
= targetEval
.isA
<parser::EndDoStmt
>();
602 auto branchTargetMatch
= [&]() {
603 if (const parser::Label targetLabel
=
604 ifCandidateStack
.back().ifTargetLabel
)
605 if (targetEval
.label
&& targetLabel
== *targetEval
.label
)
606 return true; // goto target match
607 if (targetEvalIsEndDoStmt
&& ifCandidateStack
.back().isCycleStmt
)
608 return true; // cycle target match
611 if (targetEval
.label
|| targetEvalIsEndDoStmt
) {
612 while (!ifCandidateStack
.empty() && branchTargetMatch()) {
613 lower::pft::EvaluationList::iterator ifConstructIt
=
614 ifCandidateStack
.back().ifConstructIt
;
615 lower::pft::EvaluationList::iterator successorIt
=
616 std::next(ifConstructIt
);
617 if (successorIt
!= it
) {
618 Fortran::lower::pft::EvaluationList
&ifBodyList
=
619 *ifConstructIt
->evaluationList
;
620 lower::pft::EvaluationList::iterator branchStmtIt
=
621 std::next(ifBodyList
.begin());
622 assert((branchStmtIt
->isA
<parser::GotoStmt
>() ||
623 branchStmtIt
->isA
<parser::CycleStmt
>()) &&
624 "expected goto or cycle statement");
625 ifBodyList
.erase(branchStmtIt
);
626 lower::pft::Evaluation
&ifStmt
= *ifBodyList
.begin();
627 ifStmt
.negateCondition
= true;
628 ifStmt
.lexicalSuccessor
= firstStmt(&*successorIt
);
629 lower::pft::EvaluationList::iterator endIfStmtIt
=
630 std::prev(ifBodyList
.end());
631 std::prev(it
)->lexicalSuccessor
= &*endIfStmtIt
;
632 endIfStmtIt
->lexicalSuccessor
= firstStmt(&*it
);
633 ifBodyList
.splice(endIfStmtIt
, evaluationList
, successorIt
, it
);
634 for (; successorIt
!= endIfStmtIt
; ++successorIt
)
635 successorIt
->parentConstruct
= &*ifConstructIt
;
637 ifCandidateStack
.pop_back();
640 if (eval
.isA
<parser::IfConstruct
>() && eval
.evaluationList
->size() == 3) {
641 const auto bodyEval
= std::next(eval
.evaluationList
->begin());
642 if (const auto *gotoStmt
= bodyEval
->getIf
<parser::GotoStmt
>()) {
643 if (!bodyEval
->lexicalSuccessor
->label
)
644 ifCandidateStack
.push_back({it
, gotoStmt
->v
});
646 if (const auto *cycleStmt
= bodyEval
->getIf
<parser::CycleStmt
>()) {
647 std::string cycleName
= getConstructName(*cycleStmt
);
648 if (cycleName
.empty() || cycleName
== doName
)
649 // This candidate will match doStmt's EndDoStmt.
650 ifCandidateStack
.push_back({it
, {}, true});
657 /// Mark IO statement ERR, EOR, and END specifier branch targets.
658 /// Mark an IO statement with an assigned format as unstructured.
659 template <typename A
>
660 void analyzeIoBranches(lower::pft::Evaluation
&eval
, const A
&stmt
) {
661 auto analyzeFormatSpec
= [&](const parser::Format
&format
) {
662 if (const auto *expr
= std::get_if
<parser::Expr
>(&format
.u
)) {
663 if (semantics::ExprHasTypeCategory(*semantics::GetExpr(*expr
),
664 common::TypeCategory::Integer
))
665 eval
.isUnstructured
= true;
668 auto analyzeSpecs
{[&](const auto &specList
) {
669 for (const auto &spec
: specList
) {
670 Fortran::common::visit(
671 Fortran::common::visitors
{
672 [&](const Fortran::parser::Format
&format
) {
673 analyzeFormatSpec(format
);
675 [&](const auto &label
) {
677 std::tuple
<parser::ErrLabel
, parser::EorLabel
,
679 if constexpr (common::HasMember
<decltype(label
), LabelNodes
>)
680 markBranchTarget(eval
, label
.v
);
687 std::tuple
<parser::BackspaceStmt
, parser::CloseStmt
,
688 parser::EndfileStmt
, parser::FlushStmt
, parser::OpenStmt
,
689 parser::RewindStmt
, parser::WaitStmt
>;
691 if constexpr (std::is_same_v
<A
, parser::ReadStmt
> ||
692 std::is_same_v
<A
, parser::WriteStmt
>) {
694 analyzeFormatSpec(*stmt
.format
);
695 analyzeSpecs(stmt
.controls
);
696 } else if constexpr (std::is_same_v
<A
, parser::PrintStmt
>) {
697 analyzeFormatSpec(std::get
<parser::Format
>(stmt
.t
));
698 } else if constexpr (std::is_same_v
<A
, parser::InquireStmt
>) {
699 if (const auto *specList
=
700 std::get_if
<std::list
<parser::InquireSpec
>>(&stmt
.u
))
701 analyzeSpecs(*specList
);
702 } else if constexpr (common::HasMember
<A
, OtherIOStmts
>) {
703 analyzeSpecs(stmt
.v
);
705 // Always crash if this is instantiated
706 static_assert(!std::is_same_v
<A
, parser::ReadStmt
>,
707 "Unexpected IO statement");
711 /// Set the exit of a construct, possibly from multiple enclosing constructs.
712 void setConstructExit(lower::pft::Evaluation
&eval
) {
713 eval
.constructExit
= &eval
.evaluationList
->back().nonNopSuccessor();
716 /// Mark the target of a branch as a new block.
717 void markBranchTarget(lower::pft::Evaluation
&sourceEvaluation
,
718 lower::pft::Evaluation
&targetEvaluation
) {
719 sourceEvaluation
.isUnstructured
= true;
720 if (!sourceEvaluation
.controlSuccessor
)
721 sourceEvaluation
.controlSuccessor
= &targetEvaluation
;
722 targetEvaluation
.isNewBlock
= true;
723 // If this is a branch into the body of a construct (usually illegal,
724 // but allowed in some legacy cases), then the targetEvaluation and its
725 // ancestors must be marked as unstructured.
726 lower::pft::Evaluation
*sourceConstruct
= sourceEvaluation
.parentConstruct
;
727 lower::pft::Evaluation
*targetConstruct
= targetEvaluation
.parentConstruct
;
728 if (targetConstruct
&&
729 &targetConstruct
->getFirstNestedEvaluation() == &targetEvaluation
)
730 // A branch to an initial constructStmt is a branch to the construct.
731 targetConstruct
= targetConstruct
->parentConstruct
;
732 if (targetConstruct
) {
733 while (sourceConstruct
&& sourceConstruct
!= targetConstruct
)
734 sourceConstruct
= sourceConstruct
->parentConstruct
;
735 if (sourceConstruct
!= targetConstruct
) // branch into a construct body
736 for (lower::pft::Evaluation
*eval
= &targetEvaluation
; eval
;
737 eval
= eval
->parentConstruct
) {
738 eval
->isUnstructured
= true;
739 // If the branch is a backward branch into an already analyzed
740 // DO or IF construct, mark the construct exit as a new block.
741 // For a forward branch, the isUnstructured flag will cause this
742 // to be done when the construct is analyzed.
743 if (eval
->constructExit
&& (eval
->isA
<parser::DoConstruct
>() ||
744 eval
->isA
<parser::IfConstruct
>()))
745 eval
->constructExit
->isNewBlock
= true;
749 void markBranchTarget(lower::pft::Evaluation
&sourceEvaluation
,
750 parser::Label label
) {
751 assert(label
&& "missing branch target label");
752 lower::pft::Evaluation
*targetEvaluation
{
753 labelEvaluationMap
->find(label
)->second
};
754 assert(targetEvaluation
&& "missing branch target evaluation");
755 markBranchTarget(sourceEvaluation
, *targetEvaluation
);
758 /// Mark the successor of an Evaluation as a new block.
759 void markSuccessorAsNewBlock(lower::pft::Evaluation
&eval
) {
760 eval
.nonNopSuccessor().isNewBlock
= true;
763 template <typename A
>
764 inline std::string
getConstructName(const A
&stmt
) {
765 using MaybeConstructNameWrapper
=
766 std::tuple
<parser::BlockStmt
, parser::CycleStmt
, parser::ElseStmt
,
767 parser::ElsewhereStmt
, parser::EndAssociateStmt
,
768 parser::EndBlockStmt
, parser::EndCriticalStmt
,
769 parser::EndDoStmt
, parser::EndForallStmt
, parser::EndIfStmt
,
770 parser::EndSelectStmt
, parser::EndWhereStmt
,
772 if constexpr (common::HasMember
<A
, MaybeConstructNameWrapper
>) {
774 return stmt
.v
->ToString();
777 using MaybeConstructNameInTuple
= std::tuple
<
778 parser::AssociateStmt
, parser::CaseStmt
, parser::ChangeTeamStmt
,
779 parser::CriticalStmt
, parser::ElseIfStmt
, parser::EndChangeTeamStmt
,
780 parser::ForallConstructStmt
, parser::IfThenStmt
, parser::LabelDoStmt
,
781 parser::MaskedElsewhereStmt
, parser::NonLabelDoStmt
,
782 parser::SelectCaseStmt
, parser::SelectRankCaseStmt
,
783 parser::TypeGuardStmt
, parser::WhereConstructStmt
>;
784 if constexpr (common::HasMember
<A
, MaybeConstructNameInTuple
>) {
785 if (auto name
= std::get
<std::optional
<parser::Name
>>(stmt
.t
))
786 return name
->ToString();
789 // These statements have multiple std::optional<parser::Name> elements.
790 if constexpr (std::is_same_v
<A
, parser::SelectRankStmt
> ||
791 std::is_same_v
<A
, parser::SelectTypeStmt
>) {
792 if (auto name
= std::get
<0>(stmt
.t
))
793 return name
->ToString();
799 /// \p parentConstruct can be null if this statement is at the highest
800 /// level of a program.
801 template <typename A
>
802 void insertConstructName(const A
&stmt
,
803 lower::pft::Evaluation
*parentConstruct
) {
804 std::string name
= getConstructName(stmt
);
806 constructNameMap
[name
] = parentConstruct
;
809 /// Insert branch links for a list of Evaluations.
810 /// \p parentConstruct can be null if the evaluationList contains the
811 /// top-level statements of a program.
812 void analyzeBranches(lower::pft::Evaluation
*parentConstruct
,
813 std::list
<lower::pft::Evaluation
> &evaluationList
) {
814 lower::pft::Evaluation
*lastConstructStmtEvaluation
{};
815 for (auto &eval
: evaluationList
) {
816 eval
.visit(common::visitors
{
817 // Action statements (except IO statements)
818 [&](const parser::CallStmt
&s
) {
819 // Look for alternate return specifiers.
821 std::get
<std::list
<parser::ActualArgSpec
>>(s
.call
.t
);
822 for (const auto &arg
: args
) {
823 const auto &actual
= std::get
<parser::ActualArg
>(arg
.t
);
824 if (const auto *altReturn
=
825 std::get_if
<parser::AltReturnSpec
>(&actual
.u
))
826 markBranchTarget(eval
, altReturn
->v
);
829 [&](const parser::CycleStmt
&s
) {
830 std::string name
= getConstructName(s
);
831 lower::pft::Evaluation
*construct
{name
.empty()
832 ? doConstructStack
.back()
833 : constructNameMap
[name
]};
834 assert(construct
&& "missing CYCLE construct");
835 markBranchTarget(eval
, construct
->evaluationList
->back());
837 [&](const parser::ExitStmt
&s
) {
838 std::string name
= getConstructName(s
);
839 lower::pft::Evaluation
*construct
{name
.empty()
840 ? doConstructStack
.back()
841 : constructNameMap
[name
]};
842 assert(construct
&& "missing EXIT construct");
843 markBranchTarget(eval
, *construct
->constructExit
);
845 [&](const parser::FailImageStmt
&) {
846 eval
.isUnstructured
= true;
847 if (eval
.lexicalSuccessor
->lexicalSuccessor
)
848 markSuccessorAsNewBlock(eval
);
850 [&](const parser::GotoStmt
&s
) { markBranchTarget(eval
, s
.v
); },
851 [&](const parser::IfStmt
&) {
852 eval
.lexicalSuccessor
->isNewBlock
= true;
853 lastConstructStmtEvaluation
= &eval
;
855 [&](const parser::ReturnStmt
&) {
856 eval
.isUnstructured
= true;
857 if (eval
.lexicalSuccessor
->lexicalSuccessor
)
858 markSuccessorAsNewBlock(eval
);
860 [&](const parser::StopStmt
&) {
861 eval
.isUnstructured
= true;
862 if (eval
.lexicalSuccessor
->lexicalSuccessor
)
863 markSuccessorAsNewBlock(eval
);
865 [&](const parser::ComputedGotoStmt
&s
) {
866 for (auto &label
: std::get
<std::list
<parser::Label
>>(s
.t
))
867 markBranchTarget(eval
, label
);
869 [&](const parser::ArithmeticIfStmt
&s
) {
870 markBranchTarget(eval
, std::get
<1>(s
.t
));
871 markBranchTarget(eval
, std::get
<2>(s
.t
));
872 markBranchTarget(eval
, std::get
<3>(s
.t
));
874 [&](const parser::AssignStmt
&s
) { // legacy label assignment
875 auto &label
= std::get
<parser::Label
>(s
.t
);
876 const auto *sym
= std::get
<parser::Name
>(s
.t
).symbol
;
877 assert(sym
&& "missing AssignStmt symbol");
878 lower::pft::Evaluation
*target
{
879 labelEvaluationMap
->find(label
)->second
};
880 assert(target
&& "missing branch target evaluation");
881 if (!target
->isA
<parser::FormatStmt
>())
882 target
->isNewBlock
= true;
883 auto iter
= assignSymbolLabelMap
->find(*sym
);
884 if (iter
== assignSymbolLabelMap
->end()) {
885 lower::pft::LabelSet labelSet
{};
886 labelSet
.insert(label
);
887 assignSymbolLabelMap
->try_emplace(*sym
, labelSet
);
889 iter
->second
.insert(label
);
892 [&](const parser::AssignedGotoStmt
&) {
893 // Although this statement is a branch, it doesn't have any
894 // explicit control successors. So the code at the end of the
895 // loop won't mark the successor. Do that here.
896 eval
.isUnstructured
= true;
897 markSuccessorAsNewBlock(eval
);
900 // The first executable statement after an EntryStmt is a new block.
901 [&](const parser::EntryStmt
&) {
902 eval
.lexicalSuccessor
->isNewBlock
= true;
905 // Construct statements
906 [&](const parser::AssociateStmt
&s
) {
907 insertConstructName(s
, parentConstruct
);
909 [&](const parser::BlockStmt
&s
) {
910 insertConstructName(s
, parentConstruct
);
912 [&](const parser::SelectCaseStmt
&s
) {
913 insertConstructName(s
, parentConstruct
);
914 lastConstructStmtEvaluation
= &eval
;
916 [&](const parser::CaseStmt
&) {
917 eval
.isNewBlock
= true;
918 lastConstructStmtEvaluation
->controlSuccessor
= &eval
;
919 lastConstructStmtEvaluation
= &eval
;
921 [&](const parser::EndSelectStmt
&) {
922 eval
.isNewBlock
= true;
923 lastConstructStmtEvaluation
= nullptr;
925 [&](const parser::ChangeTeamStmt
&s
) {
926 insertConstructName(s
, parentConstruct
);
928 [&](const parser::CriticalStmt
&s
) {
929 insertConstructName(s
, parentConstruct
);
931 [&](const parser::NonLabelDoStmt
&s
) {
932 insertConstructName(s
, parentConstruct
);
933 doConstructStack
.push_back(parentConstruct
);
934 const auto &loopControl
=
935 std::get
<std::optional
<parser::LoopControl
>>(s
.t
);
936 if (!loopControl
.has_value()) {
937 eval
.isUnstructured
= true; // infinite loop
940 eval
.nonNopSuccessor().isNewBlock
= true;
941 eval
.controlSuccessor
= &evaluationList
.back();
942 if (const auto *bounds
=
943 std::get_if
<parser::LoopControl::Bounds
>(&loopControl
->u
)) {
944 if (bounds
->name
.thing
.symbol
->GetType()->IsNumeric(
945 common::TypeCategory::Real
))
946 eval
.isUnstructured
= true; // real-valued loop control
947 } else if (std::get_if
<parser::ScalarLogicalExpr
>(
949 eval
.isUnstructured
= true; // while loop
952 [&](const parser::EndDoStmt
&) {
953 lower::pft::Evaluation
&doEval
= evaluationList
.front();
954 eval
.controlSuccessor
= &doEval
;
955 doConstructStack
.pop_back();
956 if (parentConstruct
->lowerAsStructured())
958 // The loop is unstructured, which wasn't known for all cases when
959 // visiting the NonLabelDoStmt.
960 parentConstruct
->constructExit
->isNewBlock
= true;
961 const auto &doStmt
= *doEval
.getIf
<parser::NonLabelDoStmt
>();
962 const auto &loopControl
=
963 std::get
<std::optional
<parser::LoopControl
>>(doStmt
.t
);
964 if (!loopControl
.has_value())
965 return; // infinite loop
966 if (const auto *concurrent
=
967 std::get_if
<parser::LoopControl::Concurrent
>(
969 // If there is a mask, the EndDoStmt starts a new block.
971 std::get
<parser::ConcurrentHeader
>(concurrent
->t
);
973 std::get
<std::optional
<parser::ScalarLogicalExpr
>>(header
.t
)
977 [&](const parser::IfThenStmt
&s
) {
978 insertConstructName(s
, parentConstruct
);
979 eval
.lexicalSuccessor
->isNewBlock
= true;
980 lastConstructStmtEvaluation
= &eval
;
982 [&](const parser::ElseIfStmt
&) {
983 eval
.isNewBlock
= true;
984 eval
.lexicalSuccessor
->isNewBlock
= true;
985 lastConstructStmtEvaluation
->controlSuccessor
= &eval
;
986 lastConstructStmtEvaluation
= &eval
;
988 [&](const parser::ElseStmt
&) {
989 eval
.isNewBlock
= true;
990 lastConstructStmtEvaluation
->controlSuccessor
= &eval
;
991 lastConstructStmtEvaluation
= nullptr;
993 [&](const parser::EndIfStmt
&) {
994 if (parentConstruct
->lowerAsUnstructured())
995 parentConstruct
->constructExit
->isNewBlock
= true;
996 if (lastConstructStmtEvaluation
) {
997 lastConstructStmtEvaluation
->controlSuccessor
=
998 parentConstruct
->constructExit
;
999 lastConstructStmtEvaluation
= nullptr;
1002 [&](const parser::SelectRankStmt
&s
) {
1003 insertConstructName(s
, parentConstruct
);
1004 lastConstructStmtEvaluation
= &eval
;
1006 [&](const parser::SelectRankCaseStmt
&) {
1007 eval
.isNewBlock
= true;
1008 lastConstructStmtEvaluation
->controlSuccessor
= &eval
;
1009 lastConstructStmtEvaluation
= &eval
;
1011 [&](const parser::SelectTypeStmt
&s
) {
1012 insertConstructName(s
, parentConstruct
);
1013 lastConstructStmtEvaluation
= &eval
;
1015 [&](const parser::TypeGuardStmt
&) {
1016 eval
.isNewBlock
= true;
1017 lastConstructStmtEvaluation
->controlSuccessor
= &eval
;
1018 lastConstructStmtEvaluation
= &eval
;
1021 // Constructs - set (unstructured) construct exit targets
1022 [&](const parser::AssociateConstruct
&) {
1023 eval
.constructExit
= &eval
.evaluationList
->back();
1025 [&](const parser::BlockConstruct
&) {
1026 eval
.constructExit
= &eval
.evaluationList
->back();
1028 [&](const parser::CaseConstruct
&) {
1029 eval
.constructExit
= &eval
.evaluationList
->back();
1030 eval
.isUnstructured
= true;
1032 [&](const parser::ChangeTeamConstruct
&) {
1033 eval
.constructExit
= &eval
.evaluationList
->back();
1035 [&](const parser::CriticalConstruct
&) {
1036 eval
.constructExit
= &eval
.evaluationList
->back();
1038 [&](const parser::DoConstruct
&) { setConstructExit(eval
); },
1039 [&](const parser::ForallConstruct
&) { setConstructExit(eval
); },
1040 [&](const parser::IfConstruct
&) { setConstructExit(eval
); },
1041 [&](const parser::SelectRankConstruct
&) {
1042 eval
.constructExit
= &eval
.evaluationList
->back();
1043 eval
.isUnstructured
= true;
1045 [&](const parser::SelectTypeConstruct
&) {
1046 eval
.constructExit
= &eval
.evaluationList
->back();
1047 eval
.isUnstructured
= true;
1049 [&](const parser::WhereConstruct
&) { setConstructExit(eval
); },
1051 // Default - Common analysis for IO statements; otherwise nop.
1052 [&](const auto &stmt
) {
1053 using A
= std::decay_t
<decltype(stmt
)>;
1054 using IoStmts
= std::tuple
<
1055 parser::BackspaceStmt
, parser::CloseStmt
, parser::EndfileStmt
,
1056 parser::FlushStmt
, parser::InquireStmt
, parser::OpenStmt
,
1057 parser::PrintStmt
, parser::ReadStmt
, parser::RewindStmt
,
1058 parser::WaitStmt
, parser::WriteStmt
>;
1059 if constexpr (common::HasMember
<A
, IoStmts
>)
1060 analyzeIoBranches(eval
, stmt
);
1064 // Analyze construct evaluations.
1065 if (eval
.evaluationList
)
1066 analyzeBranches(&eval
, *eval
.evaluationList
);
1068 // Propagate isUnstructured flag to enclosing construct.
1069 if (parentConstruct
&& eval
.isUnstructured
)
1070 parentConstruct
->isUnstructured
= true;
1072 // The successor of a branch starts a new block.
1073 if (eval
.controlSuccessor
&& eval
.isActionStmt() &&
1074 eval
.lowerAsUnstructured())
1075 markSuccessorAsNewBlock(eval
);
1079 /// Do processing specific to subprograms with multiple entry points.
1080 void processEntryPoints() {
1081 lower::pft::Evaluation
*initialEval
= &evaluationListStack
.back()->front();
1082 lower::pft::FunctionLikeUnit
*unit
= initialEval
->getOwningProcedure();
1083 int entryCount
= unit
->entryPointList
.size();
1084 if (entryCount
== 1)
1087 // The first executable statement in the subprogram is preceded by a
1088 // branch to the entry point, so it starts a new block.
1089 if (initialEval
->hasNestedEvaluations())
1090 initialEval
= &initialEval
->getFirstNestedEvaluation();
1091 else if (initialEval
->isA
<Fortran::parser::EntryStmt
>())
1092 initialEval
= initialEval
->lexicalSuccessor
;
1093 initialEval
->isNewBlock
= true;
1095 // All function entry points share a single result container.
1096 // Find one of the largest results.
1097 for (int entryIndex
= 0; entryIndex
< entryCount
; ++entryIndex
) {
1098 unit
->setActiveEntry(entryIndex
);
1099 const auto &details
=
1100 unit
->getSubprogramSymbol().get
<semantics::SubprogramDetails
>();
1101 if (details
.isFunction()) {
1102 const semantics::Symbol
*resultSym
= &details
.result();
1103 assert(resultSym
&& "missing result symbol");
1104 if (!unit
->primaryResult
||
1105 unit
->primaryResult
->size() < resultSym
->size())
1106 unit
->primaryResult
= resultSym
;
1109 unit
->setActiveEntry(0);
1112 std::unique_ptr
<lower::pft::Program
> pgm
;
1113 std::vector
<lower::pft::PftNode
> pftParentStack
;
1114 const semantics::SemanticsContext
&semanticsContext
;
1116 llvm::SmallVector
<bool> containsStmtStack
{};
1117 lower::pft::ContainedUnitList
*containedUnitList
{};
1118 std::vector
<lower::pft::Evaluation
*> constructAndDirectiveStack
{};
1119 std::vector
<lower::pft::Evaluation
*> doConstructStack
{};
1120 /// evaluationListStack is the current nested construct evaluationList state.
1121 std::vector
<lower::pft::EvaluationList
*> evaluationListStack
{};
1122 llvm::DenseMap
<parser::Label
, lower::pft::Evaluation
*> *labelEvaluationMap
{};
1123 lower::pft::SymbolLabelMap
*assignSymbolLabelMap
{};
1124 std::map
<std::string
, lower::pft::Evaluation
*> constructNameMap
{};
1125 int specificationPartLevel
{};
1126 lower::pft::Evaluation
*lastLexicalEvaluation
{};
1130 /// Dump all program scopes and symbols with addresses to disambiguate names.
1131 /// This is static, unchanging front end information, so dump it only once.
1132 void dumpScope(const semantics::Scope
*scope
, int depth
) {
1133 static int initialVisitCounter
= 0;
1135 if (++initialVisitCounter
!= 1)
1137 while (!scope
->IsGlobal())
1138 scope
= &scope
->parent();
1139 LLVM_DEBUG(llvm::dbgs() << "Full program scope information.\n"
1140 "Addresses in angle brackets are scopes. "
1141 "Unbracketed addresses are symbols.\n");
1143 static const std::string white
{" ++"};
1144 std::string w
= white
.substr(0, depth
* 2);
1146 LLVM_DEBUG(llvm::dbgs() << w
<< "<" << scope
<< "> ");
1147 if (auto *sym
{scope
->symbol()}) {
1148 LLVM_DEBUG(llvm::dbgs() << sym
<< " " << *sym
<< "\n");
1150 if (scope
->IsIntrinsicModules()) {
1151 LLVM_DEBUG(llvm::dbgs() << "IntrinsicModules (no detail)\n");
1154 if (scope
->kind() == Fortran::semantics::Scope::Kind::BlockConstruct
)
1155 LLVM_DEBUG(llvm::dbgs() << "[block]\n");
1157 LLVM_DEBUG(llvm::dbgs() << "[anonymous]\n");
1160 for (const auto &scp
: scope
->children())
1162 dumpScope(&scp
, depth
+ 1);
1163 for (auto iter
= scope
->begin(); iter
!= scope
->end(); ++iter
) {
1164 common::Reference
<semantics::Symbol
> sym
= iter
->second
;
1165 if (auto scp
= sym
->scope())
1166 dumpScope(scp
, depth
+ 1);
1168 LLVM_DEBUG(llvm::dbgs() << w
+ " " << &*sym
<< " " << *sym
<< "\n");
1175 void dumpPFT(llvm::raw_ostream
&outputStream
,
1176 const lower::pft::Program
&pft
) {
1177 for (auto &unit
: pft
.getUnits()) {
1178 Fortran::common::visit(
1180 [&](const lower::pft::BlockDataUnit
&unit
) {
1181 outputStream
<< getNodeIndex(unit
) << " ";
1182 outputStream
<< "BlockData: ";
1183 outputStream
<< "\nEnd BlockData\n\n";
1185 [&](const lower::pft::FunctionLikeUnit
&func
) {
1186 dumpFunctionLikeUnit(outputStream
, func
);
1188 [&](const lower::pft::ModuleLikeUnit
&unit
) {
1189 dumpModuleLikeUnit(outputStream
, unit
);
1191 [&](const lower::pft::CompilerDirectiveUnit
&unit
) {
1192 dumpCompilerDirectiveUnit(outputStream
, unit
);
1194 [&](const lower::pft::OpenACCDirectiveUnit
&unit
) {
1195 dumpOpenACCDirectiveUnit(outputStream
, unit
);
1202 llvm::StringRef
evaluationName(const lower::pft::Evaluation
&eval
) {
1203 return eval
.visit([](const auto &parseTreeNode
) {
1204 return parser::ParseTreeDumper::GetNodeName(parseTreeNode
);
1208 void dumpEvaluation(llvm::raw_ostream
&outputStream
,
1209 const lower::pft::Evaluation
&eval
,
1210 const std::string
&indentString
, int indent
= 1) {
1211 llvm::StringRef name
= evaluationName(eval
);
1212 llvm::StringRef newBlock
= eval
.isNewBlock
? "^" : "";
1213 llvm::StringRef bang
= eval
.isUnstructured
? "!" : "";
1214 outputStream
<< indentString
;
1215 if (eval
.printIndex
)
1216 outputStream
<< eval
.printIndex
<< ' ';
1217 if (eval
.hasNestedEvaluations())
1218 outputStream
<< "<<" << newBlock
<< name
<< bang
<< ">>";
1220 outputStream
<< newBlock
<< name
<< bang
;
1221 if (eval
.negateCondition
)
1222 outputStream
<< " [negate]";
1223 if (eval
.constructExit
)
1224 outputStream
<< " -> " << eval
.constructExit
->printIndex
;
1225 else if (eval
.controlSuccessor
)
1226 outputStream
<< " -> " << eval
.controlSuccessor
->printIndex
;
1227 else if (eval
.isA
<parser::EntryStmt
>() && eval
.lexicalSuccessor
)
1228 outputStream
<< " -> " << eval
.lexicalSuccessor
->printIndex
;
1229 bool extraNewline
= false;
1230 if (!eval
.position
.empty())
1231 outputStream
<< ": " << eval
.position
.ToString();
1232 else if (auto *dir
= eval
.getIf
<parser::CompilerDirective
>()) {
1233 extraNewline
= dir
->source
.ToString().back() == '\n';
1234 outputStream
<< ": !" << dir
->source
.ToString();
1237 outputStream
<< '\n';
1238 if (eval
.hasNestedEvaluations()) {
1239 dumpEvaluationList(outputStream
, *eval
.evaluationList
, indent
+ 1);
1240 outputStream
<< indentString
<< "<<End " << name
<< bang
<< ">>\n";
1244 void dumpEvaluation(llvm::raw_ostream
&ostream
,
1245 const lower::pft::Evaluation
&eval
) {
1246 dumpEvaluation(ostream
, eval
, "");
1249 void dumpEvaluationList(llvm::raw_ostream
&outputStream
,
1250 const lower::pft::EvaluationList
&evaluationList
,
1252 static const auto white
= " ++"s
;
1253 auto indentString
= white
.substr(0, indent
* 2);
1254 for (const lower::pft::Evaluation
&eval
: evaluationList
)
1255 dumpEvaluation(outputStream
, eval
, indentString
, indent
);
1259 dumpFunctionLikeUnit(llvm::raw_ostream
&outputStream
,
1260 const lower::pft::FunctionLikeUnit
&functionLikeUnit
) {
1261 outputStream
<< getNodeIndex(functionLikeUnit
) << " ";
1262 llvm::StringRef unitKind
;
1263 llvm::StringRef name
;
1264 llvm::StringRef header
;
1265 if (functionLikeUnit
.beginStmt
) {
1266 functionLikeUnit
.beginStmt
->visit(common::visitors
{
1267 [&](const parser::Statement
<parser::ProgramStmt
> &stmt
) {
1268 unitKind
= "Program";
1269 name
= toStringRef(stmt
.statement
.v
.source
);
1271 [&](const parser::Statement
<parser::FunctionStmt
> &stmt
) {
1272 unitKind
= "Function";
1273 name
= toStringRef(std::get
<parser::Name
>(stmt
.statement
.t
).source
);
1274 header
= toStringRef(stmt
.source
);
1276 [&](const parser::Statement
<parser::SubroutineStmt
> &stmt
) {
1277 unitKind
= "Subroutine";
1278 name
= toStringRef(std::get
<parser::Name
>(stmt
.statement
.t
).source
);
1279 header
= toStringRef(stmt
.source
);
1281 [&](const parser::Statement
<parser::MpSubprogramStmt
> &stmt
) {
1282 unitKind
= "MpSubprogram";
1283 name
= toStringRef(stmt
.statement
.v
.source
);
1284 header
= toStringRef(stmt
.source
);
1286 [&](const auto &) { llvm_unreachable("not a valid begin stmt"); },
1289 unitKind
= "Program";
1290 name
= "<anonymous>";
1292 outputStream
<< unitKind
<< ' ' << name
;
1293 if (!header
.empty())
1294 outputStream
<< ": " << header
;
1295 outputStream
<< '\n';
1296 dumpEvaluationList(outputStream
, functionLikeUnit
.evaluationList
);
1297 dumpContainedUnitList(outputStream
, functionLikeUnit
.containedUnitList
);
1298 outputStream
<< "End " << unitKind
<< ' ' << name
<< "\n\n";
1301 void dumpModuleLikeUnit(llvm::raw_ostream
&outputStream
,
1302 const lower::pft::ModuleLikeUnit
&moduleLikeUnit
) {
1303 outputStream
<< getNodeIndex(moduleLikeUnit
) << " ";
1304 llvm::StringRef unitKind
;
1305 llvm::StringRef name
;
1306 llvm::StringRef header
;
1307 moduleLikeUnit
.beginStmt
.visit(common::visitors
{
1308 [&](const parser::Statement
<parser::ModuleStmt
> &stmt
) {
1309 unitKind
= "Module";
1310 name
= toStringRef(stmt
.statement
.v
.source
);
1311 header
= toStringRef(stmt
.source
);
1313 [&](const parser::Statement
<parser::SubmoduleStmt
> &stmt
) {
1314 unitKind
= "Submodule";
1315 name
= toStringRef(std::get
<parser::Name
>(stmt
.statement
.t
).source
);
1316 header
= toStringRef(stmt
.source
);
1319 llvm_unreachable("not a valid module begin stmt");
1322 outputStream
<< unitKind
<< ' ' << name
<< ": " << header
<< '\n';
1323 dumpEvaluationList(outputStream
, moduleLikeUnit
.evaluationList
);
1324 dumpContainedUnitList(outputStream
, moduleLikeUnit
.containedUnitList
);
1325 outputStream
<< "End " << unitKind
<< ' ' << name
<< "\n\n";
1328 // Top level directives
1329 void dumpCompilerDirectiveUnit(
1330 llvm::raw_ostream
&outputStream
,
1331 const lower::pft::CompilerDirectiveUnit
&directive
) {
1332 outputStream
<< getNodeIndex(directive
) << " ";
1333 outputStream
<< "CompilerDirective: !";
1335 directive
.get
<parser::CompilerDirective
>().source
.ToString().back() ==
1338 << directive
.get
<parser::CompilerDirective
>().source
.ToString();
1340 outputStream
<< "\n";
1341 outputStream
<< "\n";
1344 void dumpContainedUnitList(
1345 llvm::raw_ostream
&outputStream
,
1346 const lower::pft::ContainedUnitList
&containedUnitList
) {
1347 if (containedUnitList
.empty())
1349 outputStream
<< "\nContains\n";
1350 for (const lower::pft::ContainedUnit
&unit
: containedUnitList
)
1351 if (const auto *func
= std::get_if
<lower::pft::FunctionLikeUnit
>(&unit
)) {
1352 dumpFunctionLikeUnit(outputStream
, *func
);
1353 } else if (const auto *dir
=
1354 std::get_if
<lower::pft::CompilerDirectiveUnit
>(&unit
)) {
1355 outputStream
<< getNodeIndex(*dir
) << " ";
1356 dumpEvaluation(outputStream
,
1357 lower::pft::Evaluation
{
1358 dir
->get
<parser::CompilerDirective
>(), dir
->parent
});
1359 outputStream
<< "\n";
1361 outputStream
<< "End Contains\n";
1365 dumpOpenACCDirectiveUnit(llvm::raw_ostream
&outputStream
,
1366 const lower::pft::OpenACCDirectiveUnit
&directive
) {
1367 outputStream
<< getNodeIndex(directive
) << " ";
1368 outputStream
<< "OpenACCDirective: !$acc ";
1370 << directive
.get
<parser::OpenACCRoutineConstruct
>().source
.ToString();
1371 outputStream
<< "\nEnd OpenACCDirective\n\n";
1374 template <typename T
>
1375 std::size_t getNodeIndex(const T
&node
) {
1376 auto addr
= static_cast<const void *>(&node
);
1377 auto it
= nodeIndexes
.find(addr
);
1378 if (it
!= nodeIndexes
.end())
1380 nodeIndexes
.try_emplace(addr
, nextIndex
);
1383 std::size_t getNodeIndex(const lower::pft::Program
&) { return 0; }
1386 llvm::DenseMap
<const void *, std::size_t> nodeIndexes
;
1387 std::size_t nextIndex
{1}; // 0 is the root
1392 template <typename A
, typename T
>
1393 static lower::pft::FunctionLikeUnit::FunctionStatement
1394 getFunctionStmt(const T
&func
) {
1395 lower::pft::FunctionLikeUnit::FunctionStatement result
{
1396 std::get
<parser::Statement
<A
>>(func
.t
)};
1400 template <typename A
, typename T
>
1401 static lower::pft::ModuleLikeUnit::ModuleStatement
getModuleStmt(const T
&mod
) {
1402 lower::pft::ModuleLikeUnit::ModuleStatement result
{
1403 std::get
<parser::Statement
<A
>>(mod
.t
)};
1407 template <typename A
>
1408 static const semantics::Symbol
*getSymbol(A
&beginStmt
) {
1409 const auto *symbol
= beginStmt
.visit(common::visitors
{
1410 [](const parser::Statement
<parser::ProgramStmt
> &stmt
)
1411 -> const semantics::Symbol
* { return stmt
.statement
.v
.symbol
; },
1412 [](const parser::Statement
<parser::FunctionStmt
> &stmt
)
1413 -> const semantics::Symbol
* {
1414 return std::get
<parser::Name
>(stmt
.statement
.t
).symbol
;
1416 [](const parser::Statement
<parser::SubroutineStmt
> &stmt
)
1417 -> const semantics::Symbol
* {
1418 return std::get
<parser::Name
>(stmt
.statement
.t
).symbol
;
1420 [](const parser::Statement
<parser::MpSubprogramStmt
> &stmt
)
1421 -> const semantics::Symbol
* { return stmt
.statement
.v
.symbol
; },
1422 [](const parser::Statement
<parser::ModuleStmt
> &stmt
)
1423 -> const semantics::Symbol
* { return stmt
.statement
.v
.symbol
; },
1424 [](const parser::Statement
<parser::SubmoduleStmt
> &stmt
)
1425 -> const semantics::Symbol
* {
1426 return std::get
<parser::Name
>(stmt
.statement
.t
).symbol
;
1428 [](const auto &) -> const semantics::Symbol
* {
1429 llvm_unreachable("unknown FunctionLike or ModuleLike beginStmt");
1432 assert(symbol
&& "parser::Name must have resolved symbol");
1436 bool Fortran::lower::pft::Evaluation::lowerAsStructured() const {
1437 return !lowerAsUnstructured();
1440 bool Fortran::lower::pft::Evaluation::lowerAsUnstructured() const {
1441 return isUnstructured
|| clDisableStructuredFir
;
1444 bool Fortran::lower::pft::Evaluation::forceAsUnstructured() const {
1445 return clDisableStructuredFir
;
1448 lower::pft::FunctionLikeUnit
*
1449 Fortran::lower::pft::Evaluation::getOwningProcedure() const {
1450 return parent
.visit(common::visitors
{
1451 [](lower::pft::FunctionLikeUnit
&c
) { return &c
; },
1452 [&](lower::pft::Evaluation
&c
) { return c
.getOwningProcedure(); },
1453 [](auto &) -> lower::pft::FunctionLikeUnit
* { return nullptr; },
1457 bool Fortran::lower::definedInCommonBlock(const semantics::Symbol
&sym
) {
1458 return semantics::FindCommonBlockContaining(sym
);
1461 /// Is the symbol `sym` a global?
1462 bool Fortran::lower::symbolIsGlobal(const semantics::Symbol
&sym
) {
1463 return semantics::IsSaved(sym
) || lower::definedInCommonBlock(sym
) ||
1464 semantics::IsNamedConstant(sym
);
1468 /// This helper class sorts the symbols in a scope such that a symbol will
1469 /// be placed after those it depends upon. Otherwise the sort is stable and
1470 /// preserves the order of the symbol table, which is sorted by name. This
1471 /// analysis may also be done for an individual symbol.
1472 struct SymbolDependenceAnalysis
{
1473 explicit SymbolDependenceAnalysis(const semantics::Scope
&scope
) {
1474 analyzeEquivalenceSets(scope
);
1475 for (const auto &iter
: scope
)
1476 analyze(iter
.second
.get());
1479 explicit SymbolDependenceAnalysis(const semantics::Symbol
&symbol
) {
1480 analyzeEquivalenceSets(symbol
.owner());
1484 Fortran::lower::pft::VariableList
getVariableList() {
1485 return std::move(layeredVarList
[0]);
1489 /// Analyze the equivalence sets defined in \p scope, plus the equivalence
1490 /// sets in host module, submodule, and procedure scopes that may define
1491 /// symbols referenced in \p scope. This analysis excludes equivalence sets
1492 /// involving common blocks, which are handled elsewhere.
1493 void analyzeEquivalenceSets(const semantics::Scope
&scope
) {
1494 // FIXME: When this function is called on the scope of an internal
1495 // procedure whose parent contains an EQUIVALENCE set and the internal
1496 // procedure uses variables from that EQUIVALENCE set, we end up creating
1497 // an AggregateStore for those variables unnecessarily.
1499 // A function defined in a [sub]module has no explicit USE of its ancestor
1500 // [sub]modules. Analyze those scopes here to accommodate references to
1502 for (auto *scp
= &scope
.parent(); !scp
->IsGlobal(); scp
= &scp
->parent())
1503 if (scp
->kind() == Fortran::semantics::Scope::Kind::Module
)
1504 analyzeLocalEquivalenceSets(*scp
);
1505 // Analyze local, USEd, and host procedure scope equivalences.
1506 for (const auto &iter
: scope
) {
1507 const semantics::Symbol
&ultimate
= iter
.second
.get().GetUltimate();
1508 if (!skipSymbol(ultimate
))
1509 analyzeLocalEquivalenceSets(ultimate
.owner());
1511 // Add all aggregate stores to the front of the variable list.
1513 // The copy in the loop matters, 'stores' will still be used.
1514 for (auto st
: stores
)
1515 layeredVarList
[0].emplace_back(std::move(st
));
1518 /// Analyze the equivalence sets defined locally in \p scope that don't
1519 /// involve common blocks.
1520 void analyzeLocalEquivalenceSets(const semantics::Scope
&scope
) {
1521 if (scope
.equivalenceSets().empty())
1522 return; // no equivalence sets to analyze
1523 if (analyzedScopes
.contains(&scope
))
1524 return; // equivalence sets already analyzed
1526 analyzedScopes
.insert(&scope
);
1527 std::list
<std::list
<semantics::SymbolRef
>> aggregates
=
1528 Fortran::semantics::GetStorageAssociations(scope
);
1529 for (std::list
<semantics::SymbolRef
> aggregate
: aggregates
) {
1530 const Fortran::semantics::Symbol
*aggregateSym
= nullptr;
1531 bool isGlobal
= false;
1532 const semantics::Symbol
&first
= *aggregate
.front();
1533 // Exclude equivalence sets involving common blocks.
1534 // Those are handled in instantiateCommon.
1535 if (lower::definedInCommonBlock(first
))
1537 std::size_t start
= first
.offset();
1538 std::size_t end
= first
.offset() + first
.size();
1539 const Fortran::semantics::Symbol
*namingSym
= nullptr;
1540 for (semantics::SymbolRef symRef
: aggregate
) {
1541 const semantics::Symbol
&sym
= *symRef
;
1542 aliasSyms
.insert(&sym
);
1543 if (sym
.test(Fortran::semantics::Symbol::Flag::CompilerCreated
)) {
1544 aggregateSym
= &sym
;
1546 isGlobal
|= lower::symbolIsGlobal(sym
);
1547 start
= std::min(sym
.offset(), start
);
1548 end
= std::max(sym
.offset() + sym
.size(), end
);
1549 if (!namingSym
|| (sym
.name() < namingSym
->name()))
1553 assert(namingSym
&& "must contain at least one user symbol");
1554 if (!aggregateSym
) {
1555 stores
.emplace_back(
1556 Fortran::lower::pft::Variable::Interval
{start
, end
- start
},
1557 *namingSym
, isGlobal
);
1559 stores
.emplace_back(*aggregateSym
, *namingSym
, isGlobal
);
1564 // Recursively visit each symbol to determine the height of its dependence on
1566 int analyze(const semantics::Symbol
&sym
) {
1567 auto done
= seen
.insert(&sym
);
1570 LLVM_DEBUG(llvm::dbgs() << "analyze symbol " << &sym
<< " in <"
1571 << &sym
.owner() << ">: " << sym
<< '\n');
1572 const semantics::Symbol
&ultimate
= sym
.GetUltimate();
1573 if (const auto *details
= ultimate
.detailsIf
<semantics::GenericDetails
>()) {
1574 // Procedure pointers may be "hidden" behind to the generic symbol if they
1575 // have the same name.
1576 if (const semantics::Symbol
*specific
= details
->specific())
1580 const bool isProcedurePointerOrDummy
=
1581 semantics::IsProcedurePointer(sym
) ||
1582 (semantics::IsProcedure(sym
) && IsDummy(sym
));
1583 // A procedure argument in a subprogram with multiple entry points might
1584 // need a layeredVarList entry to trigger creation of a symbol map entry
1585 // in some cases. Non-dummy procedures don't.
1586 if (semantics::IsProcedure(sym
) && !isProcedurePointerOrDummy
)
1588 // Derived type component symbols may be collected by "CollectSymbols"
1589 // below when processing something like "real :: x(derived%component)". The
1590 // symbol "component" has "ObjectEntityDetails", but it should not be
1591 // instantiated: it is part of "derived" that should be the only one to
1593 if (sym
.owner().IsDerivedType())
1596 if (const auto *details
=
1597 ultimate
.detailsIf
<semantics::NamelistDetails
>()) {
1598 // handle namelist group symbols
1599 for (const semantics::SymbolRef
&s
: details
->objects())
1603 if (!ultimate
.has
<semantics::ObjectEntityDetails
>() &&
1604 !isProcedurePointerOrDummy
)
1607 if (sym
.has
<semantics::DerivedTypeDetails
>())
1608 llvm_unreachable("not yet implemented - derived type analysis");
1610 // Symbol must be something lowering will have to allocate.
1612 // Analyze symbols appearing in object entity specification expressions.
1613 // This ensures these symbols will be instantiated before the current one.
1614 // This is not done for object entities that are host associated because
1615 // they must be instantiated from the value of the host symbols.
1616 // (The specification expressions should not be re-evaluated.)
1617 if (const auto *details
= sym
.detailsIf
<semantics::ObjectEntityDetails
>()) {
1618 const semantics::DeclTypeSpec
*symTy
= sym
.GetType();
1619 assert(symTy
&& "symbol must have a type");
1620 // check CHARACTER's length
1621 if (symTy
->category() == semantics::DeclTypeSpec::Character
)
1622 if (auto e
= symTy
->characterTypeSpec().length().GetExplicit())
1623 for (const auto &s
: evaluate::CollectSymbols(*e
))
1624 depth
= std::max(analyze(s
) + 1, depth
);
1626 auto doExplicit
= [&](const auto &bound
) {
1627 if (bound
.isExplicit()) {
1628 semantics::SomeExpr e
{*bound
.GetExplicit()};
1629 for (const auto &s
: evaluate::CollectSymbols(e
))
1630 depth
= std::max(analyze(s
) + 1, depth
);
1633 // Handle any symbols in array bound declarations.
1634 for (const semantics::ShapeSpec
&subs
: details
->shape()) {
1635 doExplicit(subs
.lbound());
1636 doExplicit(subs
.ubound());
1638 // Handle any symbols in coarray bound declarations.
1639 for (const semantics::ShapeSpec
&subs
: details
->coshape()) {
1640 doExplicit(subs
.lbound());
1641 doExplicit(subs
.ubound());
1643 // Handle any symbols in initialization expressions.
1644 if (auto e
= details
->init())
1645 for (const auto &s
: evaluate::CollectSymbols(*e
))
1646 if (!s
->has
<semantics::DerivedTypeDetails
>())
1647 depth
= std::max(analyze(s
) + 1, depth
);
1650 // Make sure cray pointer is instantiated even if it is not visible.
1651 if (ultimate
.test(Fortran::semantics::Symbol::Flag::CrayPointee
))
1653 analyze(Fortran::semantics::GetCrayPointer(ultimate
)) + 1, depth
);
1654 adjustSize(depth
+ 1);
1655 bool global
= lower::symbolIsGlobal(sym
);
1656 layeredVarList
[depth
].emplace_back(sym
, global
, depth
);
1657 if (semantics::IsAllocatable(sym
))
1658 layeredVarList
[depth
].back().setHeapAlloc();
1659 if (semantics::IsPointer(sym
))
1660 layeredVarList
[depth
].back().setPointer();
1661 if (ultimate
.attrs().test(semantics::Attr::TARGET
))
1662 layeredVarList
[depth
].back().setTarget();
1664 // If there are alias sets, then link the participating variables to their
1665 // aggregate stores when constructing the new variable on the list.
1666 if (lower::pft::Variable::AggregateStore
*store
= findStoreIfAlias(sym
))
1667 layeredVarList
[depth
].back().setAlias(store
->getOffset());
1671 /// Skip symbol in alias analysis.
1672 bool skipSymbol(const semantics::Symbol
&sym
) {
1673 // Common block equivalences are largely managed by the front end.
1674 // Compiler generated symbols ('.' names) cannot be equivalenced.
1675 // FIXME: Equivalence code generation may need to be revisited.
1676 return !sym
.has
<semantics::ObjectEntityDetails
>() ||
1677 lower::definedInCommonBlock(sym
) || sym
.name()[0] == '.';
1680 // Make sure the table is of appropriate size.
1681 void adjustSize(std::size_t size
) {
1682 if (layeredVarList
.size() < size
)
1683 layeredVarList
.resize(size
);
1686 Fortran::lower::pft::Variable::AggregateStore
*
1687 findStoreIfAlias(const Fortran::evaluate::Symbol
&sym
) {
1688 const semantics::Symbol
&ultimate
= sym
.GetUltimate();
1689 const semantics::Scope
&scope
= ultimate
.owner();
1690 // Expect the total number of EQUIVALENCE sets to be small for a typical
1692 if (aliasSyms
.contains(&ultimate
)) {
1693 LLVM_DEBUG(llvm::dbgs() << "found aggregate containing " << &ultimate
1694 << " " << ultimate
.name() << " in <" << &scope
1695 << "> " << scope
.GetName() << '\n');
1696 std::size_t off
= ultimate
.offset();
1697 std::size_t symSize
= ultimate
.size();
1698 for (lower::pft::Variable::AggregateStore
&v
: stores
) {
1699 if (&v
.getOwningScope() == &scope
) {
1700 auto intervalOff
= std::get
<0>(v
.interval
);
1701 auto intervalSize
= std::get
<1>(v
.interval
);
1702 if (off
>= intervalOff
&& off
< intervalOff
+ intervalSize
)
1704 // Zero sized symbol in zero sized equivalence.
1705 if (off
== intervalOff
&& symSize
== 0)
1711 llvm::dbgs() << "looking for " << off
<< "\n{\n";
1712 for (lower::pft::Variable::AggregateStore
&v
: stores
) {
1713 llvm::dbgs() << " in scope: " << &v
.getOwningScope() << "\n";
1714 llvm::dbgs() << " i = [" << std::get
<0>(v
.interval
) << ".."
1715 << std::get
<0>(v
.interval
) + std::get
<1>(v
.interval
)
1718 llvm::dbgs() << "}\n");
1720 llvm_unreachable("the store must be present");
1725 /// Flatten the result VariableList.
1727 for (int i
= 1, end
= layeredVarList
.size(); i
< end
; ++i
)
1728 layeredVarList
[0].insert(layeredVarList
[0].end(),
1729 layeredVarList
[i
].begin(),
1730 layeredVarList
[i
].end());
1733 llvm::SmallSet
<const semantics::Symbol
*, 32> seen
;
1734 std::vector
<Fortran::lower::pft::VariableList
> layeredVarList
;
1735 llvm::SmallSet
<const semantics::Symbol
*, 32> aliasSyms
;
1736 /// Set of scopes that have been analyzed for aliases.
1737 llvm::SmallSet
<const semantics::Scope
*, 4> analyzedScopes
;
1738 std::vector
<Fortran::lower::pft::Variable::AggregateStore
> stores
;
1742 //===----------------------------------------------------------------------===//
1743 // FunctionLikeUnit implementation
1744 //===----------------------------------------------------------------------===//
1746 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1747 const parser::MainProgram
&func
, const lower::pft::PftNode
&parent
,
1748 const semantics::SemanticsContext
&semanticsContext
)
1749 : ProgramUnit
{func
, parent
},
1750 endStmt
{getFunctionStmt
<parser::EndProgramStmt
>(func
)} {
1751 const auto &programStmt
=
1752 std::get
<std::optional
<parser::Statement
<parser::ProgramStmt
>>>(func
.t
);
1753 if (programStmt
.has_value()) {
1754 beginStmt
= FunctionStatement(programStmt
.value());
1755 const semantics::Symbol
*symbol
= getSymbol(*beginStmt
);
1756 entryPointList
[0].first
= symbol
;
1757 scope
= symbol
->scope();
1759 scope
= &semanticsContext
.FindScope(
1760 std::get
<parser::Statement
<parser::EndProgramStmt
>>(func
.t
).source
);
1764 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1765 const parser::FunctionSubprogram
&func
, const lower::pft::PftNode
&parent
,
1766 const semantics::SemanticsContext
&)
1767 : ProgramUnit
{func
, parent
},
1768 beginStmt
{getFunctionStmt
<parser::FunctionStmt
>(func
)},
1769 endStmt
{getFunctionStmt
<parser::EndFunctionStmt
>(func
)} {
1770 const semantics::Symbol
*symbol
= getSymbol(*beginStmt
);
1771 entryPointList
[0].first
= symbol
;
1772 scope
= symbol
->scope();
1775 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1776 const parser::SubroutineSubprogram
&func
, const lower::pft::PftNode
&parent
,
1777 const semantics::SemanticsContext
&)
1778 : ProgramUnit
{func
, parent
},
1779 beginStmt
{getFunctionStmt
<parser::SubroutineStmt
>(func
)},
1780 endStmt
{getFunctionStmt
<parser::EndSubroutineStmt
>(func
)} {
1781 const semantics::Symbol
*symbol
= getSymbol(*beginStmt
);
1782 entryPointList
[0].first
= symbol
;
1783 scope
= symbol
->scope();
1786 Fortran::lower::pft::FunctionLikeUnit::FunctionLikeUnit(
1787 const parser::SeparateModuleSubprogram
&func
,
1788 const lower::pft::PftNode
&parent
, const semantics::SemanticsContext
&)
1789 : ProgramUnit
{func
, parent
},
1790 beginStmt
{getFunctionStmt
<parser::MpSubprogramStmt
>(func
)},
1791 endStmt
{getFunctionStmt
<parser::EndMpSubprogramStmt
>(func
)} {
1792 const semantics::Symbol
*symbol
= getSymbol(*beginStmt
);
1793 entryPointList
[0].first
= symbol
;
1794 scope
= symbol
->scope();
1797 Fortran::lower::HostAssociations
&
1798 Fortran::lower::pft::FunctionLikeUnit::parentHostAssoc() {
1799 if (auto *par
= parent
.getIf
<FunctionLikeUnit
>())
1800 return par
->hostAssociations
;
1801 llvm::report_fatal_error("parent is not a function");
1804 bool Fortran::lower::pft::FunctionLikeUnit::parentHasTupleHostAssoc() {
1805 if (auto *par
= parent
.getIf
<FunctionLikeUnit
>())
1806 return par
->hostAssociations
.hasTupleAssociations();
1810 bool Fortran::lower::pft::FunctionLikeUnit::parentHasHostAssoc() {
1811 if (auto *par
= parent
.getIf
<FunctionLikeUnit
>())
1812 return !par
->hostAssociations
.empty();
1817 Fortran::lower::pft::FunctionLikeUnit::getStartingSourceLoc() const {
1819 return stmtSourceLoc(*beginStmt
);
1820 return scope
->sourceRange();
1823 //===----------------------------------------------------------------------===//
1824 // ModuleLikeUnit implementation
1825 //===----------------------------------------------------------------------===//
1827 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit(
1828 const parser::Module
&m
, const lower::pft::PftNode
&parent
)
1829 : ProgramUnit
{m
, parent
}, beginStmt
{getModuleStmt
<parser::ModuleStmt
>(m
)},
1830 endStmt
{getModuleStmt
<parser::EndModuleStmt
>(m
)} {}
1832 Fortran::lower::pft::ModuleLikeUnit::ModuleLikeUnit(
1833 const parser::Submodule
&m
, const lower::pft::PftNode
&parent
)
1834 : ProgramUnit
{m
, parent
},
1835 beginStmt
{getModuleStmt
<parser::SubmoduleStmt
>(m
)},
1836 endStmt
{getModuleStmt
<parser::EndSubmoduleStmt
>(m
)} {}
1839 Fortran::lower::pft::ModuleLikeUnit::getStartingSourceLoc() const {
1840 return stmtSourceLoc(beginStmt
);
1842 const Fortran::semantics::Scope
&
1843 Fortran::lower::pft::ModuleLikeUnit::getScope() const {
1844 const Fortran::semantics::Symbol
*symbol
= getSymbol(beginStmt
);
1845 assert(symbol
&& symbol
->scope() &&
1846 "Module statement must have a symbol with a scope");
1847 return *symbol
->scope();
1850 //===----------------------------------------------------------------------===//
1851 // BlockDataUnit implementation
1852 //===----------------------------------------------------------------------===//
1854 Fortran::lower::pft::BlockDataUnit::BlockDataUnit(
1855 const parser::BlockData
&bd
, const lower::pft::PftNode
&parent
,
1856 const semantics::SemanticsContext
&semanticsContext
)
1857 : ProgramUnit
{bd
, parent
},
1858 symTab
{semanticsContext
.FindScope(
1859 std::get
<parser::Statement
<parser::EndBlockDataStmt
>>(bd
.t
).source
)} {
1862 //===----------------------------------------------------------------------===//
1863 // Variable implementation
1864 //===----------------------------------------------------------------------===//
1866 bool Fortran::lower::pft::Variable::isRuntimeTypeInfoData() const {
1867 // So far, use flags to detect if this symbol were generated during
1868 // semantics::BuildRuntimeDerivedTypeTables(). Scope cannot be used since the
1869 // symbols are injected in the user scopes defining the described derived
1870 // types. A robustness improvement for this test could be to get hands on the
1871 // semantics::RuntimeDerivedTypeTables and to check if the symbol names
1872 // belongs to this structure.
1873 using Flags
= Fortran::semantics::Symbol::Flag
;
1874 const auto *nominal
= std::get_if
<Nominal
>(&var
);
1875 return nominal
&& nominal
->symbol
->test(Flags::CompilerCreated
) &&
1876 nominal
->symbol
->test(Flags::ReadOnly
);
1879 //===----------------------------------------------------------------------===//
1880 // API implementation
1881 //===----------------------------------------------------------------------===//
1883 std::unique_ptr
<lower::pft::Program
>
1884 Fortran::lower::createPFT(const parser::Program
&root
,
1885 const semantics::SemanticsContext
&semanticsContext
) {
1886 PFTBuilder
walker(semanticsContext
);
1888 return walker
.result();
1891 void Fortran::lower::dumpPFT(llvm::raw_ostream
&outputStream
,
1892 const lower::pft::Program
&pft
) {
1893 PFTDumper
{}.dumpPFT(outputStream
, pft
);
1896 void Fortran::lower::pft::Program::dump() const {
1897 dumpPFT(llvm::errs(), *this);
1900 void Fortran::lower::pft::Evaluation::dump() const {
1901 PFTDumper
{}.dumpEvaluation(llvm::errs(), *this);
1904 void Fortran::lower::pft::Variable::dump() const {
1905 if (auto *s
= std::get_if
<Nominal
>(&var
)) {
1906 llvm::errs() << s
->symbol
<< " " << *s
->symbol
;
1907 llvm::errs() << " (depth: " << s
->depth
<< ')';
1909 llvm::errs() << ", global";
1911 llvm::errs() << ", allocatable";
1913 llvm::errs() << ", pointer";
1915 llvm::errs() << ", target";
1917 llvm::errs() << ", equivalence(" << s
->aliasOffset
<< ')';
1918 } else if (auto *s
= std::get_if
<AggregateStore
>(&var
)) {
1919 llvm::errs() << "interval[" << std::get
<0>(s
->interval
) << ", "
1920 << std::get
<1>(s
->interval
) << "]:";
1921 llvm::errs() << " name: " << toStringRef(s
->getNamingSymbol().name());
1923 llvm::errs() << ", global";
1924 if (s
->initialValueSymbol
)
1925 llvm::errs() << ", initial value: {" << *s
->initialValueSymbol
<< "}";
1927 llvm_unreachable("not a Variable");
1929 llvm::errs() << '\n';
1932 void Fortran::lower::pft::dump(Fortran::lower::pft::VariableList
&variableList
,
1934 llvm::errs() << (s
.empty() ? "VariableList" : s
) << " " << &variableList
1935 << " size=" << variableList
.size() << "\n";
1936 for (auto var
: variableList
) {
1937 llvm::errs() << " ";
1942 void Fortran::lower::pft::FunctionLikeUnit::dump() const {
1943 PFTDumper
{}.dumpFunctionLikeUnit(llvm::errs(), *this);
1946 void Fortran::lower::pft::ModuleLikeUnit::dump() const {
1947 PFTDumper
{}.dumpModuleLikeUnit(llvm::errs(), *this);
1950 /// The BlockDataUnit dump is just the associated symbol table.
1951 void Fortran::lower::pft::BlockDataUnit::dump() const {
1952 llvm::errs() << "block data {\n" << symTab
<< "\n}\n";
1955 /// Find or create an ordered list of equivalences and variables in \p scope.
1956 /// The result is cached in \p map.
1957 const lower::pft::VariableList
&
1958 lower::pft::getScopeVariableList(const semantics::Scope
&scope
,
1959 ScopeVariableListMap
&map
) {
1960 LLVM_DEBUG(llvm::dbgs() << "\ngetScopeVariableList of [sub]module scope <"
1961 << &scope
<< "> " << scope
.GetName() << "\n");
1962 auto iter
= map
.find(&scope
);
1963 if (iter
== map
.end()) {
1964 SymbolDependenceAnalysis
sda(scope
);
1965 map
.emplace(&scope
, sda
.getVariableList());
1966 iter
= map
.find(&scope
);
1968 return iter
->second
;
1971 /// Create an ordered list of equivalences and variables in \p scope.
1972 /// The result is not cached.
1973 lower::pft::VariableList
1974 lower::pft::getScopeVariableList(const semantics::Scope
&scope
) {
1976 llvm::dbgs() << "\ngetScopeVariableList of [sub]program|block scope <"
1977 << &scope
<< "> " << scope
.GetName() << "\n");
1978 SymbolDependenceAnalysis
sda(scope
);
1979 return sda
.getVariableList();
1982 /// Create an ordered list of equivalences and variables that \p symbol
1983 /// depends on (no caching). Include \p symbol at the end of the list.
1984 lower::pft::VariableList
1985 lower::pft::getDependentVariableList(const semantics::Symbol
&symbol
) {
1986 LLVM_DEBUG(llvm::dbgs() << "\ngetDependentVariableList of " << &symbol
1987 << " - " << symbol
<< "\n");
1988 SymbolDependenceAnalysis
sda(symbol
);
1989 return sda
.getVariableList();
1993 /// Helper class to find all the symbols referenced in a FunctionLikeUnit.
1994 /// It defines a parse tree visitor doing a deep visit in all nodes with
1995 /// symbols (including evaluate::Expr).
1996 struct SymbolVisitor
{
1997 template <typename A
>
1998 bool Pre(const A
&x
) {
1999 if constexpr (Fortran::parser::HasTypedExpr
<A
>::value
)
2000 // Some parse tree Expr may legitimately be un-analyzed after semantics
2001 // (for instance PDT component initial value in the PDT definition body).
2002 if (const auto *expr
= Fortran::semantics::GetExpr(nullptr, x
))
2007 bool Pre(const Fortran::parser::Name
&name
) {
2008 if (const semantics::Symbol
*symbol
= name
.symbol
)
2009 visitSymbol(*symbol
);
2013 template <typename T
>
2014 void visitExpr(const Fortran::evaluate::Expr
<T
> &expr
) {
2015 for (const semantics::Symbol
&symbol
:
2016 Fortran::evaluate::CollectSymbols(expr
))
2017 visitSymbol(symbol
);
2020 void visitSymbol(const Fortran::semantics::Symbol
&symbol
) {
2022 // - Visit statement function body since it will be inlined in lowering.
2023 // - Visit function results specification expressions because allocations
2024 // happens on the caller side.
2025 if (const auto *subprogramDetails
=
2026 symbol
.detailsIf
<Fortran::semantics::SubprogramDetails
>()) {
2027 if (const auto &maybeExpr
= subprogramDetails
->stmtFunction()) {
2028 visitExpr(*maybeExpr
);
2030 if (subprogramDetails
->isFunction()) {
2031 // Visit result extents expressions that are explicit.
2032 const Fortran::semantics::Symbol
&result
=
2033 subprogramDetails
->result();
2034 if (const auto *objectDetails
=
2035 result
.detailsIf
<Fortran::semantics::ObjectEntityDetails
>())
2036 if (objectDetails
->shape().IsExplicitShape())
2037 for (const Fortran::semantics::ShapeSpec
&shapeSpec
:
2038 objectDetails
->shape()) {
2039 visitExpr(shapeSpec
.lbound().GetExplicit().value());
2040 visitExpr(shapeSpec
.ubound().GetExplicit().value());
2045 if (Fortran::semantics::IsProcedure(symbol
)) {
2046 if (auto dynamicType
= Fortran::evaluate::DynamicType::From(symbol
)) {
2047 // Visit result length specification expressions that are explicit.
2048 if (dynamicType
->category() ==
2049 Fortran::common::TypeCategory::Character
) {
2050 if (std::optional
<Fortran::evaluate::ExtentExpr
> length
=
2051 dynamicType
->GetCharLength())
2053 } else if (const Fortran::semantics::DerivedTypeSpec
*derivedTypeSpec
=
2054 Fortran::evaluate::GetDerivedTypeSpec(dynamicType
)) {
2055 for (const auto &[_
, param
] : derivedTypeSpec
->parameters())
2056 if (const Fortran::semantics::MaybeIntExpr
&expr
=
2057 param
.GetExplicit())
2058 visitExpr(expr
.value());
2062 // - CrayPointer needs to be available whenever a CrayPointee is used.
2063 if (symbol
.GetUltimate().test(
2064 Fortran::semantics::Symbol::Flag::CrayPointee
))
2065 visitSymbol(Fortran::semantics::GetCrayPointer(symbol
));
2068 template <typename A
>
2069 constexpr void Post(const A
&) {}
2071 const std::function
<void(const Fortran::semantics::Symbol
&)> &callBack
;
2075 void Fortran::lower::pft::visitAllSymbols(
2076 const Fortran::lower::pft::FunctionLikeUnit
&funit
,
2077 const std::function
<void(const Fortran::semantics::Symbol
&)> callBack
) {
2078 SymbolVisitor visitor
{callBack
};
2079 funit
.visit([&](const auto &functionParserNode
) {
2080 parser::Walk(functionParserNode
, visitor
);
2084 void Fortran::lower::pft::visitAllSymbols(
2085 const Fortran::lower::pft::Evaluation
&eval
,
2086 const std::function
<void(const Fortran::semantics::Symbol
&)> callBack
) {
2087 SymbolVisitor visitor
{callBack
};
2088 eval
.visit([&](const auto &functionParserNode
) {
2089 parser::Walk(functionParserNode
, visitor
);