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/openmp-directive-sets.h"
21 #include "flang/Semantics/semantics.h"
22 #include "llvm/Frontend/OpenMP/OMPConstants.h"
25 Fortran::common::EnumSet
<llvm::omp::Clause
, llvm::omp::Clause_enumSize
>;
27 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
28 #include "llvm/Frontend/OpenMP/OMP.inc"
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
{
42 Directive::OMPD_do_simd
,
43 Directive::OMPD_sections
,
44 Directive::OMPD_single
,
45 Directive::OMPD_workshare
,
50 namespace Fortran::semantics
{
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
>>;
59 class OmpStructureChecker
60 : public DirectiveStructureChecker
<llvm::omp::Directive
, llvm::omp::Clause
,
61 parser::OmpClause
, llvm::omp::Clause_enumSize
> {
63 using Base
= DirectiveStructureChecker
<llvm::omp::Directive
,
64 llvm::omp::Clause
, parser::OmpClause
, llvm::omp::Clause_enumSize
>;
66 OmpStructureChecker(SemanticsContext
&context
)
67 : DirectiveStructureChecker(context
,
68 #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
69 #include "llvm/Frontend/OpenMP/OMP.inc"
72 using llvmOmpClause
= const llvm::omp::Clause
;
74 void Enter(const parser::OpenMPConstruct
&);
75 void Leave(const parser::OpenMPConstruct
&);
76 void Enter(const parser::OpenMPDeclarativeConstruct
&);
77 void Leave(const parser::OpenMPDeclarativeConstruct
&);
79 void Enter(const parser::OpenMPLoopConstruct
&);
80 void Leave(const parser::OpenMPLoopConstruct
&);
81 void Enter(const parser::OmpEndLoopDirective
&);
82 void Leave(const parser::OmpEndLoopDirective
&);
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
&);
90 void Enter(const parser::OpenMPSectionsConstruct
&);
91 void Leave(const parser::OpenMPSectionsConstruct
&);
92 void Enter(const parser::OmpEndSectionsDirective
&);
93 void Leave(const parser::OmpEndSectionsDirective
&);
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
&);
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
&);
134 void Leave(const parser::OmpClauseList
&);
135 void Enter(const parser::OmpClause
&);
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
&);
146 void Enter(const parser::DoConstruct
&);
147 void Leave(const parser::DoConstruct
&);
149 void Enter(const parser::OmpDirectiveSpecification
&);
150 void Leave(const parser::OmpDirectiveSpecification
&);
152 void Enter(const parser::OmpMetadirectiveDirective
&);
153 void Leave(const parser::OmpMetadirectiveDirective
&);
155 void Enter(const parser::OmpContextSelector
&);
156 void Leave(const parser::OmpContextSelector
&);
158 #define GEN_FLANG_CLAUSE_CHECK_ENTER
159 #include "llvm/Frontend/OpenMP/OMP.inc"
161 void Leave(const parser::OmpClause::Fail
&);
162 void Enter(const parser::OmpFailClause
&);
163 void Leave(const parser::OmpFailClause
&);
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
;
191 typename LessTy
, typename RangeTy
,
192 typename IterTy
= decltype(std::declval
<RangeTy
>().begin())>
193 std::optional
<IterTy
> FindDuplicate(RangeTy
&&);
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
);
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};
277 void CheckAllowedRequiresClause(llvmOmpClause clause
);
278 bool deviceConstructFound_
{false};
280 void CheckAlignValue(const parser::OmpClause
&);
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 {
293 TargetBlockOnlyTeams
,
297 LastType
= ContextSelectorNest
,
299 int directiveNest_
[LastType
+ 1] = {0};
301 SymbolSourceMap deferredNonVariables_
;
303 using LoopConstruct
= std::variant
<const parser::DoConstruct
*,
304 const parser::OpenMPLoopConstruct
*>;
305 std::vector
<LoopConstruct
> loopStack_
;
306 bool isFailClause
{false};
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
) {
325 } // namespace Fortran::semantics
326 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_