198 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/10//11//===----------------------------------------------------------------------===//12#ifndef FORTRAN_LOWER_DATASHARINGPROCESSOR_H13#define FORTRAN_LOWER_DATASHARINGPROCESSOR_H14 15#include "flang/Lower/AbstractConverter.h"16#include "flang/Lower/OpenMP.h"17#include "flang/Lower/OpenMP/Clauses.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#include <variant>23 24namespace mlir {25namespace omp {26struct PrivateClauseOps;27} // namespace omp28} // namespace mlir29 30namespace Fortran {31namespace lower {32namespace omp {33 34class DataSharingProcessor {35private:36 /// A symbol visitor that keeps track of the currently active OpenMPConstruct37 /// at any point in time. This is used to track Symbol definition scopes in38 /// order to tell which OMP scope defined vs. references a certain Symbol.39 struct OMPConstructSymbolVisitor {40 OMPConstructSymbolVisitor(semantics::SemanticsContext &ctx)41 : version(ctx.langOptions().OpenMPVersion) {}42 template <typename T>43 bool Pre(const T &) {44 return true;45 }46 template <typename T>47 void Post(const T &) {}48 49 bool Pre(const parser::OpenMPConstruct &omp) {50 // Skip constructs that may not have privatizations.51 if (isOpenMPPrivatizingConstruct(omp, version))52 constructs.push_back(&omp);53 return true;54 }55 56 void Post(const parser::OpenMPConstruct &omp) {57 if (isOpenMPPrivatizingConstruct(omp, version))58 constructs.pop_back();59 }60 61 void Post(const parser::Name &name) {62 auto current = !constructs.empty() ? constructs.back() : ConstructPtr();63 symDefMap.try_emplace(name.symbol, current);64 }65 66 bool Pre(const parser::DeclarationConstruct &decl) {67 constructs.push_back(&decl);68 return true;69 }70 71 void Post(const parser::DeclarationConstruct &decl) {72 constructs.pop_back();73 }74 75 /// Given a \p symbol and an \p eval, returns true if eval is the OMP76 /// construct that defines symbol.77 bool isSymbolDefineBy(const semantics::Symbol *symbol,78 lower::pft::Evaluation &eval) const;79 80 // Given a \p symbol, returns true if it is defined by a nested81 // `DeclarationConstruct`.82 bool83 isSymbolDefineByNestedDeclaration(const semantics::Symbol *symbol) const;84 85 private:86 using ConstructPtr = std::variant<const parser::OpenMPConstruct *,87 const parser::DeclarationConstruct *>;88 llvm::SmallVector<ConstructPtr> constructs;89 llvm::DenseMap<semantics::Symbol *, ConstructPtr> symDefMap;90 91 unsigned version;92 };93 94 mlir::OpBuilder::InsertPoint lastPrivIP;95 llvm::SmallVector<mlir::Value> loopIVs;96 // Symbols in private, firstprivate, and/or lastprivate clauses.97 llvm::SetVector<const semantics::Symbol *> explicitlyPrivatizedSymbols;98 llvm::SetVector<const semantics::Symbol *> defaultSymbols;99 llvm::SetVector<const semantics::Symbol *> implicitSymbols;100 llvm::SetVector<const semantics::Symbol *> preDeterminedSymbols;101 llvm::SetVector<const semantics::Symbol *> allPrivatizedSymbols;102 103 lower::AbstractConverter &converter;104 semantics::SemanticsContext &semaCtx;105 fir::FirOpBuilder &firOpBuilder;106 omp::List<omp::Clause> clauses;107 lower::pft::Evaluation &eval;108 bool shouldCollectPreDeterminedSymbols;109 bool useDelayedPrivatization;110 llvm::SmallPtrSet<const semantics::Symbol *, 16> mightHaveReadHostSym;111 lower::SymMap &symTable;112 bool isTargetPrivatization;113 OMPConstructSymbolVisitor visitor;114 115 bool needBarrier();116 void collectSymbols(semantics::Symbol::Flag flag,117 llvm::SetVector<const semantics::Symbol *> &symbols);118 void collectSymbolsInNestedRegions(119 lower::pft::Evaluation &eval, semantics::Symbol::Flag flag,120 llvm::SetVector<const semantics::Symbol *> &symbolsInNestedRegions);121 void collectOmpObjectListSymbol(122 const omp::ObjectList &objects,123 llvm::SetVector<const semantics::Symbol *> &symbolSet);124 void collectSymbolsForPrivatization();125 void insertBarrier(mlir::omp::PrivateClauseOps *clauseOps);126 void collectDefaultSymbols();127 void collectImplicitSymbols();128 void collectPreDeterminedSymbols();129 void privatize(mlir::omp::PrivateClauseOps *clauseOps,130 std::optional<llvm::omp::Directive> dir = std::nullopt);131 void copyLastPrivatize(mlir::Operation *op);132 void insertLastPrivateCompare(mlir::Operation *op);133 void cloneSymbol(const semantics::Symbol *sym);134 void135 copyFirstPrivateSymbol(const semantics::Symbol *sym,136 mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr);137 void copyLastPrivateSymbol(const semantics::Symbol *sym,138 mlir::OpBuilder::InsertPoint *lastPrivIP);139 void insertDeallocs();140 141 static bool isOpenMPPrivatizingConstruct(const parser::OpenMPConstruct &omp,142 unsigned version);143 bool isOpenMPPrivatizingEvaluation(const pft::Evaluation &eval) const;144 145public:146 DataSharingProcessor(lower::AbstractConverter &converter,147 semantics::SemanticsContext &semaCtx,148 const List<Clause> &clauses,149 lower::pft::Evaluation &eval,150 bool shouldCollectPreDeterminedSymbols,151 bool useDelayedPrivatization, lower::SymMap &symTable,152 bool isTargetPrivatization = false);153 154 DataSharingProcessor(lower::AbstractConverter &converter,155 semantics::SemanticsContext &semaCtx,156 lower::pft::Evaluation &eval,157 bool useDelayedPrivatization, lower::SymMap &symTable,158 bool isTargetPrivatization = false);159 160 // Privatisation is split into two steps.161 // Step1 performs cloning of all privatisation clauses and copying for162 // firstprivates. Step1 is performed at the place where process/processStep1163 // is called. This is usually inside the Operation corresponding to the OpenMP164 // construct, for looping constructs this is just before the Operation. The165 // split into two steps was performed basically to be able to call166 // privatisation for looping constructs before the operation is created since167 // the bounds of the MLIR OpenMP operation can be privatised.168 // Step2 performs the copying for lastprivates and requires knowledge of the169 // MLIR operation to insert the last private update. Step2 adds170 // dealocation code as well.171 void processStep1(mlir::omp::PrivateClauseOps *clauseOps = nullptr,172 std::optional<llvm::omp::Directive> dir = std::nullopt);173 void processStep2(mlir::Operation *op, bool isLoop);174 175 void pushLoopIV(mlir::Value iv) { loopIVs.push_back(iv); }176 177 const llvm::SetVector<const semantics::Symbol *> &178 getAllSymbolsToPrivatize() const {179 return allPrivatizedSymbols;180 }181 182 llvm::ArrayRef<const semantics::Symbol *> getDelayedPrivSymbols() const {183 return useDelayedPrivatization184 ? allPrivatizedSymbols.getArrayRef()185 : llvm::ArrayRef<const semantics::Symbol *>();186 }187 188 void privatizeSymbol(const semantics::Symbol *symToPrivatize,189 mlir::omp::PrivateClauseOps *clauseOps,190 std::optional<llvm::omp::Directive> dir = std::nullopt);191};192 193} // namespace omp194} // namespace lower195} // namespace Fortran196 197#endif // FORTRAN_LOWER_DATASHARINGPROCESSOR_H198