Skip to content

[OpenACC] Implement initial parsing for parallel construct #72661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1343,13 +1343,20 @@ def err_openclcxx_virtual_function : Error<
"virtual functions are not supported in C++ for OpenCL">;

// OpenACC Support.
def warn_pragma_acc_ignored : Warning<
"unexpected '#pragma acc ...' in program">, InGroup<SourceUsesOpenACC>, DefaultIgnore;
def err_acc_unexpected_directive : Error<
"unexpected OpenACC directive %select{|'#pragma acc %1'}0">;
def warn_pragma_acc_ignored
: Warning<"unexpected '#pragma acc ...' in program">,
InGroup<SourceUsesOpenACC>,
DefaultIgnore;
def err_acc_unexpected_directive
: Error<"unexpected OpenACC directive %select{|'#pragma acc %1'}0">;
def warn_pragma_acc_unimplemented
: Warning<"OpenACC directives not yet implemented, pragma ignored">,
InGroup<SourceUsesOpenACC>;
def warn_pragma_acc_unimplemented_clause_parsing
: Warning<"OpenACC clause parsing not yet implemented">,
InGroup<SourceUsesOpenACC>;
def err_acc_invalid_directive
: Error<"invalid OpenACC directive '%0'">;

// OpenMP support.
def warn_pragma_omp_ignored : Warning<
Expand Down
30 changes: 30 additions & 0 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===--- OpenACCKinds.h - OpenACC Enums -------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines some OpenACC-specific enums and functions.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_BASIC_OPENACCKINDS_H
#define LLVM_CLANG_BASIC_OPENACCKINDS_H

namespace clang {
// Represents the Construct/Directive kind of a pragma directive. Note the
// OpenACC standard is inconsistent between calling these Construct vs
// Directive, but we're calling it a Directive to be consistent with OpenMP.
enum class OpenACCDirectiveKind {
// Compute Constructs.
Parallel,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest starting with a single construct support, say parallel. Other constructs must be added later, when each particular feature is going to be implemented.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our implementation strategy is to start with all of the 'parsing' first, starting at constructs, I don't see why this is an issue? I understand the grammar enough that this seems valid.

At this point, we HAVE successfully implemented parsing for all of the 'non-optional-parens' versions.

Doing it this way permits us to do the implementation of clauses next: clauses in OpenACC are shared between all of the constructs, so implementing 1 construct at a time would prevent us from being able to do that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify: Are you asking me to split this patch up into 23 different ones here? The first adding the infrastructure + parallel, followed by most of the 22 that are just adding an entry here and to a string-switch?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not neccesary. The first patch, that lands main infrastructure, better to have a small parsing functionality, the future patch(es) may include parsing of other stuff, if it small enough

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright then, I'll do that.


// Invalid.
Invalid,
};
} // namespace clang

#endif // LLVM_CLANG_BASIC_OPENACCKINDS_H
4 changes: 4 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ namespace clang {
class Parser : public CodeCompletionHandler {
friend class ColonProtectionRAIIObject;
friend class ParsingOpenMPDirectiveRAII;
friend class ParsingOpenACCDirectiveRAII;
friend class InMessageExpressionRAIIObject;
friend class OffsetOfStateRAIIObject;
friend class PoisonSEHIdentifiersRAIIObject;
Expand Down Expand Up @@ -230,6 +231,9 @@ class Parser : public CodeCompletionHandler {
/// Parsing OpenMP directive mode.
bool OpenMPDirectiveParsing = false;

/// Parsing OpenACC directive mode.
bool OpenACCDirectiveParsing = false;

/// When true, we are directly inside an Objective-C message
/// send expression.
///
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Parse/RAIIObjectsForParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,25 @@ namespace clang {
~ParsingOpenMPDirectiveRAII() { restore(); }
};

/// Activates OpenACC parsing mode to preseve OpenACC specific annotation
/// tokens.
class ParsingOpenACCDirectiveRAII {
Parser &P;
bool OldVal;

public:
ParsingOpenACCDirectiveRAII(Parser &P, bool Value = true)
: P(P), OldVal(P.OpenACCDirectiveParsing) {
P.OpenACCDirectiveParsing = Value;
}

/// This can be used to restore the state early, before the dtor
/// is run.
void restore() { P.OpenMPDirectiveParsing = OldVal; }

~ParsingOpenACCDirectiveRAII() { restore(); }
};

/// RAII object that makes '>' behave either as an operator
/// or as the closing angle bracket for a template argument list.
class GreaterThanIsOperatorScope {
Expand Down
69 changes: 65 additions & 4 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,79 @@
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/OpenACCKinds.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"

using namespace clang;
using namespace llvm;

namespace {

// Translate single-token string representations to the OpenACC Directive Kind.
OpenACCDirectiveKind GetOpenACCDirectiveKind(StringRef Name) {
return llvm::StringSwitch<OpenACCDirectiveKind>(Name)
.Case("parallel", OpenACCDirectiveKind::Parallel)
.Default(OpenACCDirectiveKind::Invalid);
}

// Parse and consume the tokens for OpenACC Directive/Construct kinds.
OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
Token FirstTok = P.getCurToken();
P.ConsumeToken();
std::string FirstTokSpelling = P.getPreprocessor().getSpelling(FirstTok);

OpenACCDirectiveKind DirKind = GetOpenACCDirectiveKind(FirstTokSpelling);

if (DirKind == OpenACCDirectiveKind::Invalid)
P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling;

return DirKind;
}

void ParseOpenACCClauseList(Parser &P) {
// FIXME: In the future, we'll start parsing the clauses here, but for now we
// haven't implemented that, so just emit the unimplemented diagnostic and
// fail reasonably.
if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing);
}

void ParseOpenACCDirective(Parser &P) {
ParseOpenACCDirectiveKind(P);

// Parses the list of clauses, if present.
ParseOpenACCClauseList(P);

P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented);
P.SkipUntil(tok::annot_pragma_openacc_end);
}

} // namespace

// Parse OpenACC directive on a declaration.
Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
Diag(Tok, diag::warn_pragma_acc_unimplemented);
SkipUntil(tok::annot_pragma_openacc_end);
assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");

ParsingOpenACCDirectiveRAII DirScope(*this);
ConsumeAnnotationToken();

ParseOpenACCDirective(*this);

return nullptr;
}

// Parse OpenACC Directive on a Statement.
StmtResult Parser::ParseOpenACCDirectiveStmt() {
Diag(Tok, diag::warn_pragma_acc_unimplemented);
SkipUntil(tok::annot_pragma_openacc_end);
assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");

ParsingOpenACCDirectiveRAII DirScope(*this);
ConsumeAnnotationToken();

ParseOpenACCDirective(*this);

return StmtEmpty();
}
5 changes: 3 additions & 2 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,9 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
break;
case tok::annot_pragma_openacc:
case tok::annot_pragma_openacc_end:
// FIXME: Like OpenMP above, we should not be doing this if we're parsing
// an OpenACC Directive.
// Stop before an OpenACC pragma boundary.
if (OpenACCDirectiveParsing)
return false;
ConsumeAnnotationToken();
break;
case tok::annot_module_begin:
Expand Down
16 changes: 16 additions & 0 deletions clang/test/ParserOpenACC/parse-constructs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %clang_cc1 %s -verify -fopenacc

void func() {
// expected-error@+2{{invalid OpenACC directive 'invalid'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc invalid
for(;;){}

// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc parallel clause list
for(;;){}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc parallel() clause list
}
6 changes: 6 additions & 0 deletions clang/test/ParserOpenACC/unimplemented.c
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
// RUN: %clang_cc1 %s -verify -fopenacc

// Parser::ParseExternalDeclaration
// expected-error@+3{{invalid OpenACC directive 'not'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
int foo;

struct S {
// Parser::ParseStructUnionBody
// expected-error@+3{{invalid OpenACC directive 'not'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
int foo;
};

void func() {
// Parser::ParseStmtOrDeclarationAfterAttributes
// expected-error@+3{{invalid OpenACC directive 'not'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
while(0) {}
Expand Down
6 changes: 6 additions & 0 deletions clang/test/ParserOpenACC/unimplemented.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
// RUN: %clang_cc1 %s -verify -fopenacc

// Parser::ParseExternalDeclaration
// expected-error@+3{{invalid OpenACC directive 'not'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
int foo;

struct S {
// Parser::ParseCXXClassMemberDeclarationWithPragmas
// expected-error@+3{{invalid OpenACC directive 'not'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
int foo;
};

void func() {
// Parser::ParseStmtOrDeclarationAfterAttributes
// expected-error@+3{{invalid OpenACC directive 'not'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc not yet implemented
while(false) {}
Expand Down