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/openmp-directive-sets.h"
21#include "flang/Semantics/semantics.h"
22#include "llvm/Frontend/OpenMP/OMPConstants.h"
23
24using OmpClauseSet =
25 Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
26
27#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
28#include "llvm/Frontend/OpenMP/OMP.inc"
29
30namespace llvm {
31namespace omp {
32static OmpClauseSet privateSet{
33 Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
34static 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.
40static const OmpDirectiveSet noWaitClauseNotAllowedSet{
41 Directive::OMPD_do,
42 Directive::OMPD_do_simd,
43 Directive::OMPD_sections,
44 Directive::OMPD_single,
45 Directive::OMPD_workshare,
46};
47} // namespace omp
48} // namespace llvm
49
50namespace Fortran::semantics {
51
52// Mapping from 'Symbol' to 'Source' to keep track of the variables
53// used in multiple clauses
54using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
55// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
56using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
57 std::pair<llvm::omp::Directive, const OmpClauseSet>>;
58
59class OmpStructureChecker
60 : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
61 parser::OmpClause, llvm::omp::Clause_enumSize> {
62public:
63 OmpStructureChecker(SemanticsContext &context)
64 : DirectiveStructureChecker(context,
65#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
66#include "llvm/Frontend/OpenMP/OMP.inc"
67 ) {
68 }
69 using llvmOmpClause = const llvm::omp::Clause;
70
71 void Enter(const parser::OpenMPConstruct &);
72 void Enter(const parser::OpenMPLoopConstruct &);
73 void Leave(const parser::OpenMPLoopConstruct &);
74 void Enter(const parser::OmpEndLoopDirective &);
75 void Leave(const parser::OmpEndLoopDirective &);
76
77 void Enter(const parser::OpenMPBlockConstruct &);
78 void Leave(const parser::OpenMPBlockConstruct &);
79 void Leave(const parser::OmpBeginBlockDirective &);
80 void Enter(const parser::OmpEndBlockDirective &);
81 void Leave(const parser::OmpEndBlockDirective &);
82
83 void Enter(const parser::OpenMPSectionsConstruct &);
84 void Leave(const parser::OpenMPSectionsConstruct &);
85 void Enter(const parser::OmpEndSectionsDirective &);
86 void Leave(const parser::OmpEndSectionsDirective &);
87
88 void Enter(const parser::OpenMPDeclareSimdConstruct &);
89 void Leave(const parser::OpenMPDeclareSimdConstruct &);
90 void Enter(const parser::OpenMPDeclarativeAllocate &);
91 void Leave(const parser::OpenMPDeclarativeAllocate &);
92 void Enter(const parser::OpenMPDeclareTargetConstruct &);
93 void Leave(const parser::OpenMPDeclareTargetConstruct &);
94 void Enter(const parser::OmpDeclareTargetWithList &);
95 void Enter(const parser::OmpDeclareTargetWithClause &);
96 void Leave(const parser::OmpDeclareTargetWithClause &);
97 void Enter(const parser::OpenMPExecutableAllocate &);
98 void Leave(const parser::OpenMPExecutableAllocate &);
99 void Enter(const parser::OpenMPAllocatorsConstruct &);
100 void Leave(const parser::OpenMPAllocatorsConstruct &);
101 void Enter(const parser::OpenMPRequiresConstruct &);
102 void Leave(const parser::OpenMPRequiresConstruct &);
103 void Enter(const parser::OpenMPThreadprivate &);
104 void Leave(const parser::OpenMPThreadprivate &);
105
106 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
107 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
108 void Enter(const parser::OpenMPFlushConstruct &);
109 void Leave(const parser::OpenMPFlushConstruct &);
110 void Enter(const parser::OpenMPCancelConstruct &);
111 void Leave(const parser::OpenMPCancelConstruct &);
112 void Enter(const parser::OpenMPCancellationPointConstruct &);
113 void Leave(const parser::OpenMPCancellationPointConstruct &);
114 void Enter(const parser::OpenMPCriticalConstruct &);
115 void Leave(const parser::OpenMPCriticalConstruct &);
116 void Enter(const parser::OpenMPAtomicConstruct &);
117 void Leave(const parser::OpenMPAtomicConstruct &);
118
119 void Leave(const parser::OmpClauseList &);
120 void Enter(const parser::OmpClause &);
121
122 void Enter(const parser::OmpAtomicRead &);
123 void Leave(const parser::OmpAtomicRead &);
124 void Enter(const parser::OmpAtomicWrite &);
125 void Leave(const parser::OmpAtomicWrite &);
126 void Enter(const parser::OmpAtomicUpdate &);
127 void Leave(const parser::OmpAtomicUpdate &);
128 void Enter(const parser::OmpAtomicCapture &);
129 void Leave(const parser::OmpAtomic &);
130
131#define GEN_FLANG_CLAUSE_CHECK_ENTER
132#include "llvm/Frontend/OpenMP/OMP.inc"
133
134 // Get the OpenMP Clause Kind for the corresponding Parser class
135 template <typename A>
136 llvm::omp::Clause GetClauseKindForParserClass(const A &) {
137#define GEN_FLANG_CLAUSE_PARSER_KIND_MAP
138#include "llvm/Frontend/OpenMP/OMP.inc"
139 }
140
141private:
142 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
143 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
144 const std::string &clauseName);
145 void CheckMultListItems();
146 void CheckStructureElement(const parser::OmpObjectList &ompObjectList,
147 const llvm::omp::Clause clause);
148 bool HasInvalidWorksharingNesting(
149 const parser::CharBlock &, const OmpDirectiveSet &);
150 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
151 void HasInvalidTeamsNesting(
152 const llvm::omp::Directive &dir, const parser::CharBlock &source);
153 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
154 // specific clause related
155 bool ScheduleModifierHasType(const parser::OmpScheduleClause &,
156 const parser::OmpScheduleModifierType::ModType &);
157 void CheckAllowedMapTypes(const parser::OmpMapType::Type &,
158 const std::list<parser::OmpMapType::Type> &);
159 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
160 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
161
162 void CheckDependList(const parser::DataRef &);
163 void CheckDependArraySection(
164 const common::Indirection<parser::ArrayElement> &, const parser::Name &);
165 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
166 void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
167 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
168 void CheckThreadprivateOrDeclareTargetVar(
169 const parser::OmpObjectList &objList);
170 void CheckSymbolNames(
171 const parser::CharBlock &source, const parser::OmpObjectList &objList);
172 void CheckIntentInPointer(
173 const parser::OmpObjectList &, const llvm::omp::Clause);
174 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
175 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
176 void CheckCopyingPolymorphicAllocatable(
177 SymbolSourceMap &, const llvm::omp::Clause);
178 void CheckPrivateSymbolsInOuterCxt(
179 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
180 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
181 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
182 void CheckIsLoopIvPartOfClause(
183 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
184 bool CheckTargetBlockOnlyTeams(const parser::Block &);
185 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
186
187 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
188 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
189 void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
190 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
191 void CheckAtomicMemoryOrderClause(
192 const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *);
193 void CheckAtomicUpdateStmt(const parser::AssignmentStmt &);
194 void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
195 void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
196 void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
197 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
198 void CheckSIMDNest(const parser::OpenMPConstruct &x);
199 void CheckTargetNest(const parser::OpenMPConstruct &x);
200 void CheckTargetUpdate();
201 void CheckCancellationNest(
202 const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
203 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
204 bool CheckReductionOperators(const parser::OmpClause::Reduction &);
205 bool CheckIntrinsicOperator(
206 const parser::DefinedOperator::IntrinsicOperator &);
207 void CheckReductionTypeList(const parser::OmpClause::Reduction &);
208 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
209 void ChecksOnOrderedAsBlock();
210 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
211 void ChecksOnOrderedAsStandalone();
212 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
213 void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
214 void CheckIntentInPointerAndDefinable(
215 const parser::OmpObjectList &, const llvm::omp::Clause);
216 void CheckArraySection(const parser::ArrayElement &arrayElement,
217 const parser::Name &name, const llvm::omp::Clause clause);
218 void CheckSharedBindingInOuterContext(
219 const parser::OmpObjectList &ompObjectList);
220 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
221 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
222 const parser::OmpObjectList &ompObjectList);
223 void CheckPredefinedAllocatorRestriction(
224 const parser::CharBlock &source, const parser::Name &name);
225 bool isPredefinedAllocator{false};
226
227 void CheckAllowedRequiresClause(llvmOmpClause clause);
228 bool deviceConstructFound_{false};
229
230 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
231 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
232 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
233 template <typename D> void CheckHintClause(D *, D *);
234 inline void ErrIfAllocatableVariable(const parser::Variable &);
235 inline void ErrIfLHSAndRHSSymbolsMatch(
236 const parser::Variable &, const parser::Expr &);
237 inline void ErrIfNonScalarAssignmentStmt(
238 const parser::Variable &, const parser::Expr &);
239 enum directiveNestType {
240 SIMDNest,
241 TargetBlockOnlyTeams,
242 TargetNest,
243 LastType
244 };
245 int directiveNest_[LastType + 1] = {0};
246};
247} // namespace Fortran::semantics
248#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
249

source code of flang/lib/Semantics/check-omp-structure.h