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 Enter(const parser::OmpEndBlockDirective &);
139   void Leave(const parser::OmpEndBlockDirective &);
140 
141   void Enter(const parser::OpenMPSectionsConstruct &);
142   void Leave(const parser::OpenMPSectionsConstruct &);
143   void Enter(const parser::OmpEndSectionsDirective &);
144   void Leave(const parser::OmpEndSectionsDirective &);
145 
146   void Enter(const parser::OpenMPDeclareSimdConstruct &);
147   void Leave(const parser::OpenMPDeclareSimdConstruct &);
148   void Enter(const parser::OpenMPDeclarativeAllocate &);
149   void Leave(const parser::OpenMPDeclarativeAllocate &);
150   void Enter(const parser::OpenMPDeclareTargetConstruct &);
151   void Leave(const parser::OpenMPDeclareTargetConstruct &);
152   void Enter(const parser::OpenMPExecutableAllocate &);
153   void Leave(const parser::OpenMPExecutableAllocate &);
154 
155   void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
156   void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
157   void Enter(const parser::OpenMPFlushConstruct &);
158   void Leave(const parser::OpenMPFlushConstruct &);
159   void Enter(const parser::OpenMPCancelConstruct &);
160   void Leave(const parser::OpenMPCancelConstruct &);
161   void Enter(const parser::OpenMPCancellationPointConstruct &);
162   void Leave(const parser::OpenMPCancellationPointConstruct &);
163   void Enter(const parser::OpenMPCriticalConstruct &);
164   void Leave(const parser::OpenMPCriticalConstruct &);
165   void Enter(const parser::OpenMPAtomicConstruct &);
166   void Leave(const parser::OpenMPAtomicConstruct &);
167 
168   void Leave(const parser::OmpClauseList &);
169   void Enter(const parser::OmpClause &);
170 
171   void Enter(const parser::OmpAtomicRead &);
172   void Leave(const parser::OmpAtomicRead &);
173   void Enter(const parser::OmpAtomicWrite &);
174   void Leave(const parser::OmpAtomicWrite &);
175   void Enter(const parser::OmpAtomicUpdate &);
176   void Leave(const parser::OmpAtomicUpdate &);
177   void Enter(const parser::OmpAtomicCapture &);
178   void Leave(const parser::OmpAtomic &);
179 
180 #define GEN_FLANG_CLAUSE_CHECK_ENTER
181 #include "llvm/Frontend/OpenMP/OMP.inc"
182 
183   // Get the OpenMP Clause Kind for the corresponding Parser class
184   template <typename A>
GetClauseKindForParserClass(const A &)185   llvm::omp::Clause GetClauseKindForParserClass(const A &) {
186 #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP
187 #include "llvm/Frontend/OpenMP/OMP.inc"
188   }
189 
190 private:
191   bool HasInvalidWorksharingNesting(
192       const parser::CharBlock &, const OmpDirectiveSet &);
193   bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
194   void HasInvalidTeamsNesting(
195       const llvm::omp::Directive &dir, const parser::CharBlock &source);
196   void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
197   // specific clause related
198   bool ScheduleModifierHasType(const parser::OmpScheduleClause &,
199       const parser::OmpScheduleModifierType::ModType &);
200   void CheckAllowedMapTypes(const parser::OmpMapType::Type &,
201       const std::list<parser::OmpMapType::Type> &);
202   llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
203   llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
204 
205   void CheckDependList(const parser::DataRef &);
206   void CheckDependArraySection(
207       const common::Indirection<parser::ArrayElement> &, const parser::Name &);
208   bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
209   void CheckIsVarPartOfAnotherVar(
210       const parser::CharBlock &source, const parser::OmpObjectList &objList);
211   void CheckIntentInPointer(
212       const parser::OmpObjectList &, const llvm::omp::Clause);
213   void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
214   void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
215   void CheckPrivateSymbolsInOuterCxt(
216       SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
217   const parser::Name GetLoopIndex(const parser::DoConstruct *x);
218   void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
219   void CheckIsLoopIvPartOfClause(
220       llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
221   void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
222 
223   void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
224   void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
225   void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
226   void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
227   void CheckSIMDNest(const parser::OpenMPConstruct &x);
228   std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
229   void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv);
230   bool CheckReductionOperators(const parser::OmpClause::Reduction &);
231   bool CheckIntrinsicOperator(
232       const parser::DefinedOperator::IntrinsicOperator &);
233   void CheckReductionTypeList(const parser::OmpClause::Reduction &);
234   void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
235   void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
236   void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
237   void CheckIntentInPointerAndDefinable(
238       const parser::OmpObjectList &, const llvm::omp::Clause);
239   void CheckArraySection(const parser::ArrayElement &arrayElement,
240       const parser::Name &name, const llvm::omp::Clause clause);
241   void CheckMultipleAppearanceAcrossContext(
242       const parser::OmpObjectList &ompObjectList);
243   const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
244   void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
245       const parser::OmpObjectList &ompObjectList);
246   void CheckPredefinedAllocatorRestriction(
247       const parser::CharBlock &source, const parser::Name &name);
248   bool isPredefinedAllocator{false};
249 };
250 } // namespace Fortran::semantics
251 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
252