1 //===-- lib/Semantics/check-omp-structure.h ---------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
14 #ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
15 #define FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
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"
23 using OmpDirectiveSet
= Fortran::common::EnumSet
<llvm::omp::Directive
,
24 llvm::omp::Directive_enumSize
>;
27 Fortran::common::EnumSet
<llvm::omp::Clause
, llvm::omp::Clause_enumSize
>;
29 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
30 #include "llvm/Frontend/OpenMP/OMP.inc"
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
} |
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
} |
96 static OmpDirectiveSet nestedMasterErrSet
{
97 OmpDirectiveSet
{llvm::omp::Directive::OMPD_atomic
} | taskGeneratingSet
|
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
};
110 namespace Fortran::semantics
{
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
>>;
119 class OmpStructureChecker
120 : public DirectiveStructureChecker
<llvm::omp::Directive
, llvm::omp::Clause
,
121 parser::OmpClause
, llvm::omp::Clause_enumSize
> {
123 OmpStructureChecker(SemanticsContext
&context
)
124 : DirectiveStructureChecker(context
,
125 #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
126 #include "llvm/Frontend/OpenMP/OMP.inc"
129 using llvmOmpClause
= const llvm::omp::Clause
;
131 void Enter(const parser::OpenMPConstruct
&);
132 void Enter(const parser::OpenMPLoopConstruct
&);
133 void Leave(const parser::OpenMPLoopConstruct
&);
134 void Enter(const parser::OmpEndLoopDirective
&);
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
&);
142 void Enter(const parser::OpenMPSectionsConstruct
&);
143 void Leave(const parser::OpenMPSectionsConstruct
&);
144 void Enter(const parser::OmpEndSectionsDirective
&);
145 void Leave(const parser::OmpEndSectionsDirective
&);
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::OpenMPRequiresConstruct
&);
156 void Leave(const parser::OpenMPRequiresConstruct
&);
157 void Enter(const parser::OpenMPThreadprivate
&);
158 void Leave(const parser::OpenMPThreadprivate
&);
160 void Enter(const parser::OpenMPSimpleStandaloneConstruct
&);
161 void Leave(const parser::OpenMPSimpleStandaloneConstruct
&);
162 void Enter(const parser::OpenMPFlushConstruct
&);
163 void Leave(const parser::OpenMPFlushConstruct
&);
164 void Enter(const parser::OpenMPCancelConstruct
&);
165 void Leave(const parser::OpenMPCancelConstruct
&);
166 void Enter(const parser::OpenMPCancellationPointConstruct
&);
167 void Leave(const parser::OpenMPCancellationPointConstruct
&);
168 void Enter(const parser::OpenMPCriticalConstruct
&);
169 void Leave(const parser::OpenMPCriticalConstruct
&);
170 void Enter(const parser::OpenMPAtomicConstruct
&);
171 void Leave(const parser::OpenMPAtomicConstruct
&);
173 void Leave(const parser::OmpClauseList
&);
174 void Enter(const parser::OmpClause
&);
176 void Enter(const parser::OmpAtomicRead
&);
177 void Leave(const parser::OmpAtomicRead
&);
178 void Enter(const parser::OmpAtomicWrite
&);
179 void Leave(const parser::OmpAtomicWrite
&);
180 void Enter(const parser::OmpAtomicUpdate
&);
181 void Leave(const parser::OmpAtomicUpdate
&);
182 void Enter(const parser::OmpAtomicCapture
&);
183 void Leave(const parser::OmpAtomic
&);
185 #define GEN_FLANG_CLAUSE_CHECK_ENTER
186 #include "llvm/Frontend/OpenMP/OMP.inc"
188 // Get the OpenMP Clause Kind for the corresponding Parser class
189 template <typename A
>
190 llvm::omp::Clause
GetClauseKindForParserClass(const A
&) {
191 #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP
192 #include "llvm/Frontend/OpenMP/OMP.inc"
196 void CheckMultListItems();
197 bool HasInvalidWorksharingNesting(
198 const parser::CharBlock
&, const OmpDirectiveSet
&);
199 bool IsCloselyNestedRegion(const OmpDirectiveSet
&set
);
200 void HasInvalidTeamsNesting(
201 const llvm::omp::Directive
&dir
, const parser::CharBlock
&source
);
202 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct
&x
);
203 // specific clause related
204 bool ScheduleModifierHasType(const parser::OmpScheduleClause
&,
205 const parser::OmpScheduleModifierType::ModType
&);
206 void CheckAllowedMapTypes(const parser::OmpMapType::Type
&,
207 const std::list
<parser::OmpMapType::Type
> &);
208 llvm::StringRef
getClauseName(llvm::omp::Clause clause
) override
;
209 llvm::StringRef
getDirectiveName(llvm::omp::Directive directive
) override
;
211 void CheckDependList(const parser::DataRef
&);
212 void CheckDependArraySection(
213 const common::Indirection
<parser::ArrayElement
> &, const parser::Name
&);
214 bool IsDataRefTypeParamInquiry(const parser::DataRef
*dataRef
);
215 void CheckIsVarPartOfAnotherVar(
216 const parser::CharBlock
&source
, const parser::OmpObjectList
&objList
);
217 void CheckThreadprivateOrDeclareTargetVar(
218 const parser::OmpObjectList
&objList
);
219 void CheckIntentInPointer(
220 const parser::OmpObjectList
&, const llvm::omp::Clause
);
221 void GetSymbolsInObjectList(const parser::OmpObjectList
&, SymbolSourceMap
&);
222 void CheckDefinableObjects(SymbolSourceMap
&, const llvm::omp::Clause
);
223 void CheckCopyingPolymorphicAllocatable(
224 SymbolSourceMap
&, const llvm::omp::Clause
);
225 void CheckPrivateSymbolsInOuterCxt(
226 SymbolSourceMap
&, DirectivesClauseTriple
&, const llvm::omp::Clause
);
227 const parser::Name
GetLoopIndex(const parser::DoConstruct
*x
);
228 void SetLoopInfo(const parser::OpenMPLoopConstruct
&x
);
229 void CheckIsLoopIvPartOfClause(
230 llvmOmpClause clause
, const parser::OmpObjectList
&ompObjectList
);
231 bool CheckTargetBlockOnlyTeams(const parser::Block
&);
232 void CheckWorkshareBlockStmts(const parser::Block
&, parser::CharBlock
);
234 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct
&x
);
235 void CheckDoWhile(const parser::OpenMPLoopConstruct
&x
);
236 void CheckCycleConstraints(const parser::OpenMPLoopConstruct
&x
);
237 template <typename T
, typename D
> bool IsOperatorValid(const T
&, const D
&);
238 void CheckAtomicMemoryOrderClause(
239 const parser::OmpAtomicClauseList
*, const parser::OmpAtomicClauseList
*);
240 void CheckAtomicUpdateAssignmentStmt(const parser::AssignmentStmt
&);
241 void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct
&);
242 void CheckDistLinear(const parser::OpenMPLoopConstruct
&x
);
243 void CheckSIMDNest(const parser::OpenMPConstruct
&x
);
244 void CheckTargetNest(const parser::OpenMPConstruct
&x
);
245 void CheckCancellationNest(
246 const parser::CharBlock
&source
, const parser::OmpCancelType::Type
&type
);
247 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct
&x
);
248 bool CheckReductionOperators(const parser::OmpClause::Reduction
&);
249 bool CheckIntrinsicOperator(
250 const parser::DefinedOperator::IntrinsicOperator
&);
251 void CheckReductionTypeList(const parser::OmpClause::Reduction
&);
252 void CheckMasterNesting(const parser::OpenMPBlockConstruct
&x
);
253 void ChecksOnOrderedAsBlock();
254 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct
&x
);
255 void ChecksOnOrderedAsStandalone();
256 void CheckOrderedDependClause(std::optional
<std::int64_t> orderedValue
);
257 void CheckReductionArraySection(const parser::OmpObjectList
&ompObjectList
);
258 void CheckIntentInPointerAndDefinable(
259 const parser::OmpObjectList
&, const llvm::omp::Clause
);
260 void CheckArraySection(const parser::ArrayElement
&arrayElement
,
261 const parser::Name
&name
, const llvm::omp::Clause clause
);
262 void CheckSharedBindingInOuterContext(
263 const parser::OmpObjectList
&ompObjectList
);
264 const parser::OmpObjectList
*GetOmpObjectList(const parser::OmpClause
&);
265 void CheckPredefinedAllocatorRestriction(const parser::CharBlock
&source
,
266 const parser::OmpObjectList
&ompObjectList
);
267 void CheckPredefinedAllocatorRestriction(
268 const parser::CharBlock
&source
, const parser::Name
&name
);
269 bool isPredefinedAllocator
{false};
270 void EnterDirectiveNest(const int index
) { directiveNest_
[index
]++; }
271 void ExitDirectiveNest(const int index
) { directiveNest_
[index
]--; }
272 int GetDirectiveNest(const int index
) { return directiveNest_
[index
]; }
273 template <typename D
> void CheckHintClause(D
*, D
*);
275 enum directiveNestType
{
277 TargetBlockOnlyTeams
,
281 int directiveNest_
[LastType
+ 1] = {0};
283 } // namespace Fortran::semantics
284 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_