Skip to content

Commit

Permalink
[flang][openacc] Add parsing tests and semantic check for set directive
Browse files Browse the repository at this point in the history
This patch add some parsing and clause validity tests for the set directive.
It makes use of the possibility introduces in patch D90770 to check the restriction
were one of the default_async, device_num and device_type clauses is required but also
not more than once on the set directive.

Reviewed By: sameeranjoshi

Differential Revision: https://reviews.llvm.org/D90771
  • Loading branch information
clementval committed Nov 6, 2020
1 parent cfd96f0 commit 9914a87
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 13 deletions.
27 changes: 27 additions & 0 deletions flang/test/Semantics/acc-clause-validity.f90
Expand Up @@ -14,6 +14,7 @@
! 2.11 Parallel Loop
! 2.11 Kernels Loop
! 2.11 Serial Loop
! 2.14.3 Set
! 2.16.13 Wait

program openacc_clause_validity
Expand Down Expand Up @@ -42,6 +43,32 @@ program openacc_clause_validity
!$acc init device_type(2, i, j)
!$acc init device_num(i) device_type(i, j) if(ifCondition)

!ERROR: At least one of DEFAULT_ASYNC, DEVICE_NUM, DEVICE_TYPE clause must appear on the SET directive
!$acc set

!ERROR: At least one of DEFAULT_ASYNC, DEVICE_NUM, DEVICE_TYPE clause must appear on the SET directive
!$acc set if(.TRUE.)

!ERROR: At most one DEFAULT_ASYNC clause can appear on the SET directive
!$acc set default_async(2) default_async(1)

!ERROR: At most one DEFAULT_ASYNC clause can appear on the SET directive
!$acc set default_async(2) default_async(1)

!ERROR: At most one DEVICE_NUM clause can appear on the SET directive
!$acc set device_num(1) device_num(i)

!ERROR: At most one DEVICE_TYPE clause can appear on the SET directive
!$acc set device_type(i) device_type(2, i, j)

!$acc set default_async(2)
!$acc set default_async(i)
!$acc set device_num(1)
!$acc set device_num(i)
!$acc set device_type(i)
!$acc set device_type(2, i, j)
!$acc set device_num(1) default_async(2) device_type(2, i, j)

!ERROR: At least one of ATTACH, COPYIN, CREATE clause must appear on the ENTER DATA directive
!$acc enter data

Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Frontend/OpenACC/ACC.td
Expand Up @@ -415,9 +415,15 @@ def ACC_Routine : Directive<"routine"> {
// 2.14.3
def ACC_Set : Directive<"set"> {
let allowedOnceClauses = [
VersionedClause<ACCC_DefaultAsync>,
VersionedClause<ACCC_DeviceNum>,
VersionedClause<ACCC_DeviceType>,
VersionedClause<ACCC_If>
];
let requiredClauses = [
// The three following clauses are also in allowedOnceClauses list due to
// restriction 2255 - Two instances of the same clause may not appear on the
// same directive.
VersionedClause<ACCC_DefaultAsync>,
VersionedClause<ACCC_DeviceNum>,
VersionedClause<ACCC_DeviceType>
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/TableGen/DirectiveEmitter.h
Expand Up @@ -58,7 +58,7 @@ class DirectiveLanguage {
return Records.getAllDerivedDefinitions("Clause");
}

bool CheckRecordsValidity() const;
bool HasValidityErrors() const;

private:
const llvm::Record *Def;
Expand Down
24 changes: 12 additions & 12 deletions llvm/utils/TableGen/DirectiveEmitter.cpp
Expand Up @@ -114,51 +114,51 @@ void GenerateEnumClauseVal(const std::vector<Record *> &Records,
bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
const Directive &Directive,
llvm::StringSet<> &CrtClauses) {
bool hasError = false;
bool HasError = false;
for (const auto &C : Clauses) {
VersionedClause VerClause{C};
const auto insRes = CrtClauses.insert(VerClause.getClause().getName());
if (!insRes.second) {
PrintError("Clause " + VerClause.getClause().getRecordName() +
" already defined on directive " + Directive.getRecordName());
hasError = true;
HasError = true;
}
}
return hasError;
return HasError;
}

// Check for duplicate clauses in lists. Clauses cannot appear twice in the
// three allowed list. Also, since required implies allowed, clauses cannot
// appear in both the allowedClauses and requiredClauses lists.
bool HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
bool hasDuplicate = false;
bool HasDuplicate = false;
for (const auto &D : Directives) {
Directive Dir{D};
llvm::StringSet<> Clauses;
// Check for duplicates in the three allowed lists.
if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) ||
HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) {
hasDuplicate = true;
HasDuplicate = true;
}
// Check for duplicate between allowedClauses and required
Clauses.clear();
if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) {
hasDuplicate = true;
HasDuplicate = true;
}
if (hasDuplicate)
if (HasDuplicate)
PrintFatalError("One or more clauses are defined multiple times on"
" directive " +
Dir.getRecordName());
}

return hasDuplicate;
return HasDuplicate;
}

// Check consitency of records. Return true if an error has been detected.
// Return false if the records are valid.
bool DirectiveLanguage::CheckRecordsValidity() const {
bool DirectiveLanguage::HasValidityErrors() const {
if (getDirectiveLanguages().size() != 1) {
PrintFatalError("A single definition of DirectiveLanguage is needed.");
return true;
Expand All @@ -171,7 +171,7 @@ bool DirectiveLanguage::CheckRecordsValidity() const {
// language
void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
const auto DirLang = DirectiveLanguage{Records};
if (DirLang.CheckRecordsValidity())
if (DirLang.HasValidityErrors())
return;

OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
Expand Down Expand Up @@ -649,7 +649,7 @@ void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
// language.
void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) {
const auto DirLang = DirectiveLanguage{Records};
if (DirLang.CheckRecordsValidity())
if (DirLang.HasValidityErrors())
return;

EmitDirectivesFlangImpl(DirLang, OS);
Expand All @@ -659,7 +659,7 @@ void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) {
// language. This code can be included in library.
void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
const auto DirLang = DirectiveLanguage{Records};
if (DirLang.CheckRecordsValidity())
if (DirLang.HasValidityErrors())
return;

if (!DirLang.getIncludeHeader().empty())
Expand Down

0 comments on commit 9914a87

Please sign in to comment.