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
;
73 using ReductionModifier
= parser::OmpReductionClause::ReductionModifier
;
75 void Enter(const parser::OpenMPConstruct
&);
76 void Leave(const parser::OpenMPConstruct
&);
77 void Enter(const parser::OpenMPLoopConstruct
&);
78 void Leave(const parser::OpenMPLoopConstruct
&);
79 void Enter(const parser::OmpEndLoopDirective
&);
80 void Leave(const parser::OmpEndLoopDirective
&);
82 void Enter(const parser::OpenMPBlockConstruct
&);
83 void Leave(const parser::OpenMPBlockConstruct
&);
84 void Leave(const parser::OmpBeginBlockDirective
&);
85 void Enter(const parser::OmpEndBlockDirective
&);
86 void Leave(const parser::OmpEndBlockDirective
&);
88 void Enter(const parser::OpenMPSectionsConstruct
&);
89 void Leave(const parser::OpenMPSectionsConstruct
&);
90 void Enter(const parser::OmpEndSectionsDirective
&);
91 void Leave(const parser::OmpEndSectionsDirective
&);
93 void Enter(const parser::OpenMPDeclareSimdConstruct
&);
94 void Leave(const parser::OpenMPDeclareSimdConstruct
&);
95 void Enter(const parser::OpenMPDeclarativeAllocate
&);
96 void Leave(const parser::OpenMPDeclarativeAllocate
&);
97 void Enter(const parser::OpenMPDeclareMapperConstruct
&);
98 void Leave(const parser::OpenMPDeclareMapperConstruct
&);
99 void Enter(const parser::OpenMPDeclareTargetConstruct
&);
100 void Leave(const parser::OpenMPDeclareTargetConstruct
&);
101 void Enter(const parser::OpenMPDepobjConstruct
&);
102 void Leave(const parser::OpenMPDepobjConstruct
&);
103 void Enter(const parser::OmpDeclareTargetWithList
&);
104 void Enter(const parser::OmpDeclareTargetWithClause
&);
105 void Leave(const parser::OmpDeclareTargetWithClause
&);
106 void Enter(const parser::OpenMPExecutableAllocate
&);
107 void Leave(const parser::OpenMPExecutableAllocate
&);
108 void Enter(const parser::OpenMPAllocatorsConstruct
&);
109 void Leave(const parser::OpenMPAllocatorsConstruct
&);
110 void Enter(const parser::OpenMPRequiresConstruct
&);
111 void Leave(const parser::OpenMPRequiresConstruct
&);
112 void Enter(const parser::OpenMPThreadprivate
&);
113 void Leave(const parser::OpenMPThreadprivate
&);
115 void Enter(const parser::OpenMPSimpleStandaloneConstruct
&);
116 void Leave(const parser::OpenMPSimpleStandaloneConstruct
&);
117 void Enter(const parser::OpenMPFlushConstruct
&);
118 void Leave(const parser::OpenMPFlushConstruct
&);
119 void Enter(const parser::OpenMPCancelConstruct
&);
120 void Leave(const parser::OpenMPCancelConstruct
&);
121 void Enter(const parser::OpenMPCancellationPointConstruct
&);
122 void Leave(const parser::OpenMPCancellationPointConstruct
&);
123 void Enter(const parser::OpenMPCriticalConstruct
&);
124 void Leave(const parser::OpenMPCriticalConstruct
&);
125 void Enter(const parser::OpenMPAtomicConstruct
&);
126 void Leave(const parser::OpenMPAtomicConstruct
&);
128 void Leave(const parser::OmpClauseList
&);
129 void Enter(const parser::OmpClause
&);
131 void Enter(const parser::OmpAtomicRead
&);
132 void Leave(const parser::OmpAtomicRead
&);
133 void Enter(const parser::OmpAtomicWrite
&);
134 void Leave(const parser::OmpAtomicWrite
&);
135 void Enter(const parser::OmpAtomicUpdate
&);
136 void Leave(const parser::OmpAtomicUpdate
&);
137 void Enter(const parser::OmpAtomicCapture
&);
138 void Leave(const parser::OmpAtomic
&);
140 void Enter(const parser::DoConstruct
&);
141 void Leave(const parser::DoConstruct
&);
143 #define GEN_FLANG_CLAUSE_CHECK_ENTER
144 #include "llvm/Frontend/OpenMP/OMP.inc"
147 bool CheckAllowedClause(llvmOmpClause clause
);
148 bool IsVariableListItem(const Symbol
&sym
);
149 bool IsExtendedListItem(const Symbol
&sym
);
150 std::optional
<bool> IsContiguous(const parser::OmpObject
&object
);
151 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet
&listVars
,
152 const std::list
<parser::Name
> &nameList
, const parser::CharBlock
&item
,
153 const std::string
&clauseName
);
154 void CheckMultListItems();
155 void CheckStructureElement(const parser::OmpObjectList
&ompObjectList
,
156 const llvm::omp::Clause clause
);
157 bool HasInvalidWorksharingNesting(
158 const parser::CharBlock
&, const OmpDirectiveSet
&);
159 bool IsCloselyNestedRegion(const OmpDirectiveSet
&set
);
160 void HasInvalidTeamsNesting(
161 const llvm::omp::Directive
&dir
, const parser::CharBlock
&source
);
162 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct
&x
);
163 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct
&x
);
164 // specific clause related
165 bool ScheduleModifierHasType(const parser::OmpScheduleClause
&,
166 const parser::OmpScheduleModifierType::ModType
&);
167 void CheckAllowedMapTypes(const parser::OmpMapClause::Type
&,
168 const std::list
<parser::OmpMapClause::Type
> &);
169 llvm::StringRef
getClauseName(llvm::omp::Clause clause
) override
;
170 llvm::StringRef
getDirectiveName(llvm::omp::Directive directive
) override
;
172 template <typename T
> struct DefaultLess
{
173 bool operator()(const T
*a
, const T
*b
) const { return *a
< *b
; }
175 template <typename T
, typename Less
= DefaultLess
<T
>>
176 const T
*FindDuplicateEntry(const std::list
<T
> &);
178 void CheckDependList(const parser::DataRef
&);
179 void CheckDependArraySection(
180 const common::Indirection
<parser::ArrayElement
> &, const parser::Name
&);
181 void CheckDoacross(const parser::OmpDoacross
&doa
);
182 bool IsDataRefTypeParamInquiry(const parser::DataRef
*dataRef
);
183 void CheckIsVarPartOfAnotherVar(const parser::CharBlock
&source
,
184 const parser::OmpObjectList
&objList
, llvm::StringRef clause
= "");
185 void CheckThreadprivateOrDeclareTargetVar(
186 const parser::OmpObjectList
&objList
);
187 void CheckSymbolNames(
188 const parser::CharBlock
&source
, const parser::OmpObjectList
&objList
);
189 void CheckIntentInPointer(
190 const parser::OmpObjectList
&, const llvm::omp::Clause
);
191 void GetSymbolsInObjectList(const parser::OmpObjectList
&, SymbolSourceMap
&);
192 void CheckDefinableObjects(SymbolSourceMap
&, const llvm::omp::Clause
);
193 void CheckCopyingPolymorphicAllocatable(
194 SymbolSourceMap
&, const llvm::omp::Clause
);
195 void CheckPrivateSymbolsInOuterCxt(
196 SymbolSourceMap
&, DirectivesClauseTriple
&, const llvm::omp::Clause
);
197 const parser::Name
GetLoopIndex(const parser::DoConstruct
*x
);
198 void SetLoopInfo(const parser::OpenMPLoopConstruct
&x
);
199 void CheckIsLoopIvPartOfClause(
200 llvmOmpClause clause
, const parser::OmpObjectList
&ompObjectList
);
201 bool CheckTargetBlockOnlyTeams(const parser::Block
&);
202 void CheckWorkshareBlockStmts(const parser::Block
&, parser::CharBlock
);
204 void CheckIteratorRange(const parser::OmpIteratorSpecifier
&x
);
205 void CheckIteratorModifier(const parser::OmpIterator
&x
);
206 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct
&x
);
207 void CheckDoWhile(const parser::OpenMPLoopConstruct
&x
);
208 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct
&x
);
209 template <typename T
, typename D
> bool IsOperatorValid(const T
&, const D
&);
210 void CheckAtomicMemoryOrderClause(
211 const parser::OmpAtomicClauseList
*, const parser::OmpAtomicClauseList
*);
212 void CheckAtomicUpdateStmt(const parser::AssignmentStmt
&);
213 void CheckAtomicCaptureStmt(const parser::AssignmentStmt
&);
214 void CheckAtomicWriteStmt(const parser::AssignmentStmt
&);
215 void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture
&);
216 void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct
&);
217 void CheckDistLinear(const parser::OpenMPLoopConstruct
&x
);
218 void CheckSIMDNest(const parser::OpenMPConstruct
&x
);
219 void CheckTargetNest(const parser::OpenMPConstruct
&x
);
220 void CheckTargetUpdate();
221 void CheckDependenceType(const parser::OmpDependenceType::Value
&x
);
222 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value
&x
);
223 void CheckCancellationNest(
224 const parser::CharBlock
&source
, const parser::OmpCancelType::Type
&type
);
225 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct
&x
);
226 bool CheckReductionOperators(const parser::OmpClause::Reduction
&);
227 bool CheckIntrinsicOperator(
228 const parser::DefinedOperator::IntrinsicOperator
&);
229 void CheckReductionTypeList(const parser::OmpClause::Reduction
&);
230 void CheckReductionModifier(const ReductionModifier
&);
231 void CheckMasterNesting(const parser::OpenMPBlockConstruct
&x
);
232 void ChecksOnOrderedAsBlock();
233 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct
&x
);
234 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct
&x
);
235 void ChecksOnOrderedAsStandalone();
236 void CheckOrderedDependClause(std::optional
<std::int64_t> orderedValue
);
237 void CheckReductionArraySection(const parser::OmpObjectList
&ompObjectList
);
238 void CheckIntentInPointerAndDefinable(
239 const parser::OmpObjectList
&, const llvm::omp::Clause
);
240 void CheckArraySection(const parser::ArrayElement
&arrayElement
,
241 const parser::Name
&name
, const llvm::omp::Clause clause
);
242 void CheckSharedBindingInOuterContext(
243 const parser::OmpObjectList
&ompObjectList
);
244 void CheckIfContiguous(const parser::OmpObject
&object
);
245 const parser::Name
*GetObjectName(const parser::OmpObject
&object
);
246 const parser::OmpObjectList
*GetOmpObjectList(const parser::OmpClause
&);
247 void CheckPredefinedAllocatorRestriction(const parser::CharBlock
&source
,
248 const parser::OmpObjectList
&ompObjectList
);
249 void CheckPredefinedAllocatorRestriction(
250 const parser::CharBlock
&source
, const parser::Name
&name
);
251 bool isPredefinedAllocator
{false};
253 void CheckAllowedRequiresClause(llvmOmpClause clause
);
254 bool deviceConstructFound_
{false};
256 void EnterDirectiveNest(const int index
) { directiveNest_
[index
]++; }
257 void ExitDirectiveNest(const int index
) { directiveNest_
[index
]--; }
258 int GetDirectiveNest(const int index
) { return directiveNest_
[index
]; }
259 template <typename D
> void CheckHintClause(D
*, D
*);
260 inline void ErrIfAllocatableVariable(const parser::Variable
&);
261 inline void ErrIfLHSAndRHSSymbolsMatch(
262 const parser::Variable
&, const parser::Expr
&);
263 inline void ErrIfNonScalarAssignmentStmt(
264 const parser::Variable
&, const parser::Expr
&);
265 enum directiveNestType
{
267 TargetBlockOnlyTeams
,
271 int directiveNest_
[LastType
+ 1] = {0};
273 SymbolSourceMap deferredNonVariables_
;
275 using LoopConstruct
= std::variant
<const parser::DoConstruct
*,
276 const parser::OpenMPLoopConstruct
*>;
277 std::vector
<LoopConstruct
> loopStack_
;
280 template <typename T
, typename Less
>
281 const T
*OmpStructureChecker::FindDuplicateEntry(const std::list
<T
> &list
) {
282 // Add elements of the list to a set. If the insertion fails, return
283 // the address of the failing element.
285 // The objects of type T may not be copyable, so add their addresses
286 // to the set. The set will need to compare the actual objects, so
287 // the custom comparator is provided.
288 std::set
<const T
*, Less
> uniq
;
290 for (const T
&item
: list
) {
291 if (!uniq
.insert(&item
).second
) {
298 } // namespace Fortran::semantics
299 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_