FLANG
PFTBuilder.h
1//===-- Lower/PFTBuilder.h -- PFT builder -----------------------*- C++ -*-===//
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// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
12//
13// PFT (Pre-FIR Tree) interface.
14//
15//===----------------------------------------------------------------------===//
16
17#ifndef FORTRAN_LOWER_PFTBUILDER_H
18#define FORTRAN_LOWER_PFTBUILDER_H
19
20#include "flang/Common/reference.h"
21#include "flang/Common/template.h"
22#include "flang/Lower/HostAssociations.h"
23#include "flang/Lower/PFTDefs.h"
24#include "flang/Parser/parse-tree.h"
25#include "flang/Semantics/attr.h"
26#include "flang/Semantics/scope.h"
27#include "flang/Semantics/semantics.h"
28#include "flang/Semantics/symbol.h"
29#include "llvm/Support/ErrorHandling.h"
30#include "llvm/Support/raw_ostream.h"
31
32namespace Fortran::lower::pft {
33
35struct Evaluation;
36struct FunctionLikeUnit;
37struct ModuleLikeUnit;
38struct Program;
39
40using ContainedUnit = std::variant<CompilerDirectiveUnit, FunctionLikeUnit>;
41using ContainedUnitList = std::list<ContainedUnit>;
42using EvaluationList = std::list<Evaluation>;
43
47template <bool isConst, typename... A>
48class ReferenceVariantBase {
49public:
50 template <typename B>
51 using BaseType = std::conditional_t<isConst, const B, B>;
52 template <typename B>
54
55 ReferenceVariantBase() = delete;
56 ReferenceVariantBase(std::variant<Ref<A>...> b) : u(b) {}
57 template <typename T>
58 ReferenceVariantBase(Ref<T> b) : u(b) {}
59
60 template <typename B>
61 constexpr BaseType<B> &get() const {
62 return std::get<Ref<B>>(u).get();
63 }
64 template <typename B>
65 constexpr BaseType<B> &getStatement() const {
66 return std::get<Ref<parser::Statement<B>>>(u).get().statement;
67 }
68 template <typename B>
69 constexpr BaseType<B> *getIf() const {
70 const Ref<B> *ptr = std::get_if<Ref<B>>(&u);
71 return ptr ? &ptr->get() : nullptr;
72 }
73 template <typename B>
74 constexpr bool isA() const {
75 return std::holds_alternative<Ref<B>>(u);
76 }
77 template <typename VISITOR>
78 constexpr auto visit(VISITOR &&visitor) const {
79 return Fortran::common::visit(
80 common::visitors{[&visitor](auto ref) { return visitor(ref.get()); }},
81 u);
82 }
83
84private:
85 std::variant<Ref<A>...> u;
86};
87template <typename... A>
88using ReferenceVariant = ReferenceVariantBase<true, A...>;
89template <typename... A>
90using MutableReferenceVariant = ReferenceVariantBase<false, A...>;
91
94using PftNode = MutableReferenceVariant<Program, ModuleLikeUnit,
96
98
99using ActionStmts = std::tuple<
100 parser::AllocateStmt, parser::AssignmentStmt, parser::BackspaceStmt,
101 parser::CallStmt, parser::CloseStmt, parser::ContinueStmt,
102 parser::CycleStmt, parser::DeallocateStmt, parser::EndfileStmt,
104 parser::FailImageStmt, parser::FlushStmt, parser::FormTeamStmt,
106 parser::NotifyWaitStmt, parser::NullifyStmt, parser::OpenStmt,
108 parser::ReturnStmt, parser::RewindStmt, parser::StopStmt,
109 parser::SyncAllStmt, parser::SyncImagesStmt, parser::SyncMemoryStmt,
110 parser::SyncTeamStmt, parser::UnlockStmt, parser::WaitStmt,
113 parser::AssignedGotoStmt, parser::PauseStmt>;
114
115using OtherStmts = std::tuple<parser::EntryStmt, parser::FormatStmt>;
116
117using ConstructStmts = std::tuple<
118 parser::AssociateStmt, parser::EndAssociateStmt, parser::BlockStmt,
119 parser::EndBlockStmt, parser::SelectCaseStmt, parser::CaseStmt,
121 parser::CriticalStmt, parser::EndCriticalStmt, parser::NonLabelDoStmt,
122 parser::EndDoStmt, parser::IfThenStmt, parser::ElseIfStmt, parser::ElseStmt,
125 parser::MaskedElsewhereStmt, parser::ElsewhereStmt, parser::EndWhereStmt,
126 parser::ForallConstructStmt, parser::EndForallStmt>;
127
128using EndStmts =
129 std::tuple<parser::EndProgramStmt, parser::EndFunctionStmt,
130 parser::EndSubroutineStmt, parser::EndMpSubprogramStmt>;
131
132using Constructs =
139
140using Directives =
146
147using DeclConstructs = std::tuple<parser::OpenMPDeclarativeConstruct,
149
150template <typename A>
151static constexpr bool isActionStmt{common::HasMember<A, ActionStmts>};
152
153template <typename A>
154static constexpr bool isOtherStmt{common::HasMember<A, OtherStmts>};
155
156template <typename A>
157static constexpr bool isConstructStmt{common::HasMember<A, ConstructStmts>};
158
159template <typename A>
160static constexpr bool isEndStmt{common::HasMember<A, EndStmts>};
161
162template <typename A>
163static constexpr bool isConstruct{common::HasMember<A, Constructs>};
164
165template <typename A>
166static constexpr bool isDirective{common::HasMember<A, Directives>};
167
168template <typename A>
169static constexpr bool isDeclConstruct{common::HasMember<A, DeclConstructs>};
170
171template <typename A>
172static constexpr bool isIntermediateConstructStmt{common::HasMember<
173 A, std::tuple<parser::CaseStmt, parser::ElseIfStmt, parser::ElseStmt,
174 parser::SelectRankCaseStmt, parser::TypeGuardStmt>>};
175
176template <typename A>
177static constexpr bool isNopConstructStmt{common::HasMember<
178 A, std::tuple<parser::CaseStmt, parser::ElseIfStmt, parser::ElseStmt,
179 parser::EndIfStmt, parser::SelectRankCaseStmt,
180 parser::TypeGuardStmt>>};
181
182template <typename A>
183static constexpr bool isExecutableDirective{common::HasMember<
184 A, std::tuple<parser::CompilerDirective, parser::OpenACCConstruct,
185 parser::OpenMPConstruct, parser::CUFKernelDoConstruct>>};
186
187template <typename A>
188static constexpr bool isOpenMPDirective{
189 common::HasMember<A, std::tuple<parser::OpenMPConstruct,
190 parser::OpenMPDeclarativeConstruct>>};
191
192template <typename A>
193static constexpr bool isFunctionLike{common::HasMember<
194 A, std::tuple<parser::MainProgram, parser::FunctionSubprogram,
195 parser::SubroutineSubprogram,
196 parser::SeparateModuleSubprogram>>};
197
198template <typename A>
200template <typename... A>
201struct MakeReferenceVariantHelper<std::variant<A...>> {
202 using type = ReferenceVariant<A...>;
203};
204template <typename... A>
205struct MakeReferenceVariantHelper<std::tuple<A...>> {
206 using type = ReferenceVariant<A...>;
207};
208template <typename A>
209using MakeReferenceVariant = typename MakeReferenceVariantHelper<A>::type;
210
211using EvaluationTuple =
212 common::CombineTuples<ActionStmts, OtherStmts, ConstructStmts, EndStmts,
213 Constructs, Directives>;
217using EvaluationVariant = MakeReferenceVariant<EvaluationTuple>;
218
221struct Evaluation : EvaluationVariant {
222
224 template <typename A>
225 Evaluation(const A &a, const PftNode &parent,
226 const parser::CharBlock &position,
227 const std::optional<parser::Label> &label)
228 : EvaluationVariant{a}, parent{parent}, position{position}, label{label} {
229 }
230
232 template <typename A>
233 Evaluation(const A &a, const PftNode &parent)
234 : EvaluationVariant{a}, parent{parent} {
235 static_assert(pft::isConstruct<A> || pft::isDirective<A>,
236 "must be a construct or directive");
237 }
238
240 constexpr bool isActionStmt() const {
241 return visit(common::visitors{
242 [](auto &r) { return pft::isActionStmt<std::decay_t<decltype(r)>>; }});
243 }
244 constexpr bool isOtherStmt() const {
245 return visit(common::visitors{
246 [](auto &r) { return pft::isOtherStmt<std::decay_t<decltype(r)>>; }});
247 }
248 constexpr bool isConstructStmt() const {
249 return visit(common::visitors{[](auto &r) {
250 return pft::isConstructStmt<std::decay_t<decltype(r)>>;
251 }});
252 }
253 constexpr bool isEndStmt() const {
254 return visit(common::visitors{
255 [](auto &r) { return pft::isEndStmt<std::decay_t<decltype(r)>>; }});
256 }
257 constexpr bool isConstruct() const {
258 return visit(common::visitors{
259 [](auto &r) { return pft::isConstruct<std::decay_t<decltype(r)>>; }});
260 }
261 constexpr bool isDirective() const {
262 return visit(common::visitors{
263 [](auto &r) { return pft::isDirective<std::decay_t<decltype(r)>>; }});
264 }
265 constexpr bool isNopConstructStmt() const {
266 return visit(common::visitors{[](auto &r) {
267 return pft::isNopConstructStmt<std::decay_t<decltype(r)>>;
268 }});
269 }
270 constexpr bool isExecutableDirective() const {
271 return visit(common::visitors{[](auto &r) {
272 return pft::isExecutableDirective<std::decay_t<decltype(r)>>;
273 }});
274 }
275 constexpr bool isOpenMPDirective() const {
276 return visit(common::visitors{[](auto &r) {
277 return pft::isOpenMPDirective<std::decay_t<decltype(r)>>;
278 }});
279 }
280
283 constexpr bool isIntermediateConstructStmt() const {
284 return visit(common::visitors{[](auto &r) {
285 return pft::isIntermediateConstructStmt<std::decay_t<decltype(r)>>;
286 }});
287 }
288
289 LLVM_DUMP_METHOD void dump() const;
290
294 Evaluation *successor = lexicalSuccessor;
295 if (successor && successor->isNopConstructStmt())
296 successor = successor->parentConstruct->constructExit;
297 assert(successor && "missing successor");
298 return *successor;
299 }
300
302 bool hasNestedEvaluations() const {
303 return evaluationList && !evaluationList->empty();
304 }
305
307 EvaluationList &getNestedEvaluations() {
308 assert(evaluationList && "no nested evaluations");
309 return *evaluationList;
310 }
311
312 Evaluation &getFirstNestedEvaluation() {
313 assert(hasNestedEvaluations() && "no nested evaluations");
314 return evaluationList->front();
315 }
316
317 Evaluation &getLastNestedEvaluation() {
318 assert(hasNestedEvaluations() && "no nested evaluations");
319 return evaluationList->back();
320 }
321
323 FunctionLikeUnit *getOwningProcedure() const;
324
325 bool lowerAsStructured() const;
326 bool lowerAsUnstructured() const;
327 bool forceAsUnstructured() const;
328
329 // FIR generation looks primarily at PFT ActionStmt and ConstructStmt leaf
330 // nodes. Members such as lexicalSuccessor and block are applicable only
331 // to these nodes, plus some directives. The controlSuccessor member is
332 // used for nonlexical successors, such as linking to a GOTO target. For
333 // multiway branches (computed GO TO, arithmetic IF), it is set to the
334 // first target and any additional targets are recorded in
335 // extraControlSuccessors so analyses that need to see every branch target
336 // (e.g. wrappability of an unstructured construct) can enumerate them all.
337 // Successor and exit links always target statements or directives. An
338 // internal Construct node has a constructExit link that applies to exits
339 // from anywhere within the construct.
340 //
341 // An unstructured construct is one that contains some form of goto. This
342 // is indicated by the isUnstructured member flag, which may be set on a
343 // statement and propagated to enclosing constructs. This distinction allows
344 // a structured IF or DO statement to be materialized with custom structured
345 // FIR operations. An unstructured statement is materialized as mlir
346 // operation sequences that include explicit branches.
347 //
348 // The block member is set for statements that begin a new block. This
349 // block is the target of any branch to the statement. Statements may have
350 // additional (unstructured) "local" blocks, but such blocks cannot be the
351 // target of any explicit branch. The primary example of an (unstructured)
352 // statement that may have multiple associated blocks is NonLabelDoStmt,
353 // which may have a loop preheader block for loop initialization code (the
354 // block member), and always has a "local" header block that is the target
355 // of the loop back edge. If the NonLabelDoStmt is a concurrent loop, it
356 // may be associated with an arbitrary number of nested preheader, header,
357 // and mask blocks.
358 //
359 // The printIndex member is only set for statements. It is used for dumps
360 // (and debugging) and does not affect FIR generation.
361
362 PftNode parent;
363 parser::CharBlock position{};
364 std::optional<parser::Label> label{};
365 std::unique_ptr<EvaluationList> evaluationList; // nested evaluations
366 // associated compiler directives
367 llvm::SmallVector<const parser::CompilerDirective *, 1> dirs;
368 Evaluation *parentConstruct{nullptr}; // set for nodes below the top level
369 Evaluation *lexicalSuccessor{nullptr}; // set for leaf nodes, some directives
370 Evaluation *controlSuccessor{nullptr}; // set for some leaf nodes
371 // Additional branch targets for multiway branches (computed GO TO,
372 // arithmetic IF). Empty for single-target branches; the first target is in
373 // controlSuccessor and the remaining ones are stored here in source order.
374 llvm::SmallVector<Evaluation *, 0> extraControlSuccessors;
375 Evaluation *constructExit{nullptr}; // set for constructs
376 bool isNewBlock{false}; // evaluation begins a new basic block
377 bool isUnstructured{false}; // evaluation has unstructured control flow
378 bool negateCondition{false}; // If[Then]Stmt condition must be negated
379 bool activeConstruct{false}; // temporarily set for some constructs
380 // The enclosing evaluation-list traversal should skip this evaluation once
381 // because directive lowering already consumed it.
382 bool skipNextLowering{false};
383 mlir::Block *block{nullptr}; // isNewBlock block (ActionStmt, ConstructStmt)
384 int printIndex{0}; // (ActionStmt, ConstructStmt) evaluation index for dumps
385};
386
387using ProgramVariant =
388 ReferenceVariant<parser::MainProgram, parser::FunctionSubprogram,
389 parser::SubroutineSubprogram, parser::Module,
390 parser::Submodule, parser::SeparateModuleSubprogram,
391 parser::BlockData, parser::CompilerDirective,
392 parser::OpenACCRoutineConstruct>;
395struct ProgramUnit : ProgramVariant {
396 template <typename A>
397 ProgramUnit(const A &p, const PftNode &parent)
398 : ProgramVariant{p}, parent{parent} {}
399 ProgramUnit(ProgramUnit &&) = default;
400 ProgramUnit(const ProgramUnit &) = delete;
401
402 PftNode parent;
403};
404
420struct Variable {
424 struct Nominal {
425 Nominal(const semantics::Symbol *symbol, int depth, bool global)
426 : symbol{symbol}, depth{depth}, global{global} {}
427 const semantics::Symbol *symbol{};
428
429 bool isGlobal() const { return global; }
430
431 int depth{};
432 bool global{};
433 bool heapAlloc{}; // variable needs deallocation on exit
434 bool pointer{};
435 bool target{};
436 bool aliaser{}; // participates in EQUIVALENCE union
437 std::size_t aliasOffset{};
438 };
439
441 using Interval = std::tuple<std::size_t, std::size_t>;
442
446 struct AggregateStore {
447 AggregateStore(Interval &&interval,
448 const Fortran::semantics::Symbol &namingSym,
449 bool isGlobal = false)
450 : interval{std::move(interval)}, namingSymbol{&namingSym},
451 isGlobalAggregate{isGlobal} {}
452 AggregateStore(const semantics::Symbol &initialValueSym,
453 const semantics::Symbol &namingSym, bool isGlobal = false)
454 : interval{initialValueSym.offset(), initialValueSym.size()},
455 namingSymbol{&namingSym}, initialValueSymbol{&initialValueSym},
456 isGlobalAggregate{isGlobal} {};
457
458 bool isGlobal() const { return isGlobalAggregate; }
460 std::size_t getOffset() const { return std::get<0>(interval); }
465
469 return getNamingSymbol().owner();
470 }
471
479 };
480
481 explicit Variable(const Fortran::semantics::Symbol &sym, bool global = false,
482 int depth = 0)
483 : var{Nominal(&sym, depth, global)} {}
484 explicit Variable(AggregateStore &&istore) : var{std::move(istore)} {}
485
488 assert(hasSymbol() && "variable is not nominal");
489 return *std::get<Nominal>(var).symbol;
490 }
491
493 bool isRuntimeTypeInfoData() const;
494
497 assert(isAggregateStore());
498 return std::get<AggregateStore>(var);
499 }
500
502 const Interval &getInterval() const {
503 assert(isAggregateStore());
504 return std::get<AggregateStore>(var).interval;
505 }
506
508 bool hasSymbol() const { return std::holds_alternative<Nominal>(var); }
509
511 bool isAggregateStore() const {
512 return std::holds_alternative<AggregateStore>(var);
513 }
514
516 bool isGlobal() const {
517 return Fortran::common::visit([](const auto &x) { return x.isGlobal(); },
518 var);
519 }
520
523 const semantics::Scope *scope = getOwningScope();
524 return scope && scope->kind() == Fortran::semantics::Scope::Kind::Module;
525 }
526
527 const Fortran::semantics::Scope *getOwningScope() const {
528 return Fortran::common::visit(
530 [](const Nominal &x) { return &x.symbol->GetUltimate().owner(); },
531 [](const AggregateStore &agg) { return &agg.getOwningScope(); }},
532 var);
533 }
534
535 bool isHeapAlloc() const {
536 if (auto *s = std::get_if<Nominal>(&var))
537 return s->heapAlloc;
538 return false;
539 }
540 bool isPointer() const {
541 if (auto *s = std::get_if<Nominal>(&var))
542 return s->pointer;
543 return false;
544 }
545 bool isTarget() const {
546 if (auto *s = std::get_if<Nominal>(&var))
547 return s->target;
548 return false;
549 }
550
553 bool isAlias() const {
554 if (auto *s = std::get_if<Nominal>(&var))
555 return s->aliaser;
556 return false;
557 }
558 std::size_t getAliasOffset() const {
559 if (auto *s = std::get_if<Nominal>(&var))
560 return s->aliasOffset;
561 return 0;
562 }
563 void setAlias(std::size_t offset) {
564 if (auto *s = std::get_if<Nominal>(&var)) {
565 s->aliaser = true;
566 s->aliasOffset = offset;
567 } else {
568 llvm_unreachable("not a nominal var");
569 }
570 }
571
572 void setHeapAlloc(bool to = true) {
573 if (auto *s = std::get_if<Nominal>(&var))
574 s->heapAlloc = to;
575 else
576 llvm_unreachable("not a nominal var");
577 }
578 void setPointer(bool to = true) {
579 if (auto *s = std::get_if<Nominal>(&var))
580 s->pointer = to;
581 else
582 llvm_unreachable("not a nominal var");
583 }
584 void setTarget(bool to = true) {
585 if (auto *s = std::get_if<Nominal>(&var))
586 s->target = to;
587 else
588 llvm_unreachable("not a nominal var");
589 }
590
592 int getDepth() const {
593 if (auto *s = std::get_if<Nominal>(&var))
594 return s->depth;
595 return 0;
596 }
597
598 LLVM_DUMP_METHOD void dump() const;
599
600private:
601 std::variant<Nominal, AggregateStore> var;
602};
603
604using VariableList = std::vector<Variable>;
605using ScopeVariableListMap =
606 std::map<const Fortran::semantics::Scope *, VariableList>;
607
610const VariableList &getScopeVariableList(const Fortran::semantics::Scope &scope,
611 ScopeVariableListMap &map);
612
615VariableList getScopeVariableList(const Fortran::semantics::Scope &scope);
616
619VariableList getDependentVariableList(const Fortran::semantics::Symbol &);
620
621struct FunctionLikeUnit;
626VariableList getHostModuleVariableList(const FunctionLikeUnit &funit);
627
628void dump(VariableList &, std::string s = {}); // `s` is an optional dump label
629
632struct FunctionLikeUnit : public ProgramUnit {
633 // wrapper statements for function-like syntactic structures
634 using FunctionStatement =
635 ReferenceVariant<parser::Statement<parser::ProgramStmt>,
643
644 FunctionLikeUnit(
645 const parser::MainProgram &f, const PftNode &parent,
646 const Fortran::semantics::SemanticsContext &semanticsContext);
647 FunctionLikeUnit(
648 const parser::FunctionSubprogram &f, const PftNode &parent,
649 const Fortran::semantics::SemanticsContext &semanticsContext);
650 FunctionLikeUnit(
651 const parser::SubroutineSubprogram &f, const PftNode &parent,
652 const Fortran::semantics::SemanticsContext &semanticsContext);
653 FunctionLikeUnit(
654 const parser::SeparateModuleSubprogram &f, const PftNode &parent,
655 const Fortran::semantics::SemanticsContext &semanticsContext);
656 FunctionLikeUnit(FunctionLikeUnit &&) = default;
657 FunctionLikeUnit(const FunctionLikeUnit &) = delete;
658
659 bool isMainProgram() const {
660 return endStmt.isA<parser::Statement<parser::EndProgramStmt>>();
661 }
662
665
666 void setActiveEntry(int entryIndex) {
667 assert(entryIndex >= 0 && entryIndex < (int)entryPointList.size() &&
668 "invalid entry point index");
669 activeEntry = entryIndex;
670 }
671
676 const semantics::Symbol *symbol = entryPointList[activeEntry].first;
677 if (!symbol)
678 llvm::report_fatal_error(
679 "not inside a procedure; do not call on main program.");
680 return *symbol;
681 }
682
686 if (!isMainProgram()) {
687 llvm::report_fatal_error("call only on main program.");
688 }
689 return entryPointList[activeEntry].first;
690 }
691
695 return entryPointList[activeEntry].second;
696 }
697
698 //===--------------------------------------------------------------------===//
699 // Host associations
700 //===--------------------------------------------------------------------===//
701
702 void setHostAssociatedSymbols(
703 const llvm::SetVector<const semantics::Symbol *> &symbols) {
704 hostAssociations.addSymbolsToBind(symbols, getScope());
705 }
706
710
715
718 bool parentHasHostAssoc();
719
722 HostAssociations &getHostAssoc() { return hostAssociations; }
723 const HostAssociations &getHostAssoc() const { return hostAssociations; };
724
725 LLVM_DUMP_METHOD void dump() const;
726
728 const Fortran::semantics::Scope &getScope() const { return *scope; }
729
731 std::optional<FunctionStatement> beginStmt;
732 FunctionStatement endStmt;
733 const semantics::Scope *scope;
734 LabelEvalMap labelEvaluationMap;
735 SymbolLabelMap assignSymbolLabelMap;
736 ContainedUnitList containedUnitList;
737 EvaluationList evaluationList;
744 entryPointList{std::pair{nullptr, nullptr}};
746 int activeEntry = 0;
750 bool hasIeeeAccess{false};
751 bool mayModifyHaltingMode{false};
752 bool mayModifyRoundingMode{false};
753 bool mayModifyUnderflowMode{false};
755 mlir::Block *finalBlock{};
756 HostAssociations hostAssociations;
758 std::list<Fortran::semantics::PreservedUseStmt> preservedUseStmts;
759};
760
762struct ModuleLikeUnit : public ProgramUnit {
763 // wrapper statements for module-like syntactic structures
764 using ModuleStatement =
765 ReferenceVariant<parser::Statement<parser::ModuleStmt>,
769
770 ModuleLikeUnit(const parser::Module &m, const PftNode &parent);
771 ModuleLikeUnit(const parser::Submodule &m, const PftNode &parent);
772 ~ModuleLikeUnit() = default;
773 ModuleLikeUnit(ModuleLikeUnit &&) = default;
774 ModuleLikeUnit(const ModuleLikeUnit &) = delete;
775
776 LLVM_DUMP_METHOD void dump() const;
777
780
782 const Fortran::semantics::Scope &getScope() const;
783
784 ModuleStatement beginStmt;
785 ModuleStatement endStmt;
786 ContainedUnitList containedUnitList;
787 EvaluationList evaluationList;
789 std::list<Fortran::semantics::PreservedUseStmt> preservedUseStmts;
790};
791
794struct BlockDataUnit : public ProgramUnit {
795 BlockDataUnit(const parser::BlockData &bd, const PftNode &parent,
796 const Fortran::semantics::SemanticsContext &semanticsContext);
797 BlockDataUnit(BlockDataUnit &&) = default;
798 BlockDataUnit(const BlockDataUnit &) = delete;
799
800 LLVM_DUMP_METHOD void dump() const;
801
802 const Fortran::semantics::Scope &symTab; // symbol table
803};
804
805// Top level compiler directives
806struct CompilerDirectiveUnit : public ProgramUnit {
807 CompilerDirectiveUnit(const parser::CompilerDirective &directive,
808 const PftNode &parent)
809 : ProgramUnit{directive, parent} {};
810 CompilerDirectiveUnit(CompilerDirectiveUnit &&) = default;
811 CompilerDirectiveUnit(const CompilerDirectiveUnit &) = delete;
812};
813
814// Top level OpenACC routine directives
815struct OpenACCDirectiveUnit : public ProgramUnit {
816 OpenACCDirectiveUnit(const parser::OpenACCRoutineConstruct &directive,
817 const PftNode &parent)
818 : ProgramUnit{directive, parent}, routine{directive} {};
819 OpenACCDirectiveUnit(OpenACCDirectiveUnit &&) = default;
820 OpenACCDirectiveUnit(const OpenACCDirectiveUnit &) = delete;
821 const parser::OpenACCRoutineConstruct &routine;
822};
823
825struct Program {
826 using Units = std::variant<FunctionLikeUnit, ModuleLikeUnit, BlockDataUnit,
828
829 Program(semantics::CommonBlockList &&commonBlocks)
830 : commonBlocks{std::move(commonBlocks)} {}
831 Program(Program &&) = default;
832 Program(const Program &) = delete;
833
834 const std::list<Units> &getUnits() const { return units; }
835 std::list<Units> &getUnits() { return units; }
836 const semantics::CommonBlockList &getCommonBlocks() const {
837 return commonBlocks;
838 }
839 ScopeVariableListMap &getScopeVariableListMap() {
840 return scopeVariableListMap;
841 }
842
844 LLVM_DUMP_METHOD void dump() const;
845
846private:
847 std::list<Units> units;
848 semantics::CommonBlockList commonBlocks;
849 ScopeVariableListMap scopeVariableListMap; // module and submodule scopes
850};
851
854template <typename T>
855static parser::CharBlock stmtSourceLoc(const T &stmt) {
856 return stmt.visit(common::visitors{[](const auto &x) { return x.source; }});
857}
858
860template <typename ParentType, typename A>
861ParentType *getAncestor(A &node) {
862 if (auto *seekedParent = node.parent.template getIf<ParentType>())
863 return seekedParent;
864 return node.parent.visit(common::visitors{
865 [](Program &p) -> ParentType * { return nullptr; },
866 [](auto &p) -> ParentType * { return getAncestor<ParentType>(p); }});
867}
868
870template <typename A>
871ScopeVariableListMap &getScopeVariableListMap(A &node) {
872 Program *pftRoot = getAncestor<Program>(node);
873 assert(pftRoot && "pft must have a root");
874 return pftRoot->getScopeVariableListMap();
875}
876
879void visitAllSymbols(const FunctionLikeUnit &funit,
880 std::function<void(const semantics::Symbol &)> callBack);
881
884void visitAllSymbols(const Evaluation &eval,
885 std::function<void(const semantics::Symbol &)> callBack);
886
890bool isWrappableConstruct(const Evaluation &eval,
891 const semantics::SemanticsContext &semaCtx);
892
893} // namespace Fortran::lower::pft
894
895namespace Fortran::lower {
896class LoweringOptions;
897
906std::unique_ptr<pft::Program>
907createPFT(const parser::Program &root,
908 const Fortran::semantics::SemanticsContext &semanticsContext,
909 const LoweringOptions &loweringOptions);
910
912void dumpPFT(llvm::raw_ostream &outputStream, const pft::Program &pft);
913} // namespace Fortran::lower
914
915#endif // FORTRAN_LOWER_PFTBUILDER_H
Definition reference.h:18
Definition HostAssociations.h:28
void addSymbolsToBind(const llvm::SetVector< const Fortran::semantics::Symbol * > &symbols, const Fortran::semantics::Scope &hostScope)
Definition HostAssociations.cpp:541
Definition LoweringOptions.h:35
Definition char-block.h:26
Definition scope.h:68
Definition semantics.h:67
Definition symbol.h:907
Definition OpenACC.h:20
Definition ParserActions.h:24
void dumpPFT(llvm::raw_ostream &outputStream, const pft::Program &pft)
Dumper for displaying a PFT.
Definition PFTBuilder.cpp:2114
std::unique_ptr< pft::Program > createPFT(const parser::Program &root, const Fortran::semantics::SemanticsContext &semanticsContext, const LoweringOptions &loweringOptions)
Definition PFTBuilder.cpp:2106
Definition idioms.h:60
Definition PFTBuilder.h:794
LLVM_DUMP_METHOD void dump() const
The BlockDataUnit dump is just the associated symbol table.
Definition PFTBuilder.cpp:2174
Definition PFTBuilder.h:221
FunctionLikeUnit * getOwningProcedure() const
Return the FunctionLikeUnit containing this evaluation (or nullptr).
Definition PFTBuilder.cpp:1657
Evaluation(const A &a, const PftNode &parent)
Construct and Directive ctor.
Definition PFTBuilder.h:233
EvaluationList & getNestedEvaluations()
Return nested evaluation list.
Definition PFTBuilder.h:307
Evaluation(const A &a, const PftNode &parent, const parser::CharBlock &position, const std::optional< parser::Label > &label)
General ctor.
Definition PFTBuilder.h:225
Evaluation & nonNopSuccessor() const
Definition PFTBuilder.h:293
constexpr bool isIntermediateConstructStmt() const
Definition PFTBuilder.h:283
constexpr bool isActionStmt() const
Evaluation classification predicates.
Definition PFTBuilder.h:240
bool hasNestedEvaluations() const
Return true if this Evaluation has at least one nested evaluation.
Definition PFTBuilder.h:302
Definition PFTBuilder.h:632
Evaluation * getEntryEval() const
Definition PFTBuilder.h:694
llvm::SmallVector< std::pair< const semantics::Symbol *, Evaluation * >, 1 > entryPointList
Definition PFTBuilder.h:744
HostAssociations & parentHostAssoc()
Definition PFTBuilder.cpp:2020
bool parentHasHostAssoc()
Definition PFTBuilder.cpp:2032
int activeEntry
Current index into entryPointList. Index 0 is the primary entry point.
Definition PFTBuilder.h:746
mlir::Block * finalBlock
Terminal basic block (if any)
Definition PFTBuilder.h:755
std::list< Fortran::semantics::PreservedUseStmt > preservedUseStmts
Preserved USE statements for debug info generation.
Definition PFTBuilder.h:758
parser::CharBlock getStartingSourceLoc() const
Get the starting source location for this function like unit.
Definition PFTBuilder.cpp:2039
HostAssociations & getHostAssoc()
Definition PFTBuilder.h:722
const semantics::Symbol * primaryResult
Definition PFTBuilder.h:749
std::optional< FunctionStatement > beginStmt
Anonymous programs do not have a begin statement.
Definition PFTBuilder.h:731
const semantics::Symbol * getMainProgramSymbol() const
Definition PFTBuilder.h:685
const Fortran::semantics::Scope & getScope() const
Get the function scope.
Definition PFTBuilder.h:728
const semantics::Symbol & getSubprogramSymbol() const
Definition PFTBuilder.h:675
bool parentHasTupleHostAssoc()
Definition PFTBuilder.cpp:2026
Module-like units contain a list of function-like units.
Definition PFTBuilder.h:762
parser::CharBlock getStartingSourceLoc() const
Get the starting source location for this module like unit.
Definition PFTBuilder.cpp:2061
std::list< Fortran::semantics::PreservedUseStmt > preservedUseStmts
Preserved USE statements for debug info generation.
Definition PFTBuilder.h:789
const Fortran::semantics::Scope & getScope() const
Get the module scope.
Definition PFTBuilder.cpp:2065
A Program is the top-level root of the PFT.
Definition PFTBuilder.h:825
LLVM_DUMP_METHOD void dump() const
LLVM dump method on a Program.
Definition PFTBuilder.cpp:2119
std::size_t getOffset() const
Get offset of the aggregate inside its scope.
Definition PFTBuilder.h:460
const semantics::Symbol & getNamingSymbol() const
Returns the symbol that gives its name to the aggregate.
Definition PFTBuilder.h:466
const semantics::Symbol * namingSymbol
Symbol that gives its name to the aggregate. Always set by constructor.
Definition PFTBuilder.h:474
const semantics::Symbol * initialValueSymbol
Compiler generated symbol with the aggregate initial value if any.
Definition PFTBuilder.h:476
bool isGlobalAggregate
Is this a global aggregate?
Definition PFTBuilder.h:478
Interval interval
<offset, size> of the aggregate in its scope.
Definition PFTBuilder.h:472
const semantics::Symbol * getInitialValueSymbol() const
Returns symbols holding the aggregate initial value if any.
Definition PFTBuilder.h:462
const semantics::Scope & getOwningScope() const
Scope to which the aggregates belongs to.
Definition PFTBuilder.h:468
Definition PFTBuilder.h:424
Definition PFTBuilder.h:420
bool isAggregateStore() const
Is this an aggregate store?
Definition PFTBuilder.h:511
bool isRuntimeTypeInfoData() const
Is this variable a compiler generated global to describe derived types?
Definition PFTBuilder.cpp:2088
bool isGlobal() const
Is this variable a global?
Definition PFTBuilder.h:516
bool isModuleOrSubmoduleVariable() const
Is this a module or submodule variable?
Definition PFTBuilder.h:522
bool isAlias() const
Definition PFTBuilder.h:553
std::tuple< std::size_t, std::size_t > Interval
<offset, size> pair
Definition PFTBuilder.h:441
bool hasSymbol() const
Only nominal variable have front-end symbols.
Definition PFTBuilder.h:508
const Interval & getInterval() const
Return the interval range of an aggregate store.
Definition PFTBuilder.h:502
const Fortran::semantics::Symbol & getSymbol() const
Return the front-end symbol for a nominal variable.
Definition PFTBuilder.h:487
int getDepth() const
The depth is recorded for nominal variables as a debugging aid.
Definition PFTBuilder.h:592
const AggregateStore & getAggregateStore() const
Return the aggregate store.
Definition PFTBuilder.h:496
Definition parse-tree.h:2022
Definition parse-tree.h:3544
Definition parse-tree.h:3549
Definition parse-tree.h:3554
Definition parse-tree.h:2048
Definition parse-tree.h:2203
Definition parse-tree.h:2194
Definition parse-tree.h:2225
Definition parse-tree.h:3064
Definition parse-tree.h:6010
Definition parse-tree.h:3346
Definition parse-tree.h:2466
Definition parse-tree.h:2454
Definition parse-tree.h:2256
Definition parse-tree.h:2241
Definition parse-tree.h:2725
Definition parse-tree.h:3433
Definition parse-tree.h:2553
Definition parse-tree.h:2272
Definition parse-tree.h:2263
Definition parse-tree.h:2042
Definition parse-tree.h:2368
Definition parse-tree.h:2388
Definition parse-tree.h:2250
Definition parse-tree.h:2607
Definition parse-tree.h:2621
Definition parse-tree.h:2138
Definition parse-tree.h:2173
Definition parse-tree.h:2150
Definition parse-tree.h:2633
Definition parse-tree.h:3366
Definition parse-tree.h:2402
Definition parse-tree.h:2418
Definition parse-tree.h:2381
Definition parse-tree.h:2951
Definition parse-tree.h:2647
Definition parse-tree.h:2972
Definition parse-tree.h:2105
Definition parse-tree.h:3008
Definition parse-tree.h:2351
Definition parse-tree.h:2575
Definition parse-tree.h:5984
Definition parse-tree.h:5846
Definition parse-tree.h:5670
Definition parse-tree.h:2070
Definition parse-tree.h:2825
Definition parse-tree.h:2788
Definition parse-tree.h:2425
Definition parse-tree.h:2489
Definition parse-tree.h:2501
Definition parse-tree.h:2480
Definition parse-tree.h:2535
Definition parse-tree.h:2515
Definition parse-tree.h:3392
Definition parse-tree.h:362
Definition parse-tree.h:2567
Definition parse-tree.h:3050
Definition parse-tree.h:3376
Definition parse-tree.h:2585
Definition parse-tree.h:2598
Definition parse-tree.h:2524
Definition parse-tree.h:2657
Definition parse-tree.h:2089
Definition parse-tree.h:2120
Definition parse-tree.h:2083
Definition parse-tree.h:2810