Skip to content

Commit 923f039

Browse files
committed
[OpenACC] Implement 'copy' Clause
The copy clause takes a var-list, similar to cache. This patch implements the parsing in terms of how we did cache, and does some infrastructure for future clause parsing. As a part of this, many functions needed to become members of Parser, which I anticipated needing to happen in the future anyway.
1 parent d21fb06 commit 923f039

File tree

4 files changed

+194
-68
lines changed

4 files changed

+194
-68
lines changed

clang/include/clang/Basic/OpenACCKinds.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ enum class OpenACCClauseKind {
9898
If,
9999
/// 'self' clause, allowed on Compute and Combined Constructs, plus 'update'.
100100
Self,
101+
/// 'copy' clause, allowed on Compute and Combined Constructs, plus 'data' and
102+
/// 'declare'.
103+
Copy,
101104
/// Represents an invalid clause, for the purposes of parsing.
102105
Invalid,
103106
};

clang/include/clang/Parse/Parser.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_PARSE_PARSER_H
1414
#define LLVM_CLANG_PARSE_PARSER_H
1515

16+
#include "clang/Basic/OpenACCKinds.h"
1617
#include "clang/Basic/OperatorPrecedence.h"
1718
#include "clang/Lex/CodeCompletionHandler.h"
1819
#include "clang/Lex/Preprocessor.h"
@@ -3568,6 +3569,16 @@ class Parser : public CodeCompletionHandler {
35683569
void ParseOpenACCCacheVarList();
35693570
/// Parses a single variable in a variable list for OpenACC.
35703571
bool ParseOpenACCVar();
3572+
/// Parses the variable list for the variety of clauses that take a var-list,
3573+
/// including the optional Special Token listed for some,based on clause type.
3574+
bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind);
3575+
/// Parses any parameters for an OpenACC Clause, including required/optional
3576+
/// parens.
3577+
bool ParseOpenACCClauseParams(OpenACCClauseKind Kind);
3578+
/// Parses a single clause in a clause-list for OpenACC.
3579+
bool ParseOpenACCClause();
3580+
/// Parses the clause-list for an OpenACC directive.
3581+
void ParseOpenACCClauseList();
35713582
bool ParseOpenACCWaitArgument();
35723583

35733584
private:

clang/lib/Parse/ParseOpenACC.cpp

Lines changed: 95 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
9090
return llvm::StringSwitch<OpenACCClauseKind>(
9191
Tok.getIdentifierInfo()->getName())
9292
.Case("auto", OpenACCClauseKind::Auto)
93+
.Case("copy", OpenACCClauseKind::Copy)
9394
.Case("default", OpenACCClauseKind::Default)
9495
.Case("finalize", OpenACCClauseKind::Finalize)
9596
.Case("if", OpenACCClauseKind::If)
@@ -334,7 +335,8 @@ bool ClauseHasOptionalParens(OpenACCClauseKind Kind) {
334335
}
335336

336337
bool ClauseHasRequiredParens(OpenACCClauseKind Kind) {
337-
return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If;
338+
return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If ||
339+
Kind == OpenACCClauseKind::Copy;
338340
}
339341

340342
ExprResult ParseOpenACCConditionalExpr(Parser &P) {
@@ -345,43 +347,124 @@ ExprResult ParseOpenACCConditionalExpr(Parser &P) {
345347
return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression());
346348
}
347349

348-
bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
349-
BalancedDelimiterTracker Parens(P, tok::l_paren,
350+
// Skip until we see the end of pragma token, but don't consume it. This is us
351+
// just giving up on the rest of the pragma so we can continue executing. We
352+
// have to do this because 'SkipUntil' considers paren balancing, which isn't
353+
// what we want.
354+
void SkipUntilEndOfDirective(Parser &P) {
355+
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
356+
P.ConsumeAnyToken();
357+
}
358+
359+
} // namespace
360+
361+
// OpenACC 3.3, section 1.7:
362+
// To simplify the specification and convey appropriate constraint information,
363+
// a pqr-list is a comma-separated list of pdr items. The one exception is a
364+
// clause-list, which is a list of one or more clauses optionally separated by
365+
// commas.
366+
void Parser::ParseOpenACCClauseList() {
367+
bool FirstClause = true;
368+
while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {
369+
// Comma is optional in a clause-list.
370+
if (!FirstClause && getCurToken().is(tok::comma))
371+
ConsumeToken();
372+
FirstClause = false;
373+
374+
// Recovering from a bad clause is really difficult, so we just give up on
375+
// error.
376+
if (ParseOpenACCClause()) {
377+
SkipUntilEndOfDirective(*this);
378+
return;
379+
}
380+
}
381+
}
382+
383+
bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) {
384+
// FIXME: Future clauses will require 'special word' parsing, check for one,
385+
// then parse it based on whether it is a clause that requires a 'special
386+
// word'.
387+
(void)Kind;
388+
389+
// If the var parsing fails, skip until the end of the directive as this is
390+
// an expression and gets messy if we try to continue otherwise.
391+
if (ParseOpenACCVar())
392+
return true;
393+
394+
while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
395+
ExpectAndConsume(tok::comma);
396+
397+
// If the var parsing fails, skip until the end of the directive as this is
398+
// an expression and gets messy if we try to continue otherwise.
399+
if (ParseOpenACCVar())
400+
return true;
401+
}
402+
return false;
403+
}
404+
// The OpenACC Clause List is a comma or space-delimited list of clauses (see
405+
// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
406+
// really have its owner grammar and each individual one has its own definition.
407+
// However, they all are named with a single-identifier (or auto/default!)
408+
// token, followed in some cases by either braces or parens.
409+
bool Parser::ParseOpenACCClause() {
410+
// A number of clause names are actually keywords, so accept a keyword that
411+
// can be converted to a name.
412+
if (expectIdentifierOrKeyword(*this))
413+
return true;
414+
415+
OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken());
416+
417+
if (Kind == OpenACCClauseKind::Invalid)
418+
return Diag(getCurToken(), diag::err_acc_invalid_clause)
419+
<< getCurToken().getIdentifierInfo();
420+
421+
// Consume the clause name.
422+
ConsumeToken();
423+
424+
return ParseOpenACCClauseParams(Kind);
425+
}
426+
427+
bool Parser::ParseOpenACCClauseParams(OpenACCClauseKind Kind) {
428+
BalancedDelimiterTracker Parens(*this, tok::l_paren,
350429
tok::annot_pragma_openacc_end);
351430

352431
if (ClauseHasRequiredParens(Kind)) {
353432
if (Parens.expectAndConsume()) {
354433
// We are missing a paren, so assume that the person just forgot the
355434
// parameter. Return 'false' so we try to continue on and parse the next
356435
// clause.
357-
P.SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
358-
Parser::StopBeforeMatch);
436+
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
437+
Parser::StopBeforeMatch);
359438
return false;
360439
}
361440

362441
switch (Kind) {
363442
case OpenACCClauseKind::Default: {
364-
Token DefKindTok = P.getCurToken();
443+
Token DefKindTok = getCurToken();
365444

366-
if (expectIdentifierOrKeyword(P))
445+
if (expectIdentifierOrKeyword(*this))
367446
break;
368447

369-
P.ConsumeToken();
448+
ConsumeToken();
370449

371450
if (getOpenACCDefaultClauseKind(DefKindTok) ==
372451
OpenACCDefaultClauseKind::Invalid)
373-
P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
452+
Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
374453

375454
break;
376455
}
377456
case OpenACCClauseKind::If: {
378-
ExprResult CondExpr = ParseOpenACCConditionalExpr(P);
457+
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
379458
// An invalid expression can be just about anything, so just give up on
380459
// this clause list.
381460
if (CondExpr.isInvalid())
382461
return true;
383462
break;
384463
}
464+
case OpenACCClauseKind::Copy:
465+
if (ParseOpenACCClauseVarList(Kind))
466+
return true;
467+
break;
385468
default:
386469
llvm_unreachable("Not a required parens type?");
387470
}
@@ -391,7 +474,7 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
391474
if (!Parens.consumeOpen()) {
392475
switch (Kind) {
393476
case OpenACCClauseKind::Self: {
394-
ExprResult CondExpr = ParseOpenACCConditionalExpr(P);
477+
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
395478
// An invalid expression can be just about anything, so just give up on
396479
// this clause list.
397480
if (CondExpr.isInvalid())
@@ -407,62 +490,6 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
407490
return false;
408491
}
409492

410-
// The OpenACC Clause List is a comma or space-delimited list of clauses (see
411-
// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
412-
// really have its owner grammar and each individual one has its own definition.
413-
// However, they all are named with a single-identifier (or auto/default!)
414-
// token, followed in some cases by either braces or parens.
415-
bool ParseOpenACCClause(Parser &P) {
416-
// A number of clause names are actually keywords, so accept a keyword that
417-
// can be converted to a name.
418-
if (expectIdentifierOrKeyword(P))
419-
return true;
420-
421-
OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken());
422-
423-
if (Kind == OpenACCClauseKind::Invalid)
424-
return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause)
425-
<< P.getCurToken().getIdentifierInfo();
426-
427-
// Consume the clause name.
428-
P.ConsumeToken();
429-
430-
return ParseOpenACCClauseParams(P, Kind);
431-
}
432-
433-
// Skip until we see the end of pragma token, but don't consume it. This is us
434-
// just giving up on the rest of the pragma so we can continue executing. We
435-
// have to do this because 'SkipUntil' considers paren balancing, which isn't
436-
// what we want.
437-
void SkipUntilEndOfDirective(Parser &P) {
438-
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
439-
P.ConsumeAnyToken();
440-
}
441-
442-
// OpenACC 3.3, section 1.7:
443-
// To simplify the specification and convey appropriate constraint information,
444-
// a pqr-list is a comma-separated list of pdr items. The one exception is a
445-
// clause-list, which is a list of one or more clauses optionally separated by
446-
// commas.
447-
void ParseOpenACCClauseList(Parser &P) {
448-
bool FirstClause = true;
449-
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) {
450-
// Comma is optional in a clause-list.
451-
if (!FirstClause && P.getCurToken().is(tok::comma))
452-
P.ConsumeToken();
453-
FirstClause = false;
454-
455-
// Recovering from a bad clause is really difficult, so we just give up on
456-
// error.
457-
if (ParseOpenACCClause(P)) {
458-
SkipUntilEndOfDirective(P);
459-
return;
460-
}
461-
}
462-
}
463-
464-
} // namespace
465-
466493
/// OpenACC 3.3, section 2.16:
467494
/// In this section and throughout the specification, the term wait-argument
468495
/// means:
@@ -664,7 +691,7 @@ void Parser::ParseOpenACCDirective() {
664691
}
665692

666693
// Parses the list of clauses, if present.
667-
ParseOpenACCClauseList(*this);
694+
ParseOpenACCClauseList();
668695

669696
Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
670697
assert(Tok.is(tok::annot_pragma_openacc_end) &&

clang/test/ParserOpenACC/parse-clauses.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,91 @@ void SyncClause() {
315315
for(;;){}
316316
}
317317

318+
struct Members {
319+
int value;
320+
char array[5];
321+
};
322+
struct HasMembersArray {
323+
struct Members MemArr[4];
324+
};
325+
326+
void VarListClauses() {
327+
// expected-error@+2{{expected '('}}
328+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
329+
#pragma acc serial copy
330+
331+
// expected-error@+2{{expected '('}}
332+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
333+
#pragma acc serial copy, seq
334+
335+
// expected-error@+3{{expected '('}}
336+
// expected-error@+2{{expected identifier}}
337+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
338+
#pragma acc serial copy)
339+
340+
// expected-error@+3{{expected '('}}
341+
// expected-error@+2{{expected identifier}}
342+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
343+
#pragma acc serial copy), seq
344+
345+
// expected-error@+2{{expected expression}}
346+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
347+
#pragma acc serial copy(
348+
349+
// expected-error@+2{{expected expression}}
350+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
351+
#pragma acc serial copy(, seq
352+
353+
// expected-error@+2{{expected expression}}
354+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
355+
#pragma acc serial copy()
356+
357+
// expected-error@+2{{expected expression}}
358+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
359+
#pragma acc serial copy(), seq
360+
361+
struct Members s;
362+
struct HasMembersArray HasMem;
363+
364+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
365+
#pragma acc serial copy(s.array[s.value]), seq
366+
367+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
368+
#pragma acc serial copy(s.array[s.value : 5]), seq
369+
370+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
371+
#pragma acc serial copy(HasMem.MemArr[3].array[1]), seq
372+
373+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
374+
#pragma acc serial copy(HasMem.MemArr[3].array[1:4]), seq
375+
376+
// expected-error@+2{{OpenMP array section is not allowed here}}
377+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
378+
#pragma acc serial copy(HasMem.MemArr[1:3].array[1]), seq
379+
380+
// expected-error@+2{{OpenMP array section is not allowed here}}
381+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
382+
#pragma acc serial copy(HasMem.MemArr[1:3].array[1:2]), seq
383+
384+
// expected-error@+2{{expected expression}}
385+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
386+
#pragma acc serial copy(HasMem.MemArr[:]), seq
387+
388+
// expected-error@+2{{expected expression}}
389+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
390+
#pragma acc serial copy(HasMem.MemArr[::]), seq
391+
392+
// expected-error@+4{{expected expression}}
393+
// expected-error@+3{{expected ']'}}
394+
// expected-note@+2{{to match this '['}}
395+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
396+
#pragma acc serial copy(HasMem.MemArr[: :]), seq
397+
398+
// expected-error@+2{{expected expression}}
399+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
400+
#pragma acc serial copy(HasMem.MemArr[3:]), seq
401+
}
402+
318403
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
319404
#pragma acc routine worker, vector, seq, nohost
320405
void bar();

0 commit comments

Comments
 (0)