xref: /llvm-project/flang/lib/Lower/OpenMP/DataSharingProcessor.h (revision 1fcb6a9754a8db057e18f629cb90011b638901e7)
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 (!std::holds_alternative<parser::OpenMPCriticalConstruct>(omp.u))
49         currentConstruct = &omp;
50       return true;
51     }
52 
53     void Post(const parser::OpenMPConstruct &omp) {
54       currentConstruct = nullptr;
55     }
56 
57     void Post(const parser::Name &name) {
58       symDefMap.try_emplace(name.symbol, currentConstruct);
59     }
60 
61     const parser::OpenMPConstruct *currentConstruct = nullptr;
62     llvm::DenseMap<semantics::Symbol *, const parser::OpenMPConstruct *>
63         symDefMap;
64 
65     /// Given a \p symbol and an \p eval, returns true if eval is the OMP
66     /// construct that defines symbol.
67     bool isSymbolDefineBy(const semantics::Symbol *symbol,
68                           lower::pft::Evaluation &eval) const;
69   };
70 
71   mlir::OpBuilder::InsertPoint lastPrivIP;
72   llvm::SmallVector<mlir::Value> loopIVs;
73   // Symbols in private, firstprivate, and/or lastprivate clauses.
74   llvm::SetVector<const semantics::Symbol *> explicitlyPrivatizedSymbols;
75   llvm::SetVector<const semantics::Symbol *> defaultSymbols;
76   llvm::SetVector<const semantics::Symbol *> implicitSymbols;
77   llvm::SetVector<const semantics::Symbol *> preDeterminedSymbols;
78   llvm::SetVector<const semantics::Symbol *> allPrivatizedSymbols;
79 
80   llvm::DenseMap<const semantics::Symbol *, mlir::omp::PrivateClauseOp>
81       symToPrivatizer;
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   bool callsInitClone = false;
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();
104   void collectDefaultSymbols();
105   void collectImplicitSymbols();
106   void collectPreDeterminedSymbols();
107   void privatize(mlir::omp::PrivateClauseOps *clauseOps);
108   void doPrivatize(const semantics::Symbol *sym,
109                    mlir::omp::PrivateClauseOps *clauseOps);
110   void copyLastPrivatize(mlir::Operation *op);
111   void insertLastPrivateCompare(mlir::Operation *op);
112   void cloneSymbol(const semantics::Symbol *sym);
113   void
114   copyFirstPrivateSymbol(const semantics::Symbol *sym,
115                          mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr);
116   void copyLastPrivateSymbol(const semantics::Symbol *sym,
117                              mlir::OpBuilder::InsertPoint *lastPrivIP);
118   void insertDeallocs();
119 
120 public:
121   DataSharingProcessor(lower::AbstractConverter &converter,
122                        semantics::SemanticsContext &semaCtx,
123                        const List<Clause> &clauses,
124                        lower::pft::Evaluation &eval,
125                        bool shouldCollectPreDeterminedSymbols,
126                        bool useDelayedPrivatization, lower::SymMap &symTable);
127 
128   // Privatisation is split into two steps.
129   // Step1 performs cloning of all privatisation clauses and copying for
130   // firstprivates. Step1 is performed at the place where process/processStep1
131   // is called. This is usually inside the Operation corresponding to the OpenMP
132   // construct, for looping constructs this is just before the Operation. The
133   // split into two steps was performed basically to be able to call
134   // privatisation for looping constructs before the operation is created since
135   // the bounds of the MLIR OpenMP operation can be privatised.
136   // Step2 performs the copying for lastprivates and requires knowledge of the
137   // MLIR operation to insert the last private update. Step2 adds
138   // dealocation code as well.
139   void processStep1(mlir::omp::PrivateClauseOps *clauseOps = nullptr);
140   void processStep2(mlir::Operation *op, bool isLoop);
141 
142   void pushLoopIV(mlir::Value iv) { loopIVs.push_back(iv); }
143 
144   const llvm::SetVector<const semantics::Symbol *> &
145   getAllSymbolsToPrivatize() const {
146     return allPrivatizedSymbols;
147   }
148 
149   llvm::ArrayRef<const semantics::Symbol *> getDelayedPrivSymbols() const {
150     return useDelayedPrivatization
151                ? allPrivatizedSymbols.getArrayRef()
152                : llvm::ArrayRef<const semantics::Symbol *>();
153   }
154 };
155 
156 } // namespace omp
157 } // namespace lower
158 } // namespace Fortran
159 
160 #endif // FORTRAN_LOWER_DATASHARINGPROCESSOR_H
161