1 | //===-- Lower/OpenMP/DataSharingProcessor.h ---------------------*- 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 | #ifndef FORTRAN_LOWER_DATASHARINGPROCESSOR_H |
13 | #define FORTRAN_LOWER_DATASHARINGPROCESSOR_H |
14 | |
15 | #include "Clauses.h" |
16 | #include "flang/Lower/AbstractConverter.h" |
17 | #include "flang/Lower/OpenMP.h" |
18 | #include "flang/Optimizer/Builder/FIRBuilder.h" |
19 | #include "flang/Parser/parse-tree.h" |
20 | #include "flang/Semantics/symbol.h" |
21 | #include "mlir/Dialect/OpenMP/OpenMPDialect.h" |
22 | |
23 | namespace mlir { |
24 | namespace omp { |
25 | struct PrivateClauseOps; |
26 | } // namespace omp |
27 | } // namespace mlir |
28 | |
29 | namespace Fortran { |
30 | namespace lower { |
31 | namespace omp { |
32 | |
33 | class DataSharingProcessor { |
34 | private: |
35 | /// A symbol visitor that keeps track of the currently active OpenMPConstruct |
36 | /// at any point in time. This is used to track Symbol definition scopes in |
37 | /// order to tell which OMP scope defined vs. references a certain Symbol. |
38 | struct OMPConstructSymbolVisitor { |
39 | template <typename T> |
40 | bool Pre(const T &) { |
41 | return true; |
42 | } |
43 | template <typename T> |
44 | void Post(const T &) {} |
45 | |
46 | bool Pre(const parser::OpenMPConstruct &omp) { |
47 | // Skip constructs that may not have privatizations. |
48 | if (isOpenMPPrivatizingConstruct(omp)) |
49 | constructs.push_back(&omp); |
50 | return true; |
51 | } |
52 | |
53 | void Post(const parser::OpenMPConstruct &omp) { |
54 | if (isOpenMPPrivatizingConstruct(omp)) |
55 | constructs.pop_back(); |
56 | } |
57 | |
58 | void Post(const parser::Name &name) { |
59 | auto *current = !constructs.empty() ? constructs.back() : nullptr; |
60 | symDefMap.try_emplace(name.symbol, current); |
61 | } |
62 | |
63 | llvm::SmallVector<const parser::OpenMPConstruct *> constructs; |
64 | llvm::DenseMap<semantics::Symbol *, const parser::OpenMPConstruct *> |
65 | symDefMap; |
66 | |
67 | /// Given a \p symbol and an \p eval, returns true if eval is the OMP |
68 | /// construct that defines symbol. |
69 | bool isSymbolDefineBy(const semantics::Symbol *symbol, |
70 | lower::pft::Evaluation &eval) const; |
71 | }; |
72 | |
73 | mlir::OpBuilder::InsertPoint lastPrivIP; |
74 | llvm::SmallVector<mlir::Value> loopIVs; |
75 | // Symbols in private, firstprivate, and/or lastprivate clauses. |
76 | llvm::SetVector<const semantics::Symbol *> explicitlyPrivatizedSymbols; |
77 | llvm::SetVector<const semantics::Symbol *> defaultSymbols; |
78 | llvm::SetVector<const semantics::Symbol *> implicitSymbols; |
79 | llvm::SetVector<const semantics::Symbol *> preDeterminedSymbols; |
80 | llvm::SetVector<const semantics::Symbol *> allPrivatizedSymbols; |
81 | |
82 | lower::AbstractConverter &converter; |
83 | semantics::SemanticsContext &semaCtx; |
84 | fir::FirOpBuilder &firOpBuilder; |
85 | omp::List<omp::Clause> clauses; |
86 | lower::pft::Evaluation &eval; |
87 | bool shouldCollectPreDeterminedSymbols; |
88 | bool useDelayedPrivatization; |
89 | llvm::SmallSet<const semantics::Symbol *, 16> mightHaveReadHostSym; |
90 | lower::SymMap &symTable; |
91 | OMPConstructSymbolVisitor visitor; |
92 | |
93 | bool needBarrier(); |
94 | void collectSymbols(semantics::Symbol::Flag flag, |
95 | llvm::SetVector<const semantics::Symbol *> &symbols); |
96 | void collectSymbolsInNestedRegions( |
97 | lower::pft::Evaluation &eval, semantics::Symbol::Flag flag, |
98 | llvm::SetVector<const semantics::Symbol *> &symbolsInNestedRegions); |
99 | void collectOmpObjectListSymbol( |
100 | const omp::ObjectList &objects, |
101 | llvm::SetVector<const semantics::Symbol *> &symbolSet); |
102 | void collectSymbolsForPrivatization(); |
103 | void insertBarrier(mlir::omp::PrivateClauseOps *clauseOps); |
104 | void collectDefaultSymbols(); |
105 | void collectImplicitSymbols(); |
106 | void collectPreDeterminedSymbols(); |
107 | void privatize(mlir::omp::PrivateClauseOps *clauseOps); |
108 | void copyLastPrivatize(mlir::Operation *op); |
109 | void insertLastPrivateCompare(mlir::Operation *op); |
110 | void cloneSymbol(const semantics::Symbol *sym); |
111 | void |
112 | copyFirstPrivateSymbol(const semantics::Symbol *sym, |
113 | mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr); |
114 | void copyLastPrivateSymbol(const semantics::Symbol *sym, |
115 | mlir::OpBuilder::InsertPoint *lastPrivIP); |
116 | void insertDeallocs(); |
117 | |
118 | static bool isOpenMPPrivatizingConstruct(const parser::OpenMPConstruct &omp); |
119 | bool isOpenMPPrivatizingEvaluation(const pft::Evaluation &eval) const; |
120 | |
121 | public: |
122 | DataSharingProcessor(lower::AbstractConverter &converter, |
123 | semantics::SemanticsContext &semaCtx, |
124 | const List<Clause> &clauses, |
125 | lower::pft::Evaluation &eval, |
126 | bool shouldCollectPreDeterminedSymbols, |
127 | bool useDelayedPrivatization, lower::SymMap &symTable); |
128 | |
129 | DataSharingProcessor(lower::AbstractConverter &converter, |
130 | semantics::SemanticsContext &semaCtx, |
131 | lower::pft::Evaluation &eval, |
132 | bool useDelayedPrivatization, lower::SymMap &symTable); |
133 | |
134 | // Privatisation is split into two steps. |
135 | // Step1 performs cloning of all privatisation clauses and copying for |
136 | // firstprivates. Step1 is performed at the place where process/processStep1 |
137 | // is called. This is usually inside the Operation corresponding to the OpenMP |
138 | // construct, for looping constructs this is just before the Operation. The |
139 | // split into two steps was performed basically to be able to call |
140 | // privatisation for looping constructs before the operation is created since |
141 | // the bounds of the MLIR OpenMP operation can be privatised. |
142 | // Step2 performs the copying for lastprivates and requires knowledge of the |
143 | // MLIR operation to insert the last private update. Step2 adds |
144 | // dealocation code as well. |
145 | void processStep1(mlir::omp::PrivateClauseOps *clauseOps = nullptr); |
146 | void processStep2(mlir::Operation *op, bool isLoop); |
147 | |
148 | void pushLoopIV(mlir::Value iv) { loopIVs.push_back(iv); } |
149 | |
150 | const llvm::SetVector<const semantics::Symbol *> & |
151 | getAllSymbolsToPrivatize() const { |
152 | return allPrivatizedSymbols; |
153 | } |
154 | |
155 | llvm::ArrayRef<const semantics::Symbol *> getDelayedPrivSymbols() const { |
156 | return useDelayedPrivatization |
157 | ? allPrivatizedSymbols.getArrayRef() |
158 | : llvm::ArrayRef<const semantics::Symbol *>(); |
159 | } |
160 | |
161 | void privatizeSymbol(const semantics::Symbol *symToPrivatize, |
162 | mlir::omp::PrivateClauseOps *clauseOps); |
163 | }; |
164 | |
165 | } // namespace omp |
166 | } // namespace lower |
167 | } // namespace Fortran |
168 | |
169 | #endif // FORTRAN_LOWER_DATASHARINGPROCESSOR_H |
170 | |