| 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 | |