[flang][openacc] Add parsing tests and semantic check for set directive

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
This commit is contained in:
Valentin Clement 2020-11-05 22:19:21 -05:00 committed by clementval
parent cfd96f057b
commit 9914a8737f
4 changed files with 46 additions and 13 deletions

View File

@ -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
@ -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

View File

@ -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>

View File

@ -58,7 +58,7 @@ public:
return Records.getAllDerivedDefinitions("Clause");
}
bool CheckRecordsValidity() const;
bool HasValidityErrors() const;
private:
const llvm::Record *Def;

View File

@ -114,24 +114,24 @@ 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;
@ -139,26 +139,26 @@ bool HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
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;
@ -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";
@ -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);
@ -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())