6
6
//
7
7
// ===----------------------------------------------------------------------===//
8
8
#include " check-acc-structure.h"
9
+ #include " resolve-names-utils.h"
9
10
#include " flang/Common/enum-set.h"
10
11
#include " flang/Evaluate/tools.h"
11
12
#include " flang/Parser/parse-tree.h"
@@ -106,18 +107,25 @@ bool AccStructureChecker::IsComputeConstruct(
106
107
directive == llvm::acc::ACCD_kernels_loop;
107
108
}
108
109
109
- bool AccStructureChecker::IsInsideComputeConstruct () const {
110
- if (dirContext_.size () <= 1 ) {
111
- return false ;
112
- }
110
+ bool AccStructureChecker::IsLoopConstruct (
111
+ llvm::acc::Directive directive) const {
112
+ return directive == llvm::acc::Directive::ACCD_loop ||
113
+ directive == llvm::acc::ACCD_parallel_loop ||
114
+ directive == llvm::acc::ACCD_serial_loop ||
115
+ directive == llvm::acc::ACCD_kernels_loop;
116
+ }
113
117
118
+ std::optional<llvm::acc::Directive>
119
+ AccStructureChecker::getParentComputeConstruct () const {
114
120
// Check all nested context skipping the first one.
115
- for (std::size_t i = dirContext_.size () - 1 ; i > 0 ; --i) {
116
- if (IsComputeConstruct (dirContext_[i - 1 ].directive )) {
117
- return true ;
118
- }
119
- }
120
- return false ;
121
+ for (std::size_t i = dirContext_.size () - 1 ; i > 0 ; --i)
122
+ if (IsComputeConstruct (dirContext_[i - 1 ].directive ))
123
+ return dirContext_[i - 1 ].directive ;
124
+ return std::nullopt;
125
+ }
126
+
127
+ bool AccStructureChecker::IsInsideComputeConstruct () const {
128
+ return getParentComputeConstruct ().has_value ();
121
129
}
122
130
123
131
void AccStructureChecker::CheckNotInComputeConstruct () {
@@ -128,6 +136,14 @@ void AccStructureChecker::CheckNotInComputeConstruct() {
128
136
}
129
137
}
130
138
139
+ bool AccStructureChecker::IsInsideParallelConstruct () const {
140
+ if (auto directive = getParentComputeConstruct ())
141
+ if (*directive == llvm::acc::ACCD_parallel ||
142
+ *directive == llvm::acc::ACCD_parallel_loop)
143
+ return true ;
144
+ return false ;
145
+ }
146
+
131
147
void AccStructureChecker::Enter (const parser::AccClause &x) {
132
148
SetContextClause (x);
133
149
}
@@ -250,6 +266,85 @@ void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) {
250
266
dirContext_.pop_back ();
251
267
}
252
268
269
+ std::optional<std::int64_t > AccStructureChecker::getGangDimensionSize (
270
+ DirectiveContext &dirContext) {
271
+ for (auto it : dirContext.clauseInfo ) {
272
+ const auto *clause{it.second };
273
+ if (const auto *gangClause{
274
+ std::get_if<parser::AccClause::Gang>(&clause->u )})
275
+ if (gangClause->v ) {
276
+ const Fortran::parser::AccGangArgList &x{*gangClause->v };
277
+ for (const Fortran::parser::AccGangArg &gangArg : x.v )
278
+ if (const auto *dim{
279
+ std::get_if<Fortran::parser::AccGangArg::Dim>(&gangArg.u )})
280
+ if (const auto v{EvaluateInt64 (context_, dim->v )})
281
+ return *v;
282
+ }
283
+ }
284
+ return std::nullopt;
285
+ }
286
+
287
+ void AccStructureChecker::CheckNotInSameOrSubLevelLoopConstruct () {
288
+ for (std::size_t i = dirContext_.size () - 1 ; i > 0 ; --i) {
289
+ auto &parent{dirContext_[i - 1 ]};
290
+ if (IsLoopConstruct (parent.directive )) {
291
+ for (auto parentClause : parent.actualClauses ) {
292
+ for (auto cl : GetContext ().actualClauses ) {
293
+ bool invalid{false };
294
+ if (parentClause == llvm::acc::Clause::ACCC_gang &&
295
+ cl == llvm::acc::Clause::ACCC_gang) {
296
+ if (IsInsideParallelConstruct ()) {
297
+ auto parentDim = getGangDimensionSize (parent);
298
+ auto currentDim = getGangDimensionSize (GetContext ());
299
+ std::int64_t parentDimNum = 1 , currentDimNum = 1 ;
300
+ if (parentDim)
301
+ parentDimNum = *parentDim;
302
+ if (currentDim)
303
+ currentDimNum = *currentDim;
304
+ if (parentDimNum <= currentDimNum) {
305
+ std::string parentDimStr, currentDimStr;
306
+ if (parentDim)
307
+ parentDimStr = " (dim:" + std::to_string (parentDimNum) + " )" ;
308
+ if (currentDim)
309
+ currentDimStr = " (dim:" + std::to_string (currentDimNum) + " )" ;
310
+ context_.Say (GetContext ().clauseSource ,
311
+ " %s%s clause is not allowed in the region of a loop with the %s%s clause" _err_en_US,
312
+ parser::ToUpperCaseLetters (
313
+ llvm::acc::getOpenACCClauseName (cl).str ()),
314
+ currentDimStr,
315
+ parser::ToUpperCaseLetters (
316
+ llvm::acc::getOpenACCClauseName (parentClause).str ()),
317
+ parentDimStr);
318
+ continue ;
319
+ }
320
+ } else {
321
+ invalid = true ;
322
+ }
323
+ } else if (parentClause == llvm::acc::Clause::ACCC_worker &&
324
+ (cl == llvm::acc::Clause::ACCC_gang ||
325
+ cl == llvm::acc::Clause::ACCC_worker)) {
326
+ invalid = true ;
327
+ } else if (parentClause == llvm::acc::Clause::ACCC_vector &&
328
+ (cl == llvm::acc::Clause::ACCC_gang ||
329
+ cl == llvm::acc::Clause::ACCC_worker ||
330
+ cl == llvm::acc::Clause::ACCC_vector)) {
331
+ invalid = true ;
332
+ }
333
+ if (invalid)
334
+ context_.Say (GetContext ().clauseSource ,
335
+ " %s clause is not allowed in the region of a loop with the %s clause" _err_en_US,
336
+ parser::ToUpperCaseLetters (
337
+ llvm::acc::getOpenACCClauseName (cl).str ()),
338
+ parser::ToUpperCaseLetters (
339
+ llvm::acc::getOpenACCClauseName (parentClause).str ()));
340
+ }
341
+ }
342
+ }
343
+ if (IsComputeConstruct (parent.directive ))
344
+ break ;
345
+ }
346
+ }
347
+
253
348
void AccStructureChecker::Enter (const parser::OpenACCLoopConstruct &x) {
254
349
const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t )};
255
350
const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t )};
@@ -267,6 +362,8 @@ void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) {
267
362
CheckNotAllowedIfClause (llvm::acc::Clause::ACCC_seq,
268
363
{llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector,
269
364
llvm::acc::Clause::ACCC_worker});
365
+ // Restriction - 2.9.2, 2.9.3, 2.9.4
366
+ CheckNotInSameOrSubLevelLoopConstruct ();
270
367
}
271
368
dirContext_.pop_back ();
272
369
}
0 commit comments