1//===--- SemaOpenACC.cpp - Semantic Analysis for OpenACC constructs -------===//
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/// \file
9/// This file implements semantic analysis for OpenACC constructs and
10/// clauses.
11///
12//===----------------------------------------------------------------------===//
13
14#include "clang/Sema/SemaOpenACC.h"
15#include "clang/AST/StmtOpenACC.h"
16#include "clang/Basic/DiagnosticSema.h"
17#include "clang/Basic/OpenACCKinds.h"
18#include "clang/Sema/Sema.h"
19#include "llvm/Support/Casting.h"
20
21using namespace clang;
22
23namespace {
24bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K,
25 SourceLocation StartLoc, bool IsStmt) {
26 switch (K) {
27 default:
28 case OpenACCDirectiveKind::Invalid:
29 // Nothing to do here, both invalid and unimplemented don't really need to
30 // do anything.
31 break;
32 case OpenACCDirectiveKind::Parallel:
33 case OpenACCDirectiveKind::Serial:
34 case OpenACCDirectiveKind::Kernels:
35 if (!IsStmt)
36 return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K;
37 break;
38 }
39 return false;
40}
41
42bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
43 OpenACCClauseKind ClauseKind) {
44 switch (ClauseKind) {
45 // FIXME: For each clause as we implement them, we can add the
46 // 'legalization' list here.
47 case OpenACCClauseKind::Default:
48 switch (DirectiveKind) {
49 case OpenACCDirectiveKind::Parallel:
50 case OpenACCDirectiveKind::Serial:
51 case OpenACCDirectiveKind::Kernels:
52 case OpenACCDirectiveKind::ParallelLoop:
53 case OpenACCDirectiveKind::SerialLoop:
54 case OpenACCDirectiveKind::KernelsLoop:
55 case OpenACCDirectiveKind::Data:
56 return true;
57 default:
58 return false;
59 }
60 case OpenACCClauseKind::If:
61 switch (DirectiveKind) {
62 case OpenACCDirectiveKind::Parallel:
63 case OpenACCDirectiveKind::Serial:
64 case OpenACCDirectiveKind::Kernels:
65 case OpenACCDirectiveKind::Data:
66 case OpenACCDirectiveKind::EnterData:
67 case OpenACCDirectiveKind::ExitData:
68 case OpenACCDirectiveKind::HostData:
69 case OpenACCDirectiveKind::Init:
70 case OpenACCDirectiveKind::Shutdown:
71 case OpenACCDirectiveKind::Set:
72 case OpenACCDirectiveKind::Update:
73 case OpenACCDirectiveKind::Wait:
74 case OpenACCDirectiveKind::ParallelLoop:
75 case OpenACCDirectiveKind::SerialLoop:
76 case OpenACCDirectiveKind::KernelsLoop:
77 return true;
78 default:
79 return false;
80 }
81 case OpenACCClauseKind::Self:
82 switch (DirectiveKind) {
83 case OpenACCDirectiveKind::Parallel:
84 case OpenACCDirectiveKind::Serial:
85 case OpenACCDirectiveKind::Kernels:
86 case OpenACCDirectiveKind::Update:
87 case OpenACCDirectiveKind::ParallelLoop:
88 case OpenACCDirectiveKind::SerialLoop:
89 case OpenACCDirectiveKind::KernelsLoop:
90 return true;
91 default:
92 return false;
93 }
94 case OpenACCClauseKind::NumGangs:
95 case OpenACCClauseKind::NumWorkers:
96 case OpenACCClauseKind::VectorLength:
97 switch (DirectiveKind) {
98 case OpenACCDirectiveKind::Parallel:
99 case OpenACCDirectiveKind::Kernels:
100 case OpenACCDirectiveKind::ParallelLoop:
101 case OpenACCDirectiveKind::KernelsLoop:
102 return true;
103 default:
104 return false;
105 }
106 default:
107 // Do nothing so we can go to the 'unimplemented' diagnostic instead.
108 return true;
109 }
110 llvm_unreachable("Invalid clause kind");
111}
112
113bool checkAlreadyHasClauseOfKind(
114 SemaOpenACC &S, ArrayRef<const OpenACCClause *> ExistingClauses,
115 SemaOpenACC::OpenACCParsedClause &Clause) {
116 const auto *Itr = llvm::find_if(Range&: ExistingClauses, P: [&](const OpenACCClause *C) {
117 return C->getClauseKind() == Clause.getClauseKind();
118 });
119 if (Itr != ExistingClauses.end()) {
120 S.Diag(Clause.getBeginLoc(), diag::err_acc_duplicate_clause_disallowed)
121 << Clause.getDirectiveKind() << Clause.getClauseKind();
122 S.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
123 return true;
124 }
125 return false;
126}
127
128} // namespace
129
130SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}
131
132OpenACCClause *
133SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
134 OpenACCParsedClause &Clause) {
135 if (Clause.getClauseKind() == OpenACCClauseKind::Invalid)
136 return nullptr;
137
138 // Diagnose that we don't support this clause on this directive.
139 if (!doesClauseApplyToDirective(DirectiveKind: Clause.getDirectiveKind(),
140 ClauseKind: Clause.getClauseKind())) {
141 Diag(Clause.getBeginLoc(), diag::err_acc_clause_appertainment)
142 << Clause.getDirectiveKind() << Clause.getClauseKind();
143 return nullptr;
144 }
145
146 switch (Clause.getClauseKind()) {
147 case OpenACCClauseKind::Default: {
148 // Restrictions only properly implemented on 'compute' constructs, and
149 // 'compute' constructs are the only construct that can do anything with
150 // this yet, so skip/treat as unimplemented in this case.
151 if (!isOpenACCComputeDirectiveKind(K: Clause.getDirectiveKind()))
152 break;
153
154 // Don't add an invalid clause to the AST.
155 if (Clause.getDefaultClauseKind() == OpenACCDefaultClauseKind::Invalid)
156 return nullptr;
157
158 // OpenACC 3.3, Section 2.5.4:
159 // At most one 'default' clause may appear, and it must have a value of
160 // either 'none' or 'present'.
161 // Second half of the sentence is diagnosed during parsing.
162 if (checkAlreadyHasClauseOfKind(S&: *this, ExistingClauses, Clause))
163 return nullptr;
164
165 return OpenACCDefaultClause::Create(
166 C: getASTContext(), K: Clause.getDefaultClauseKind(), BeginLoc: Clause.getBeginLoc(),
167 LParenLoc: Clause.getLParenLoc(), EndLoc: Clause.getEndLoc());
168 }
169
170 case OpenACCClauseKind::If: {
171 // Restrictions only properly implemented on 'compute' constructs, and
172 // 'compute' constructs are the only construct that can do anything with
173 // this yet, so skip/treat as unimplemented in this case.
174 if (!isOpenACCComputeDirectiveKind(K: Clause.getDirectiveKind()))
175 break;
176
177 // There is no prose in the standard that says duplicates aren't allowed,
178 // but this diagnostic is present in other compilers, as well as makes
179 // sense.
180 if (checkAlreadyHasClauseOfKind(S&: *this, ExistingClauses, Clause))
181 return nullptr;
182
183 // The parser has ensured that we have a proper condition expr, so there
184 // isn't really much to do here.
185
186 // If the 'if' clause is true, it makes the 'self' clause have no effect,
187 // diagnose that here.
188 // TODO OpenACC: When we add these two to other constructs, we might not
189 // want to warn on this (for example, 'update').
190 const auto *Itr =
191 llvm::find_if(Range&: ExistingClauses, P: llvm::IsaPred<OpenACCSelfClause>);
192 if (Itr != ExistingClauses.end()) {
193 Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict);
194 Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
195 }
196
197 return OpenACCIfClause::Create(
198 C: getASTContext(), BeginLoc: Clause.getBeginLoc(), LParenLoc: Clause.getLParenLoc(),
199 ConditionExpr: Clause.getConditionExpr(), EndLoc: Clause.getEndLoc());
200 }
201
202 case OpenACCClauseKind::Self: {
203 // Restrictions only properly implemented on 'compute' constructs, and
204 // 'compute' constructs are the only construct that can do anything with
205 // this yet, so skip/treat as unimplemented in this case.
206 if (!isOpenACCComputeDirectiveKind(K: Clause.getDirectiveKind()))
207 break;
208
209 // TODO OpenACC: When we implement this for 'update', this takes a
210 // 'var-list' instead of a condition expression, so semantics/handling has
211 // to happen differently here.
212
213 // There is no prose in the standard that says duplicates aren't allowed,
214 // but this diagnostic is present in other compilers, as well as makes
215 // sense.
216 if (checkAlreadyHasClauseOfKind(S&: *this, ExistingClauses, Clause))
217 return nullptr;
218
219 // If the 'if' clause is true, it makes the 'self' clause have no effect,
220 // diagnose that here.
221 // TODO OpenACC: When we add these two to other constructs, we might not
222 // want to warn on this (for example, 'update').
223 const auto *Itr =
224 llvm::find_if(Range&: ExistingClauses, P: llvm::IsaPred<OpenACCIfClause>);
225 if (Itr != ExistingClauses.end()) {
226 Diag(Clause.getBeginLoc(), diag::warn_acc_if_self_conflict);
227 Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
228 }
229
230 return OpenACCSelfClause::Create(
231 C: getASTContext(), BeginLoc: Clause.getBeginLoc(), LParenLoc: Clause.getLParenLoc(),
232 ConditionExpr: Clause.getConditionExpr(), EndLoc: Clause.getEndLoc());
233 }
234 case OpenACCClauseKind::NumGangs: {
235 // Restrictions only properly implemented on 'compute' constructs, and
236 // 'compute' constructs are the only construct that can do anything with
237 // this yet, so skip/treat as unimplemented in this case.
238 if (!isOpenACCComputeDirectiveKind(K: Clause.getDirectiveKind()))
239 break;
240
241 // There is no prose in the standard that says duplicates aren't allowed,
242 // but this diagnostic is present in other compilers, as well as makes
243 // sense.
244 if (checkAlreadyHasClauseOfKind(S&: *this, ExistingClauses, Clause))
245 return nullptr;
246
247 if (Clause.getIntExprs().empty())
248 Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args)
249 << /*NoArgs=*/0;
250
251 unsigned MaxArgs =
252 (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel ||
253 Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop)
254 ? 3
255 : 1;
256 if (Clause.getIntExprs().size() > MaxArgs)
257 Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args)
258 << /*NoArgs=*/1 << Clause.getDirectiveKind() << MaxArgs
259 << Clause.getIntExprs().size();
260
261 // Create the AST node for the clause even if the number of expressions is
262 // incorrect.
263 return OpenACCNumGangsClause::Create(
264 C: getASTContext(), BeginLoc: Clause.getBeginLoc(), LParenLoc: Clause.getLParenLoc(),
265 IntExprs: Clause.getIntExprs(), EndLoc: Clause.getEndLoc());
266 break;
267 }
268 case OpenACCClauseKind::NumWorkers: {
269 // Restrictions only properly implemented on 'compute' constructs, and
270 // 'compute' constructs are the only construct that can do anything with
271 // this yet, so skip/treat as unimplemented in this case.
272 if (!isOpenACCComputeDirectiveKind(K: Clause.getDirectiveKind()))
273 break;
274
275 // There is no prose in the standard that says duplicates aren't allowed,
276 // but this diagnostic is present in other compilers, as well as makes
277 // sense.
278 if (checkAlreadyHasClauseOfKind(S&: *this, ExistingClauses, Clause))
279 return nullptr;
280
281 assert(Clause.getIntExprs().size() == 1 &&
282 "Invalid number of expressions for NumWorkers");
283 return OpenACCNumWorkersClause::Create(
284 C: getASTContext(), BeginLoc: Clause.getBeginLoc(), LParenLoc: Clause.getLParenLoc(),
285 IntExpr: Clause.getIntExprs()[0], EndLoc: Clause.getEndLoc());
286 }
287 case OpenACCClauseKind::VectorLength: {
288 // Restrictions only properly implemented on 'compute' constructs, and
289 // 'compute' constructs are the only construct that can do anything with
290 // this yet, so skip/treat as unimplemented in this case.
291 if (!isOpenACCComputeDirectiveKind(K: Clause.getDirectiveKind()))
292 break;
293
294 // There is no prose in the standard that says duplicates aren't allowed,
295 // but this diagnostic is present in other compilers, as well as makes
296 // sense.
297 if (checkAlreadyHasClauseOfKind(S&: *this, ExistingClauses, Clause))
298 return nullptr;
299
300 assert(Clause.getIntExprs().size() == 1 &&
301 "Invalid number of expressions for VectorLength");
302 return OpenACCVectorLengthClause::Create(
303 C: getASTContext(), BeginLoc: Clause.getBeginLoc(), LParenLoc: Clause.getLParenLoc(),
304 IntExpr: Clause.getIntExprs()[0], EndLoc: Clause.getEndLoc());
305 }
306 default:
307 break;
308 }
309
310 Diag(Clause.getBeginLoc(), diag::warn_acc_clause_unimplemented)
311 << Clause.getClauseKind();
312 return nullptr;
313}
314
315void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
316 SourceLocation StartLoc) {
317 switch (K) {
318 case OpenACCDirectiveKind::Invalid:
319 // Nothing to do here, an invalid kind has nothing we can check here. We
320 // want to continue parsing clauses as far as we can, so we will just
321 // ensure that we can still work and don't check any construct-specific
322 // rules anywhere.
323 break;
324 case OpenACCDirectiveKind::Parallel:
325 case OpenACCDirectiveKind::Serial:
326 case OpenACCDirectiveKind::Kernels:
327 // Nothing to do here, there is no real legalization that needs to happen
328 // here as these constructs do not take any arguments.
329 break;
330 default:
331 Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K;
332 break;
333 }
334}
335
336ExprResult SemaOpenACC::ActOnIntExpr(OpenACCDirectiveKind DK,
337 OpenACCClauseKind CK, SourceLocation Loc,
338 Expr *IntExpr) {
339
340 assert(((DK != OpenACCDirectiveKind::Invalid &&
341 CK == OpenACCClauseKind::Invalid) ||
342 (DK == OpenACCDirectiveKind::Invalid &&
343 CK != OpenACCClauseKind::Invalid)) &&
344 "Only one of directive or clause kind should be provided");
345
346 class IntExprConverter : public Sema::ICEConvertDiagnoser {
347 OpenACCDirectiveKind DirectiveKind;
348 OpenACCClauseKind ClauseKind;
349 Expr *IntExpr;
350
351 public:
352 IntExprConverter(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
353 Expr *IntExpr)
354 : ICEConvertDiagnoser(/*AllowScopedEnumerations=*/false,
355 /*Suppress=*/false,
356 /*SuppressConversion=*/true),
357 DirectiveKind(DK), ClauseKind(CK), IntExpr(IntExpr) {}
358
359 bool match(QualType T) override {
360 // OpenACC spec just calls this 'integer expression' as having an
361 // 'integer type', so fall back on C99's 'integer type'.
362 return T->isIntegerType();
363 }
364 SemaBase::SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
365 QualType T) override {
366 if (ClauseKind != OpenACCClauseKind::Invalid)
367 return S.Diag(Loc, diag::err_acc_int_expr_requires_integer) <<
368 /*Clause=*/0 << ClauseKind << T;
369
370 return S.Diag(Loc, diag::err_acc_int_expr_requires_integer) <<
371 /*Directive=*/1 << DirectiveKind << T;
372 }
373
374 SemaBase::SemaDiagnosticBuilder
375 diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) override {
376 return S.Diag(Loc, diag::err_acc_int_expr_incomplete_class_type)
377 << T << IntExpr->getSourceRange();
378 }
379
380 SemaBase::SemaDiagnosticBuilder
381 diagnoseExplicitConv(Sema &S, SourceLocation Loc, QualType T,
382 QualType ConvTy) override {
383 return S.Diag(Loc, diag::err_acc_int_expr_explicit_conversion)
384 << T << ConvTy;
385 }
386
387 SemaBase::SemaDiagnosticBuilder noteExplicitConv(Sema &S,
388 CXXConversionDecl *Conv,
389 QualType ConvTy) override {
390 return S.Diag(Conv->getLocation(), diag::note_acc_int_expr_conversion)
391 << ConvTy->isEnumeralType() << ConvTy;
392 }
393
394 SemaBase::SemaDiagnosticBuilder
395 diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) override {
396 return S.Diag(Loc, diag::err_acc_int_expr_multiple_conversions) << T;
397 }
398
399 SemaBase::SemaDiagnosticBuilder
400 noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
401 return S.Diag(Conv->getLocation(), diag::note_acc_int_expr_conversion)
402 << ConvTy->isEnumeralType() << ConvTy;
403 }
404
405 SemaBase::SemaDiagnosticBuilder
406 diagnoseConversion(Sema &S, SourceLocation Loc, QualType T,
407 QualType ConvTy) override {
408 llvm_unreachable("conversion functions are permitted");
409 }
410 } IntExprDiagnoser(DK, CK, IntExpr);
411
412 ExprResult IntExprResult = SemaRef.PerformContextualImplicitConversion(
413 Loc, FromE: IntExpr, Converter&: IntExprDiagnoser);
414 if (IntExprResult.isInvalid())
415 return ExprError();
416
417 IntExpr = IntExprResult.get();
418 if (!IntExpr->isTypeDependent() && !IntExpr->getType()->isIntegerType())
419 return ExprError();
420
421 // TODO OpenACC: Do we want to perform usual unary conversions here? When
422 // doing codegen we might find that is necessary, but skip it for now.
423 return IntExpr;
424}
425
426bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K,
427 SourceLocation StartLoc) {
428 return diagnoseConstructAppertainment(S&: *this, K, StartLoc, /*IsStmt=*/true);
429}
430
431StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K,
432 SourceLocation StartLoc,
433 SourceLocation EndLoc,
434 ArrayRef<OpenACCClause *> Clauses,
435 StmtResult AssocStmt) {
436 switch (K) {
437 default:
438 return StmtEmpty();
439 case OpenACCDirectiveKind::Invalid:
440 return StmtError();
441 case OpenACCDirectiveKind::Parallel:
442 case OpenACCDirectiveKind::Serial:
443 case OpenACCDirectiveKind::Kernels:
444 // TODO OpenACC: Add clauses to the construct here.
445 return OpenACCComputeConstruct::Create(
446 C: getASTContext(), K, BeginLoc: StartLoc, EndLoc, Clauses,
447 StructuredBlock: AssocStmt.isUsable() ? AssocStmt.get() : nullptr);
448 }
449 llvm_unreachable("Unhandled case in directive handling?");
450}
451
452StmtResult SemaOpenACC::ActOnAssociatedStmt(OpenACCDirectiveKind K,
453 StmtResult AssocStmt) {
454 switch (K) {
455 default:
456 llvm_unreachable("Unimplemented associated statement application");
457 case OpenACCDirectiveKind::Parallel:
458 case OpenACCDirectiveKind::Serial:
459 case OpenACCDirectiveKind::Kernels:
460 // There really isn't any checking here that could happen. As long as we
461 // have a statement to associate, this should be fine.
462 // OpenACC 3.3 Section 6:
463 // Structured Block: in C or C++, an executable statement, possibly
464 // compound, with a single entry at the top and a single exit at the
465 // bottom.
466 // FIXME: Should we reject DeclStmt's here? The standard isn't clear, and
467 // an interpretation of it is to allow this and treat the initializer as
468 // the 'structured block'.
469 return AssocStmt;
470 }
471 llvm_unreachable("Invalid associated statement application");
472}
473
474bool SemaOpenACC::ActOnStartDeclDirective(OpenACCDirectiveKind K,
475 SourceLocation StartLoc) {
476 return diagnoseConstructAppertainment(S&: *this, K, StartLoc, /*IsStmt=*/false);
477}
478
479DeclGroupRef SemaOpenACC::ActOnEndDeclDirective() { return DeclGroupRef{}; }
480

source code of clang/lib/Sema/SemaOpenACC.cpp