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/semantics.h"
21 #include "llvm/Frontend/OpenMP/OMPConstants.h"
22 
23 using OmpDirectiveSet = Fortran::common::EnumSet<llvm::omp::Directive,
24     llvm::omp::Directive_enumSize>;
25 
26 using OmpClauseSet =
27     Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
28 
29 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
30 #include "llvm/Frontend/OpenMP/OMP.inc"
31 
32 namespace llvm {
33 namespace omp {
34 static OmpDirectiveSet parallelSet{Directive::OMPD_distribute_parallel_do,
35     Directive::OMPD_distribute_parallel_do_simd, Directive::OMPD_parallel,
36     Directive::OMPD_parallel_do, Directive::OMPD_parallel_do_simd,
37     Directive::OMPD_parallel_sections, Directive::OMPD_parallel_workshare,
38     Directive::OMPD_target_parallel, Directive::OMPD_target_parallel_do,
39     Directive::OMPD_target_parallel_do_simd,
40     Directive::OMPD_target_teams_distribute_parallel_do,
41     Directive::OMPD_target_teams_distribute_parallel_do_simd,
42     Directive::OMPD_teams_distribute_parallel_do,
43     Directive::OMPD_teams_distribute_parallel_do_simd};
44 static OmpDirectiveSet doSet{Directive::OMPD_distribute_parallel_do,
45     Directive::OMPD_distribute_parallel_do_simd, Directive::OMPD_parallel_do,
46     Directive::OMPD_parallel_do_simd, Directive::OMPD_do,
47     Directive::OMPD_do_simd, Directive::OMPD_target_parallel_do,
48     Directive::OMPD_target_parallel_do_simd,
49     Directive::OMPD_target_teams_distribute_parallel_do,
50     Directive::OMPD_target_teams_distribute_parallel_do_simd,
51     Directive::OMPD_teams_distribute_parallel_do,
52     Directive::OMPD_teams_distribute_parallel_do_simd};
53 static OmpDirectiveSet doSimdSet{Directive::OMPD_distribute_parallel_do_simd,
54     Directive::OMPD_parallel_do_simd, Directive::OMPD_do_simd,
55     Directive::OMPD_target_parallel_do_simd,
56     Directive::OMPD_target_teams_distribute_parallel_do_simd,
57     Directive::OMPD_teams_distribute_parallel_do_simd};
58 static OmpDirectiveSet workShareSet{
59     OmpDirectiveSet{Directive::OMPD_workshare,
60         Directive::OMPD_parallel_workshare, Directive::OMPD_parallel_sections,
61         Directive::OMPD_sections, Directive::OMPD_single} |
62     doSet};
63 static OmpDirectiveSet taskloopSet{
64     Directive::OMPD_taskloop, Directive::OMPD_taskloop_simd};
65 static OmpDirectiveSet targetSet{Directive::OMPD_target,
66     Directive::OMPD_target_parallel, Directive::OMPD_target_parallel_do,
67     Directive::OMPD_target_parallel_do_simd, Directive::OMPD_target_simd,
68     Directive::OMPD_target_teams, Directive::OMPD_target_teams_distribute,
69     Directive::OMPD_target_teams_distribute_simd};
70 static OmpDirectiveSet simdSet{Directive::OMPD_distribute_parallel_do_simd,
71     Directive::OMPD_distribute_simd, Directive::OMPD_parallel_do_simd,
72     Directive::OMPD_do_simd, Directive::OMPD_simd,
73     Directive::OMPD_target_parallel_do_simd,
74     Directive::OMPD_target_teams_distribute_parallel_do_simd,
75     Directive::OMPD_target_teams_distribute_simd, Directive::OMPD_target_simd,
76     Directive::OMPD_taskloop_simd,
77     Directive::OMPD_teams_distribute_parallel_do_simd,
78     Directive::OMPD_teams_distribute_simd};
79 static OmpDirectiveSet teamSet{Directive::OMPD_teams,
80     Directive::OMPD_teams_distribute,
81     Directive::OMPD_teams_distribute_parallel_do,
82     Directive::OMPD_teams_distribute_parallel_do_simd,
83     Directive::OMPD_teams_distribute_parallel_for,
84     Directive::OMPD_teams_distribute_parallel_for_simd,
85     Directive::OMPD_teams_distribute_simd};
86 static OmpDirectiveSet taskGeneratingSet{
87     OmpDirectiveSet{Directive::OMPD_task} | taskloopSet};
88 static OmpDirectiveSet nestedOrderedErrSet{Directive::OMPD_critical,
89     Directive::OMPD_ordered, Directive::OMPD_atomic, Directive::OMPD_task,
90     Directive::OMPD_taskloop};
91 static OmpDirectiveSet nestedWorkshareErrSet{
92     OmpDirectiveSet{Directive::OMPD_task, Directive::OMPD_taskloop,
93         Directive::OMPD_critical, Directive::OMPD_ordered,
94         Directive::OMPD_atomic, Directive::OMPD_master} |
95     workShareSet};
96 static OmpDirectiveSet nestedMasterErrSet{
97     OmpDirectiveSet{llvm::omp::Directive::OMPD_atomic} | taskGeneratingSet |
98     workShareSet};
99 static OmpDirectiveSet nestedBarrierErrSet{
100     OmpDirectiveSet{Directive::OMPD_critical, Directive::OMPD_ordered,
101         Directive::OMPD_atomic, Directive::OMPD_master} |
102     taskGeneratingSet | workShareSet};
103 static OmpClauseSet privateSet{
104     Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
105 static OmpClauseSet privateReductionSet{
106     OmpClauseSet{Clause::OMPC_reduction} | privateSet};
107 } // namespace omp
108 } // namespace llvm
109 
110 namespace Fortran::semantics {
111 
112 // Mapping from 'Symbol' to 'Source' to keep track of the variables
113 // used in multiple clauses
114 using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
115 // Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
116 using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
117     std::pair<llvm::omp::Directive, const OmpClauseSet>>;
118 
119 class OmpStructureChecker
120     : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
121           parser::OmpClause, llvm::omp::Clause_enumSize> {
122 public:
OmpStructureChecker(SemanticsContext & context)123   OmpStructureChecker(SemanticsContext &context)
124       : DirectiveStructureChecker(context,
125 #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
126 #include "llvm/Frontend/OpenMP/OMP.inc"
127         ) {
128   }
129   using llvmOmpClause = const llvm::omp::Clause;
130 
131   void Enter(const parser::OpenMPConstruct &);
132   void Enter(const parser::OpenMPLoopConstruct &);
133   void Leave(const parser::OpenMPLoopConstruct &);
134   void Enter(const parser::OmpEndLoopDirective &);
135 
136   void Enter(const parser::OpenMPBlockConstruct &);
137   void Leave(const parser::OpenMPBlockConstruct &);
138   void Leave(const parser::OmpBeginBlockDirective &);
139   void Enter(const parser::OmpEndBlockDirective &);
140   void Leave(const parser::OmpEndBlockDirective &);
141 
142   void Enter(const parser::OpenMPSectionsConstruct &);
143   void Leave(const parser::OpenMPSectionsConstruct &);
144   void Enter(const parser::OmpEndSectionsDirective &);
145   void Leave(const parser::OmpEndSectionsDirective &);
146 
147   void Enter(const parser::OpenMPDeclareSimdConstruct &);
148   void Leave(const parser::OpenMPDeclareSimdConstruct &);
149   void Enter(const parser::OpenMPDeclarativeAllocate &);
150   void Leave(const parser::OpenMPDeclarativeAllocate &);
151   void Enter(const parser::OpenMPDeclareTargetConstruct &);
152   void Leave(const parser::OpenMPDeclareTargetConstruct &);
153   void Enter(const parser::OpenMPExecutableAllocate &);
154   void Leave(const parser::OpenMPExecutableAllocate &);
155   void Enter(const parser::OpenMPThreadprivate &);
156   void Leave(const parser::OpenMPThreadprivate &);
157 
158   void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
159   void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
160   void Enter(const parser::OpenMPFlushConstruct &);
161   void Leave(const parser::OpenMPFlushConstruct &);
162   void Enter(const parser::OpenMPCancelConstruct &);
163   void Leave(const parser::OpenMPCancelConstruct &);
164   void Enter(const parser::OpenMPCancellationPointConstruct &);
165   void Leave(const parser::OpenMPCancellationPointConstruct &);
166   void Enter(const parser::OpenMPCriticalConstruct &);
167   void Leave(const parser::OpenMPCriticalConstruct &);
168   void Enter(const parser::OpenMPAtomicConstruct &);
169   void Leave(const parser::OpenMPAtomicConstruct &);
170 
171   void Leave(const parser::OmpClauseList &);
172   void Enter(const parser::OmpClause &);
173 
174   void Enter(const parser::OmpAtomicRead &);
175   void Leave(const parser::OmpAtomicRead &);
176   void Enter(const parser::OmpAtomicWrite &);
177   void Leave(const parser::OmpAtomicWrite &);
178   void Enter(const parser::OmpAtomicUpdate &);
179   void Leave(const parser::OmpAtomicUpdate &);
180   void Enter(const parser::OmpAtomicCapture &);
181   void Leave(const parser::OmpAtomic &);
182 
183 #define GEN_FLANG_CLAUSE_CHECK_ENTER
184 #include "llvm/Frontend/OpenMP/OMP.inc"
185 
186   // Get the OpenMP Clause Kind for the corresponding Parser class
187   template <typename A>
GetClauseKindForParserClass(const A &)188   llvm::omp::Clause GetClauseKindForParserClass(const A &) {
189 #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP
190 #include "llvm/Frontend/OpenMP/OMP.inc"
191   }
192 
193 private:
194   void CheckMultListItems();
195   bool HasInvalidWorksharingNesting(
196       const parser::CharBlock &, const OmpDirectiveSet &);
197   bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
198   void HasInvalidTeamsNesting(
199       const llvm::omp::Directive &dir, const parser::CharBlock &source);
200   void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
201   // specific clause related
202   bool ScheduleModifierHasType(const parser::OmpScheduleClause &,
203       const parser::OmpScheduleModifierType::ModType &);
204   void CheckAllowedMapTypes(const parser::OmpMapType::Type &,
205       const std::list<parser::OmpMapType::Type> &);
206   llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
207   llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
208 
209   void CheckDependList(const parser::DataRef &);
210   void CheckDependArraySection(
211       const common::Indirection<parser::ArrayElement> &, const parser::Name &);
212   bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
213   void CheckIsVarPartOfAnotherVar(
214       const parser::CharBlock &source, const parser::OmpObjectList &objList);
215   void CheckThreadprivateOrDeclareTargetVar(
216       const parser::OmpObjectList &objList);
217   void CheckIntentInPointer(
218       const parser::OmpObjectList &, const llvm::omp::Clause);
219   void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
220   void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
221   void CheckCopyingPolymorphicAllocatable(
222       SymbolSourceMap &, const llvm::omp::Clause);
223   void CheckPrivateSymbolsInOuterCxt(
224       SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
225   const parser::Name GetLoopIndex(const parser::DoConstruct *x);
226   void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
227   void CheckIsLoopIvPartOfClause(
228       llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
229   bool CheckTargetBlockOnlyTeams(const parser::Block &);
230   void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
231 
232   void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
233   void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
234   void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
235   template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
236   void CheckAtomicMemoryOrderClause(
237       const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *);
238   void CheckAtomicUpdateAssignmentStmt(const parser::AssignmentStmt &);
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 CheckCancellationNest(
244       const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
245   std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
246   bool CheckReductionOperators(const parser::OmpClause::Reduction &);
247   bool CheckIntrinsicOperator(
248       const parser::DefinedOperator::IntrinsicOperator &);
249   void CheckReductionTypeList(const parser::OmpClause::Reduction &);
250   void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
251   void ChecksOnOrderedAsBlock();
252   void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
253   void ChecksOnOrderedAsStandalone();
254   void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
255   void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
256   void CheckIntentInPointerAndDefinable(
257       const parser::OmpObjectList &, const llvm::omp::Clause);
258   void CheckArraySection(const parser::ArrayElement &arrayElement,
259       const parser::Name &name, const llvm::omp::Clause clause);
260   void CheckMultipleAppearanceAcrossContext(
261       const parser::OmpObjectList &ompObjectList);
262   const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
263   void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
264       const parser::OmpObjectList &ompObjectList);
265   void CheckPredefinedAllocatorRestriction(
266       const parser::CharBlock &source, const parser::Name &name);
267   bool isPredefinedAllocator{false};
EnterDirectiveNest(const int index)268   void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
ExitDirectiveNest(const int index)269   void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
GetDirectiveNest(const int index)270   int GetDirectiveNest(const int index) { return directiveNest_[index]; }
271   template <typename D> void CheckHintClause(D *, D *);
272 
273   enum directiveNestType {
274     SIMDNest,
275     TargetBlockOnlyTeams,
276     TargetNest,
277     LastType
278   };
279   int directiveNest_[LastType + 1] = {0};
280 };
281 } // namespace Fortran::semantics
282 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
283