xref: /llvm-project/flang/lib/Semantics/check-omp-structure.h (revision 15ab7be2e049bc0f4ea6744ca037395686a923bc)
1 //===-- lib/Semantics/check-omp-structure.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 // OpenMP structure validity check list
10 //    1. invalid clauses on directive
11 //    2. invalid repeated clauses on directive
12 //    3. TODO: invalid nesting of regions
13 
14 #ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
15 #define FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
16 
17 #include "check-directive-structure.h"
18 #include "flang/Common/enum-set.h"
19 #include "flang/Parser/parse-tree.h"
20 #include "flang/Semantics/openmp-directive-sets.h"
21 #include "flang/Semantics/semantics.h"
22 #include "llvm/Frontend/OpenMP/OMPConstants.h"
23 
24 using OmpClauseSet =
25     Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
26 
27 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
28 #include "llvm/Frontend/OpenMP/OMP.inc"
29 
30 namespace llvm {
31 namespace omp {
32 static OmpClauseSet privateSet{
33     Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
34 static OmpClauseSet privateReductionSet{
35     OmpClauseSet{Clause::OMPC_reduction} | privateSet};
36 // omp.td cannot differentiate allowed/not allowed clause list for few
37 // directives for fortran. nowait is not allowed on begin directive clause list
38 // for below list of directives. Directives with conflicting list of clauses are
39 // included in below list.
40 static const OmpDirectiveSet noWaitClauseNotAllowedSet{
41     Directive::OMPD_do,
42     Directive::OMPD_do_simd,
43     Directive::OMPD_sections,
44     Directive::OMPD_single,
45     Directive::OMPD_workshare,
46 };
47 } // namespace omp
48 } // namespace llvm
49 
50 namespace Fortran::semantics {
51 
52 // Mapping from 'Symbol' to 'Source' to keep track of the variables
53 // used in multiple clauses
54 using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
55 // Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
56 using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
57     std::pair<llvm::omp::Directive, const OmpClauseSet>>;
58 
59 class OmpStructureChecker
60     : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
61           parser::OmpClause, llvm::omp::Clause_enumSize> {
62 public:
63   using Base = DirectiveStructureChecker<llvm::omp::Directive,
64       llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>;
65 
66   OmpStructureChecker(SemanticsContext &context)
67       : DirectiveStructureChecker(context,
68 #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
69 #include "llvm/Frontend/OpenMP/OMP.inc"
70         ) {
71   }
72   using llvmOmpClause = const llvm::omp::Clause;
73 
74   void Enter(const parser::OpenMPConstruct &);
75   void Leave(const parser::OpenMPConstruct &);
76   void Enter(const parser::OpenMPDeclarativeConstruct &);
77   void Leave(const parser::OpenMPDeclarativeConstruct &);
78 
79   void Enter(const parser::OpenMPLoopConstruct &);
80   void Leave(const parser::OpenMPLoopConstruct &);
81   void Enter(const parser::OmpEndLoopDirective &);
82   void Leave(const parser::OmpEndLoopDirective &);
83 
84   void Enter(const parser::OpenMPBlockConstruct &);
85   void Leave(const parser::OpenMPBlockConstruct &);
86   void Leave(const parser::OmpBeginBlockDirective &);
87   void Enter(const parser::OmpEndBlockDirective &);
88   void Leave(const parser::OmpEndBlockDirective &);
89 
90   void Enter(const parser::OpenMPSectionsConstruct &);
91   void Leave(const parser::OpenMPSectionsConstruct &);
92   void Enter(const parser::OmpEndSectionsDirective &);
93   void Leave(const parser::OmpEndSectionsDirective &);
94 
95   void Enter(const parser::OpenMPDeclareSimdConstruct &);
96   void Leave(const parser::OpenMPDeclareSimdConstruct &);
97   void Enter(const parser::OpenMPDeclarativeAllocate &);
98   void Leave(const parser::OpenMPDeclarativeAllocate &);
99   void Enter(const parser::OpenMPDeclareMapperConstruct &);
100   void Leave(const parser::OpenMPDeclareMapperConstruct &);
101   void Enter(const parser::OpenMPDeclareTargetConstruct &);
102   void Leave(const parser::OpenMPDeclareTargetConstruct &);
103   void Enter(const parser::OpenMPDepobjConstruct &);
104   void Leave(const parser::OpenMPDepobjConstruct &);
105   void Enter(const parser::OmpDeclareTargetWithList &);
106   void Enter(const parser::OmpDeclareTargetWithClause &);
107   void Leave(const parser::OmpDeclareTargetWithClause &);
108   void Enter(const parser::OpenMPDispatchConstruct &);
109   void Leave(const parser::OpenMPDispatchConstruct &);
110   void Enter(const parser::OmpErrorDirective &);
111   void Leave(const parser::OmpErrorDirective &);
112   void Enter(const parser::OpenMPExecutableAllocate &);
113   void Leave(const parser::OpenMPExecutableAllocate &);
114   void Enter(const parser::OpenMPAllocatorsConstruct &);
115   void Leave(const parser::OpenMPAllocatorsConstruct &);
116   void Enter(const parser::OpenMPRequiresConstruct &);
117   void Leave(const parser::OpenMPRequiresConstruct &);
118   void Enter(const parser::OpenMPThreadprivate &);
119   void Leave(const parser::OpenMPThreadprivate &);
120 
121   void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
122   void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
123   void Enter(const parser::OpenMPFlushConstruct &);
124   void Leave(const parser::OpenMPFlushConstruct &);
125   void Enter(const parser::OpenMPCancelConstruct &);
126   void Leave(const parser::OpenMPCancelConstruct &);
127   void Enter(const parser::OpenMPCancellationPointConstruct &);
128   void Leave(const parser::OpenMPCancellationPointConstruct &);
129   void Enter(const parser::OpenMPCriticalConstruct &);
130   void Leave(const parser::OpenMPCriticalConstruct &);
131   void Enter(const parser::OpenMPAtomicConstruct &);
132   void Leave(const parser::OpenMPAtomicConstruct &);
133 
134   void Leave(const parser::OmpClauseList &);
135   void Enter(const parser::OmpClause &);
136 
137   void Enter(const parser::OmpAtomicRead &);
138   void Leave(const parser::OmpAtomicRead &);
139   void Enter(const parser::OmpAtomicWrite &);
140   void Leave(const parser::OmpAtomicWrite &);
141   void Enter(const parser::OmpAtomicUpdate &);
142   void Leave(const parser::OmpAtomicUpdate &);
143   void Enter(const parser::OmpAtomicCapture &);
144   void Leave(const parser::OmpAtomic &);
145 
146   void Enter(const parser::DoConstruct &);
147   void Leave(const parser::DoConstruct &);
148 
149   void Enter(const parser::OmpDirectiveSpecification &);
150   void Leave(const parser::OmpDirectiveSpecification &);
151 
152   void Enter(const parser::OmpMetadirectiveDirective &);
153   void Leave(const parser::OmpMetadirectiveDirective &);
154 
155   void Enter(const parser::OmpContextSelector &);
156   void Leave(const parser::OmpContextSelector &);
157 
158 #define GEN_FLANG_CLAUSE_CHECK_ENTER
159 #include "llvm/Frontend/OpenMP/OMP.inc"
160 
161   void Leave(const parser::OmpClause::Fail &);
162   void Enter(const parser::OmpFailClause &);
163   void Leave(const parser::OmpFailClause &);
164 
165 private:
166   bool CheckAllowedClause(llvmOmpClause clause);
167   bool IsVariableListItem(const Symbol &sym);
168   bool IsExtendedListItem(const Symbol &sym);
169   bool IsCommonBlock(const Symbol &sym);
170   std::optional<bool> IsContiguous(const parser::OmpObject &object);
171   void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
172       const std::list<parser::Name> &nameList, const parser::CharBlock &item,
173       const std::string &clauseName);
174   void CheckMultListItems();
175   void CheckStructureComponent(
176       const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
177   bool HasInvalidWorksharingNesting(
178       const parser::CharBlock &, const OmpDirectiveSet &);
179   bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
180   void HasInvalidTeamsNesting(
181       const llvm::omp::Directive &dir, const parser::CharBlock &source);
182   void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
183   void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
184   // specific clause related
185   void CheckAllowedMapTypes(const parser::OmpMapType::Value &,
186       const std::list<parser::OmpMapType::Value> &);
187   llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
188   llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
189 
190   template < //
191       typename LessTy, typename RangeTy,
192       typename IterTy = decltype(std::declval<RangeTy>().begin())>
193   std::optional<IterTy> FindDuplicate(RangeTy &&);
194 
195   const Symbol *GetObjectSymbol(const parser::OmpObject &object);
196   std::optional<parser::CharBlock> GetObjectSource(
197       const parser::OmpObject &object);
198   void CheckDependList(const parser::DataRef &);
199   void CheckDependArraySection(
200       const common::Indirection<parser::ArrayElement> &, const parser::Name &);
201   void CheckDoacross(const parser::OmpDoacross &doa);
202   bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
203   void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
204       const parser::OmpObjectList &objList, llvm::StringRef clause = "");
205   void CheckThreadprivateOrDeclareTargetVar(
206       const parser::OmpObjectList &objList);
207   void CheckSymbolNames(
208       const parser::CharBlock &source, const parser::OmpObjectList &objList);
209   void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
210   void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
211   void CheckCrayPointee(const parser::OmpObjectList &objectList,
212       llvm::StringRef clause, bool suggestToUseCrayPointer = true);
213   void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
214   void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
215   void CheckCopyingPolymorphicAllocatable(
216       SymbolSourceMap &, const llvm::omp::Clause);
217   void CheckPrivateSymbolsInOuterCxt(
218       SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
219   const parser::Name GetLoopIndex(const parser::DoConstruct *x);
220   void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
221   void CheckIsLoopIvPartOfClause(
222       llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
223   bool CheckTargetBlockOnlyTeams(const parser::Block &);
224   void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
225 
226   void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
227   void CheckIteratorModifier(const parser::OmpIterator &x);
228   void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
229   void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
230   void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
231   template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
232   void CheckAtomicMemoryOrderClause(
233       const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *);
234   void CheckAtomicUpdateStmt(const parser::AssignmentStmt &);
235   void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
236   void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
237   void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &);
238   void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &);
239   void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
240   void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
241   void CheckSIMDNest(const parser::OpenMPConstruct &x);
242   void CheckTargetNest(const parser::OpenMPConstruct &x);
243   void CheckTargetUpdate();
244   void CheckDependenceType(const parser::OmpDependenceType::Value &x);
245   void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
246   void CheckCancellationNest(
247       const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
248   std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
249   void CheckReductionObjects(
250       const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
251   bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
252       parser::CharBlock source, llvm::omp::Clause clauseId);
253   void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
254       const parser::OmpReductionIdentifier &ident);
255   void CheckReductionModifier(const parser::OmpReductionModifier &);
256   void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
257   void ChecksOnOrderedAsBlock();
258   void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
259   void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
260   void ChecksOnOrderedAsStandalone();
261   void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
262   void CheckReductionArraySection(
263       const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
264   void CheckArraySection(const parser::ArrayElement &arrayElement,
265       const parser::Name &name, const llvm::omp::Clause clause);
266   void CheckSharedBindingInOuterContext(
267       const parser::OmpObjectList &ompObjectList);
268   void CheckIfContiguous(const parser::OmpObject &object);
269   const parser::Name *GetObjectName(const parser::OmpObject &object);
270   const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
271   void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
272       const parser::OmpObjectList &ompObjectList);
273   void CheckPredefinedAllocatorRestriction(
274       const parser::CharBlock &source, const parser::Name &name);
275   bool isPredefinedAllocator{false};
276 
277   void CheckAllowedRequiresClause(llvmOmpClause clause);
278   bool deviceConstructFound_{false};
279 
280   void CheckAlignValue(const parser::OmpClause &);
281 
282   void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
283   void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
284   int GetDirectiveNest(const int index) { return directiveNest_[index]; }
285   template <typename D> void CheckHintClause(D *, D *);
286   inline void ErrIfAllocatableVariable(const parser::Variable &);
287   inline void ErrIfLHSAndRHSSymbolsMatch(
288       const parser::Variable &, const parser::Expr &);
289   inline void ErrIfNonScalarAssignmentStmt(
290       const parser::Variable &, const parser::Expr &);
291   enum directiveNestType : int {
292     SIMDNest,
293     TargetBlockOnlyTeams,
294     TargetNest,
295     DeclarativeNest,
296     ContextSelectorNest,
297     LastType = ContextSelectorNest,
298   };
299   int directiveNest_[LastType + 1] = {0};
300 
301   SymbolSourceMap deferredNonVariables_;
302 
303   using LoopConstruct = std::variant<const parser::DoConstruct *,
304       const parser::OpenMPLoopConstruct *>;
305   std::vector<LoopConstruct> loopStack_;
306   bool isFailClause{false};
307 };
308 
309 /// Find a duplicate entry in the range, and return an iterator to it.
310 /// If there are no duplicate entries, return nullopt.
311 template <typename LessTy, typename RangeTy, typename IterTy>
312 std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
313   // Deal with iterators, since the actual elements may be rvalues (i.e.
314   // have no addresses), for example with custom-constructed ranges that
315   // are not simple c.begin()..c.end().
316   std::set<IterTy, LessTy> uniq;
317   for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
318     if (!uniq.insert(it).second) {
319       return it;
320     }
321   }
322   return std::nullopt;
323 }
324 
325 } // namespace Fortran::semantics
326 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
327