[flang][OpenMP] Parse cancel-directive-name as clause (#130146)
The cancellable construct names on CANCEL or CANCELLATION POINT directives are actually clauses (with the same names as the corresponding constructs). Instead of parsing them into a custom structure, parse them as a clause, which will make CANCEL/CANCELLATION POINT follow the same uniform scheme as other constructs (<directive> [(<arguments>)] [clauses]).
This commit is contained in:
parent
7e292772ad
commit
5ba7a3bd4c
@ -456,8 +456,6 @@ public:
|
||||
READ_FEATURE(OmpBeginLoopDirective)
|
||||
READ_FEATURE(OmpBeginSectionsDirective)
|
||||
READ_FEATURE(OmpBlockDirective)
|
||||
READ_FEATURE(OmpCancelType)
|
||||
READ_FEATURE(OmpCancelType::Type)
|
||||
READ_FEATURE(OmpClause)
|
||||
READ_FEATURE(OmpClauseList)
|
||||
READ_FEATURE(OmpCriticalDirective)
|
||||
@ -551,7 +549,6 @@ public:
|
||||
READ_FEATURE(OpenMPAtomicConstruct)
|
||||
READ_FEATURE(OpenMPBlockConstruct)
|
||||
READ_FEATURE(OpenMPCancelConstruct)
|
||||
READ_FEATURE(OpenMPCancelConstruct::If)
|
||||
READ_FEATURE(OpenMPCancellationPointConstruct)
|
||||
READ_FEATURE(OpenMPConstruct)
|
||||
READ_FEATURE(OpenMPCriticalConstruct)
|
||||
|
@ -265,9 +265,6 @@ void OpenMPCounterVisitor::Post(const OmpDirectiveNameModifier &c) {
|
||||
clauseDetails +=
|
||||
"name_modifier=" + llvm::omp::getOpenMPDirectiveName(c.v).str() + ";";
|
||||
}
|
||||
void OpenMPCounterVisitor::Post(const OmpCancelType::Type &c) {
|
||||
clauseDetails += "type=" + std::string{OmpCancelType::EnumToString(c)} + ";";
|
||||
}
|
||||
void OpenMPCounterVisitor::Post(const OmpClause &c) {
|
||||
PostClauseCommon(normalize_clause_name(c.source.ToString()));
|
||||
clauseDetails.clear();
|
||||
|
@ -78,7 +78,6 @@ struct OpenMPCounterVisitor {
|
||||
void Post(const OmpMapType::Value &c);
|
||||
void Post(const OmpScheduleClause::Kind &c);
|
||||
void Post(const OmpDirectiveNameModifier &c);
|
||||
void Post(const OmpCancelType::Type &c);
|
||||
void Post(const OmpClause &c);
|
||||
void PostClauseCommon(const ClauseInfo &ci);
|
||||
|
||||
|
@ -540,12 +540,11 @@ public:
|
||||
"llvm::omp::Directive = ", llvm::omp::getOpenMPDirectiveName(x))
|
||||
.str();
|
||||
}
|
||||
NODE(parser, OmpCancelType)
|
||||
NODE_ENUM(OmpCancelType, Type)
|
||||
NODE(parser, OmpClause)
|
||||
#define GEN_FLANG_DUMP_PARSE_TREE_CLAUSES
|
||||
#include "llvm/Frontend/OpenMP/OMP.inc"
|
||||
NODE(parser, OmpClauseList)
|
||||
NODE(parser, OmpCancellationConstructTypeClause)
|
||||
NODE(parser, OmpContainsClause)
|
||||
NODE(parser, OmpCriticalDirective)
|
||||
NODE(parser, OmpErrorDirective)
|
||||
@ -688,7 +687,6 @@ public:
|
||||
NODE(parser, OpenMPAtomicConstruct)
|
||||
NODE(parser, OpenMPBlockConstruct)
|
||||
NODE(parser, OpenMPCancelConstruct)
|
||||
NODE(OpenMPCancelConstruct, If)
|
||||
NODE(parser, OpenMPCancellationPointConstruct)
|
||||
NODE(parser, OpenMPConstruct)
|
||||
NODE(parser, OpenMPCriticalConstruct)
|
||||
|
@ -4047,6 +4047,12 @@ struct OmpBindClause {
|
||||
WRAPPER_CLASS_BOILERPLATE(OmpBindClause, Binding);
|
||||
};
|
||||
|
||||
// Artificial clause to represent a cancellable construct.
|
||||
struct OmpCancellationConstructTypeClause {
|
||||
TUPLE_CLASS_BOILERPLATE(OmpCancellationConstructTypeClause);
|
||||
std::tuple<OmpDirectiveName, std::optional<ScalarLogicalExpr>> t;
|
||||
};
|
||||
|
||||
// Ref: [5.2:214]
|
||||
//
|
||||
// contains-clause ->
|
||||
@ -4859,26 +4865,18 @@ struct OmpLoopDirective {
|
||||
CharBlock source;
|
||||
};
|
||||
|
||||
// 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP
|
||||
struct OmpCancelType {
|
||||
ENUM_CLASS(Type, Parallel, Sections, Do, Taskgroup)
|
||||
WRAPPER_CLASS_BOILERPLATE(OmpCancelType, Type);
|
||||
CharBlock source;
|
||||
};
|
||||
|
||||
// 2.14.2 cancellation-point -> CANCELLATION POINT construct-type-clause
|
||||
struct OpenMPCancellationPointConstruct {
|
||||
TUPLE_CLASS_BOILERPLATE(OpenMPCancellationPointConstruct);
|
||||
CharBlock source;
|
||||
std::tuple<Verbatim, OmpCancelType> t;
|
||||
std::tuple<Verbatim, OmpClauseList> t;
|
||||
};
|
||||
|
||||
// 2.14.1 cancel -> CANCEL construct-type-clause [ [,] if-clause]
|
||||
struct OpenMPCancelConstruct {
|
||||
TUPLE_CLASS_BOILERPLATE(OpenMPCancelConstruct);
|
||||
WRAPPER_CLASS(If, ScalarLogicalExpr);
|
||||
CharBlock source;
|
||||
std::tuple<Verbatim, OmpCancelType, std::optional<If>> t;
|
||||
std::tuple<Verbatim, OmpClauseList> t;
|
||||
};
|
||||
|
||||
// Ref: [5.0:254-255], [5.1:287-288], [5.2:322-323]
|
||||
|
@ -50,6 +50,20 @@ template <typename Parser> constexpr auto unwrap(const Parser &p) {
|
||||
return UnwrapParser<Parser>(p);
|
||||
}
|
||||
|
||||
// Check (without advancing the parsing location) if the next thing in the
|
||||
// input would be accepted by the "checked" parser, and if so, run the "parser"
|
||||
// parser.
|
||||
// The intended use is with the "checker" parser being some token, followed
|
||||
// by a more complex parser that consumes the token plus more things, e.g.
|
||||
// "PARALLEL"_id >= Parser<OmpDirectiveSpecification>{}.
|
||||
//
|
||||
// The >= has a higher precedence than ||, so it can be used just like >>
|
||||
// in an alternatives parser without parentheses.
|
||||
template <typename PA, typename PB>
|
||||
constexpr auto operator>=(PA checker, PB parser) {
|
||||
return lookAhead(checker) >> parser;
|
||||
}
|
||||
|
||||
/// Parse OpenMP directive name (this includes compound directives).
|
||||
struct OmpDirectiveNameParser {
|
||||
using resultType = OmpDirectiveName;
|
||||
@ -575,6 +589,9 @@ TYPE_PARSER(construct<OmpAffinityClause>(
|
||||
maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"),
|
||||
Parser<OmpObjectList>{}))
|
||||
|
||||
TYPE_PARSER(construct<OmpCancellationConstructTypeClause>(
|
||||
OmpDirectiveNameParser{}, maybe(parenthesized(scalarLogicalExpr))))
|
||||
|
||||
// 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
|
||||
TYPE_PARSER(construct<OmpDefaultClause::DataSharingAttribute>(
|
||||
"PRIVATE" >> pure(OmpDefaultClause::DataSharingAttribute::Private) ||
|
||||
@ -804,8 +821,9 @@ TYPE_PARSER(construct<OmpAbsentClause>(many(maybe(","_tok) >>
|
||||
TYPE_PARSER(construct<OmpContainsClause>(many(maybe(","_tok) >>
|
||||
construct<llvm::omp::Directive>(unwrap(OmpDirectiveNameParser{})))))
|
||||
|
||||
TYPE_PARSER("ABSENT" >> construct<OmpClause>(construct<OmpClause::Absent>(
|
||||
parenthesized(Parser<OmpAbsentClause>{}))) ||
|
||||
TYPE_PARSER( //
|
||||
"ABSENT" >> construct<OmpClause>(construct<OmpClause::Absent>(
|
||||
parenthesized(Parser<OmpAbsentClause>{}))) ||
|
||||
"ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
|
||||
"ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
|
||||
"AFFINITY" >> construct<OmpClause>(construct<OmpClause::Affinity>(
|
||||
@ -982,7 +1000,20 @@ TYPE_PARSER("ABSENT" >> construct<OmpClause>(construct<OmpClause::Absent>(
|
||||
"UPDATE" >> construct<OmpClause>(construct<OmpClause::Update>(
|
||||
parenthesized(Parser<OmpUpdateClause>{}))) ||
|
||||
"WHEN" >> construct<OmpClause>(construct<OmpClause::When>(
|
||||
parenthesized(Parser<OmpWhenClause>{}))))
|
||||
parenthesized(Parser<OmpWhenClause>{}))) ||
|
||||
// Cancellable constructs
|
||||
"DO"_id >=
|
||||
construct<OmpClause>(construct<OmpClause::CancellationConstructType>(
|
||||
Parser<OmpCancellationConstructTypeClause>{})) ||
|
||||
"PARALLEL"_id >=
|
||||
construct<OmpClause>(construct<OmpClause::CancellationConstructType>(
|
||||
Parser<OmpCancellationConstructTypeClause>{})) ||
|
||||
"SECTIONS"_id >=
|
||||
construct<OmpClause>(construct<OmpClause::CancellationConstructType>(
|
||||
Parser<OmpCancellationConstructTypeClause>{})) ||
|
||||
"TASKGROUP"_id >=
|
||||
construct<OmpClause>(construct<OmpClause::CancellationConstructType>(
|
||||
Parser<OmpCancellationConstructTypeClause>{})))
|
||||
|
||||
// [Clause, [Clause], ...]
|
||||
TYPE_PARSER(sourced(construct<OmpClauseList>(
|
||||
@ -1096,20 +1127,13 @@ TYPE_PARSER(sourced(construct<OmpLoopDirective>(first(
|
||||
TYPE_PARSER(sourced(construct<OmpBeginLoopDirective>(
|
||||
sourced(Parser<OmpLoopDirective>{}), Parser<OmpClauseList>{})))
|
||||
|
||||
// 2.14.1 construct-type-clause -> PARALLEL | SECTIONS | DO | TASKGROUP
|
||||
TYPE_PARSER(sourced(construct<OmpCancelType>(
|
||||
first("PARALLEL" >> pure(OmpCancelType::Type::Parallel),
|
||||
"SECTIONS" >> pure(OmpCancelType::Type::Sections),
|
||||
"DO" >> pure(OmpCancelType::Type::Do),
|
||||
"TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup)))))
|
||||
|
||||
// 2.14.2 Cancellation Point construct
|
||||
TYPE_PARSER(sourced(construct<OpenMPCancellationPointConstruct>(
|
||||
verbatim("CANCELLATION POINT"_tok), Parser<OmpCancelType>{})))
|
||||
verbatim("CANCELLATION POINT"_tok), Parser<OmpClauseList>{})))
|
||||
|
||||
// 2.14.1 Cancel construct
|
||||
TYPE_PARSER(sourced(construct<OpenMPCancelConstruct>(verbatim("CANCEL"_tok),
|
||||
Parser<OmpCancelType>{}, maybe("IF" >> parenthesized(scalarLogicalExpr)))))
|
||||
TYPE_PARSER(sourced(construct<OpenMPCancelConstruct>(
|
||||
verbatim("CANCEL"_tok), Parser<OmpClauseList>{})))
|
||||
|
||||
TYPE_PARSER(sourced(construct<OmpFailClause>(
|
||||
parenthesized(indirect(Parser<OmpMemoryOrderClause>{})))))
|
||||
@ -1193,9 +1217,10 @@ TYPE_PARSER(
|
||||
sourced(construct<OpenMPStandaloneConstruct>(
|
||||
Parser<OpenMPSimpleStandaloneConstruct>{}) ||
|
||||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||
|
||||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
|
||||
// Try CANCELLATION POINT before CANCEL.
|
||||
construct<OpenMPStandaloneConstruct>(
|
||||
Parser<OpenMPCancellationPointConstruct>{}) ||
|
||||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
|
||||
construct<OpenMPStandaloneConstruct>(
|
||||
Parser<OmpMetadirectiveDirective>{}) ||
|
||||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPDepobjConstruct>{})) /
|
||||
|
@ -2851,15 +2851,14 @@ public:
|
||||
void Unparse(const OpenMPCancellationPointConstruct &x) {
|
||||
BeginOpenMP();
|
||||
Word("!$OMP CANCELLATION POINT ");
|
||||
Walk(std::get<OmpCancelType>(x.t));
|
||||
Walk(std::get<OmpClauseList>(x.t));
|
||||
Put("\n");
|
||||
EndOpenMP();
|
||||
}
|
||||
void Unparse(const OpenMPCancelConstruct &x) {
|
||||
BeginOpenMP();
|
||||
Word("!$OMP CANCEL ");
|
||||
Walk(std::get<OmpCancelType>(x.t));
|
||||
Walk(std::get<std::optional<OpenMPCancelConstruct::If>>(x.t));
|
||||
Walk(std::get<OmpClauseList>(x.t));
|
||||
Put("\n");
|
||||
EndOpenMP();
|
||||
}
|
||||
@ -3034,7 +3033,6 @@ public:
|
||||
OmpDeviceTypeClause, DeviceTypeDescription) // OMP device_type
|
||||
WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier
|
||||
WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation
|
||||
WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
|
||||
WALK_NESTED_ENUM(OmpOrderClause, Ordering) // OMP ordering
|
||||
WALK_NESTED_ENUM(OmpOrderModifier, Value) // OMP order-modifier
|
||||
WALK_NESTED_ENUM(OmpPrescriptiveness, Value) // OMP prescriptiveness
|
||||
|
@ -2244,9 +2244,13 @@ void OmpStructureChecker::Leave(const parser::OpenMPFlushConstruct &x) {
|
||||
|
||||
void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
|
||||
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
||||
const auto &type{std::get<parser::OmpCancelType>(x.t)};
|
||||
const auto &clauses{std::get<parser::OmpClauseList>(x.t)};
|
||||
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_cancel);
|
||||
CheckCancellationNest(dir.source, type.v);
|
||||
|
||||
if (auto maybeConstruct{GetCancelType(
|
||||
llvm::omp::Directive::OMPD_cancel, x.source, clauses)}) {
|
||||
CheckCancellationNest(dir.source, *maybeConstruct);
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) {
|
||||
@ -2296,13 +2300,37 @@ void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) {
|
||||
dirContext_.pop_back();
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(
|
||||
const parser::OmpClause::CancellationConstructType &x) {
|
||||
// Do not call CheckAllowed/CheckAllowedClause, because in case of an error
|
||||
// it will print "CANCELLATION_CONSTRUCT_TYPE" as the clause name instead of
|
||||
// the contained construct name.
|
||||
auto &dirName{std::get<parser::OmpDirectiveName>(x.v.t)};
|
||||
switch (dirName.v) {
|
||||
case llvm::omp::Directive::OMPD_do:
|
||||
case llvm::omp::Directive::OMPD_parallel:
|
||||
case llvm::omp::Directive::OMPD_sections:
|
||||
case llvm::omp::Directive::OMPD_taskgroup:
|
||||
break;
|
||||
default:
|
||||
context_.Say(dirName.source, "%s is not a cancellable construct"_err_en_US,
|
||||
parser::ToUpperCaseLetters(
|
||||
llvm::omp::getOpenMPDirectiveName(dirName.v).str()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(
|
||||
const parser::OpenMPCancellationPointConstruct &x) {
|
||||
const auto &dir{std::get<parser::Verbatim>(x.t)};
|
||||
const auto &type{std::get<parser::OmpCancelType>(x.t)};
|
||||
const auto &clauses{std::get<parser::OmpClauseList>(x.t)};
|
||||
PushContextAndClauseSets(
|
||||
dir.source, llvm::omp::Directive::OMPD_cancellation_point);
|
||||
CheckCancellationNest(dir.source, type.v);
|
||||
|
||||
if (auto maybeConstruct{GetCancelType(
|
||||
llvm::omp::Directive::OMPD_cancellation_point, x.source, clauses)}) {
|
||||
CheckCancellationNest(dir.source, *maybeConstruct);
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Leave(
|
||||
@ -2310,8 +2338,42 @@ void OmpStructureChecker::Leave(
|
||||
dirContext_.pop_back();
|
||||
}
|
||||
|
||||
std::optional<llvm::omp::Directive> OmpStructureChecker::GetCancelType(
|
||||
llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
|
||||
const parser::OmpClauseList &clauses) {
|
||||
// Given clauses from CANCEL or CANCELLATION_POINT, identify the construct
|
||||
// to which the cancellation applies.
|
||||
std::optional<llvm::omp::Directive> cancelee;
|
||||
llvm::StringRef cancelName{llvm::omp::getOpenMPDirectiveName(cancelDir)};
|
||||
|
||||
for (const parser::OmpClause &clause : clauses.v) {
|
||||
using CancellationConstructType =
|
||||
parser::OmpClause::CancellationConstructType;
|
||||
if (auto *cctype{std::get_if<CancellationConstructType>(&clause.u)}) {
|
||||
if (cancelee) {
|
||||
context_.Say(cancelSource,
|
||||
"Multiple cancel-directive-name clauses are not allowed on the %s construct"_err_en_US,
|
||||
parser::ToUpperCaseLetters(cancelName.str()));
|
||||
return std::nullopt;
|
||||
}
|
||||
cancelee = std::get<parser::OmpDirectiveName>(cctype->v.t).v;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cancelee) {
|
||||
context_.Say(cancelSource,
|
||||
"Missing cancel-directive-name clause on the %s construct"_err_en_US,
|
||||
parser::ToUpperCaseLetters(cancelName.str()));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return cancelee;
|
||||
}
|
||||
|
||||
void OmpStructureChecker::CheckCancellationNest(
|
||||
const parser::CharBlock &source, const parser::OmpCancelType::Type &type) {
|
||||
const parser::CharBlock &source, llvm::omp::Directive type) {
|
||||
llvm::StringRef typeName{llvm::omp::getOpenMPDirectiveName(type)};
|
||||
|
||||
if (CurrentDirectiveIsNested()) {
|
||||
// If construct-type-clause is taskgroup, the cancellation construct must be
|
||||
// closely nested inside a task or a taskloop construct and the cancellation
|
||||
@ -2322,8 +2384,9 @@ void OmpStructureChecker::CheckCancellationNest(
|
||||
// that matches the type specified in construct-type-clause of the
|
||||
// cancellation construct.
|
||||
bool eligibleCancellation{false};
|
||||
|
||||
switch (type) {
|
||||
case parser::OmpCancelType::Type::Taskgroup:
|
||||
case llvm::omp::Directive::OMPD_taskgroup:
|
||||
if (llvm::omp::nestedCancelTaskgroupAllowedSet.test(
|
||||
GetContextParent().directive)) {
|
||||
eligibleCancellation = true;
|
||||
@ -2349,38 +2412,37 @@ void OmpStructureChecker::CheckCancellationNest(
|
||||
}
|
||||
if (!eligibleCancellation) {
|
||||
context_.Say(source,
|
||||
"With %s clause, %s construct must be closely nested inside TASK "
|
||||
"or TASKLOOP construct and %s region must be closely nested inside "
|
||||
"TASKGROUP region"_err_en_US,
|
||||
parser::ToUpperCaseLetters(
|
||||
parser::OmpCancelType::EnumToString(type)),
|
||||
"With %s clause, %s construct must be closely nested inside TASK or TASKLOOP construct and %s region must be closely nested inside TASKGROUP region"_err_en_US,
|
||||
parser::ToUpperCaseLetters(typeName.str()),
|
||||
ContextDirectiveAsFortran(), ContextDirectiveAsFortran());
|
||||
}
|
||||
return;
|
||||
case parser::OmpCancelType::Type::Sections:
|
||||
case llvm::omp::Directive::OMPD_sections:
|
||||
if (llvm::omp::nestedCancelSectionsAllowedSet.test(
|
||||
GetContextParent().directive)) {
|
||||
eligibleCancellation = true;
|
||||
}
|
||||
break;
|
||||
case parser::OmpCancelType::Type::Do:
|
||||
case llvm::omp::Directive::OMPD_do:
|
||||
if (llvm::omp::nestedCancelDoAllowedSet.test(
|
||||
GetContextParent().directive)) {
|
||||
eligibleCancellation = true;
|
||||
}
|
||||
break;
|
||||
case parser::OmpCancelType::Type::Parallel:
|
||||
case llvm::omp::Directive::OMPD_parallel:
|
||||
if (llvm::omp::nestedCancelParallelAllowedSet.test(
|
||||
GetContextParent().directive)) {
|
||||
eligibleCancellation = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// This should have been diagnosed by this point.
|
||||
llvm_unreachable("Unexpected directive");
|
||||
}
|
||||
if (!eligibleCancellation) {
|
||||
context_.Say(source,
|
||||
"With %s clause, %s construct cannot be closely nested inside %s "
|
||||
"construct"_err_en_US,
|
||||
parser::ToUpperCaseLetters(parser::OmpCancelType::EnumToString(type)),
|
||||
"With %s clause, %s construct cannot be closely nested inside %s construct"_err_en_US,
|
||||
parser::ToUpperCaseLetters(typeName.str()),
|
||||
ContextDirectiveAsFortran(),
|
||||
parser::ToUpperCaseLetters(
|
||||
getDirectiveName(GetContextParent().directive).str()));
|
||||
@ -2388,38 +2450,33 @@ void OmpStructureChecker::CheckCancellationNest(
|
||||
} else {
|
||||
// The cancellation directive cannot be orphaned.
|
||||
switch (type) {
|
||||
case parser::OmpCancelType::Type::Taskgroup:
|
||||
case llvm::omp::Directive::OMPD_taskgroup:
|
||||
context_.Say(source,
|
||||
"%s %s directive is not closely nested inside "
|
||||
"TASK or TASKLOOP"_err_en_US,
|
||||
"%s %s directive is not closely nested inside TASK or TASKLOOP"_err_en_US,
|
||||
ContextDirectiveAsFortran(),
|
||||
parser::ToUpperCaseLetters(
|
||||
parser::OmpCancelType::EnumToString(type)));
|
||||
parser::ToUpperCaseLetters(typeName.str()));
|
||||
break;
|
||||
case parser::OmpCancelType::Type::Sections:
|
||||
case llvm::omp::Directive::OMPD_sections:
|
||||
context_.Say(source,
|
||||
"%s %s directive is not closely nested inside "
|
||||
"SECTION or SECTIONS"_err_en_US,
|
||||
"%s %s directive is not closely nested inside SECTION or SECTIONS"_err_en_US,
|
||||
ContextDirectiveAsFortran(),
|
||||
parser::ToUpperCaseLetters(
|
||||
parser::OmpCancelType::EnumToString(type)));
|
||||
parser::ToUpperCaseLetters(typeName.str()));
|
||||
break;
|
||||
case parser::OmpCancelType::Type::Do:
|
||||
case llvm::omp::Directive::OMPD_do:
|
||||
context_.Say(source,
|
||||
"%s %s directive is not closely nested inside "
|
||||
"the construct that matches the DO clause type"_err_en_US,
|
||||
"%s %s directive is not closely nested inside the construct that matches the DO clause type"_err_en_US,
|
||||
ContextDirectiveAsFortran(),
|
||||
parser::ToUpperCaseLetters(
|
||||
parser::OmpCancelType::EnumToString(type)));
|
||||
parser::ToUpperCaseLetters(typeName.str()));
|
||||
break;
|
||||
case parser::OmpCancelType::Type::Parallel:
|
||||
case llvm::omp::Directive::OMPD_parallel:
|
||||
context_.Say(source,
|
||||
"%s %s directive is not closely nested inside "
|
||||
"the construct that matches the PARALLEL clause type"_err_en_US,
|
||||
"%s %s directive is not closely nested inside the construct that matches the PARALLEL clause type"_err_en_US,
|
||||
ContextDirectiveAsFortran(),
|
||||
parser::ToUpperCaseLetters(
|
||||
parser::OmpCancelType::EnumToString(type)));
|
||||
parser::ToUpperCaseLetters(typeName.str()));
|
||||
break;
|
||||
default:
|
||||
// This should have been diagnosed by this point.
|
||||
llvm_unreachable("Unexpected directive");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3106,7 +3163,6 @@ CHECK_SIMPLE_CLAUSE(MemoryOrder, OMPC_memory_order)
|
||||
CHECK_SIMPLE_CLAUSE(Bind, OMPC_bind)
|
||||
CHECK_SIMPLE_CLAUSE(Align, OMPC_align)
|
||||
CHECK_SIMPLE_CLAUSE(Compare, OMPC_compare)
|
||||
CHECK_SIMPLE_CLAUSE(CancellationConstructType, OMPC_cancellation_construct_type)
|
||||
CHECK_SIMPLE_CLAUSE(OmpxAttribute, OMPC_ompx_attribute)
|
||||
CHECK_SIMPLE_CLAUSE(Weak, OMPC_weak)
|
||||
|
||||
|
@ -275,8 +275,11 @@ private:
|
||||
void CheckTargetUpdate();
|
||||
void CheckDependenceType(const parser::OmpDependenceType::Value &x);
|
||||
void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
|
||||
std::optional<llvm::omp::Directive> GetCancelType(
|
||||
llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
|
||||
const parser::OmpClauseList &clauses);
|
||||
void CheckCancellationNest(
|
||||
const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
|
||||
const parser::CharBlock &source, llvm::omp::Directive type);
|
||||
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
|
||||
void CheckReductionObjects(
|
||||
const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
|
||||
|
29
flang/test/Semantics/OpenMP/cancel.f90
Normal file
29
flang/test/Semantics/OpenMP/cancel.f90
Normal file
@ -0,0 +1,29 @@
|
||||
!RUN: %python %S/../test_errors.py %s %flang -fopenmp
|
||||
|
||||
subroutine f00
|
||||
!$omp parallel
|
||||
!ERROR: Missing cancel-directive-name clause on the CANCEL construct
|
||||
!$omp cancel
|
||||
!$omp end parallel
|
||||
end
|
||||
|
||||
subroutine f01
|
||||
!$omp parallel
|
||||
!ERROR: Multiple cancel-directive-name clauses are not allowed on the CANCEL construct
|
||||
!$omp cancel parallel parallel
|
||||
!$omp end parallel
|
||||
end
|
||||
|
||||
subroutine f02
|
||||
!$omp parallel
|
||||
!ERROR: Missing cancel-directive-name clause on the CANCELLATION POINT construct
|
||||
!$omp cancellation point
|
||||
!$omp end parallel
|
||||
end
|
||||
|
||||
subroutine f03
|
||||
!$omp parallel
|
||||
!ERROR: Multiple cancel-directive-name clauses are not allowed on the CANCELLATION POINT construct
|
||||
!$omp cancellation point parallel parallel
|
||||
!$omp end parallel
|
||||
end
|
@ -105,6 +105,7 @@ def OMPC_CancellationConstructType : Clause<"cancellation_construct_type"> {
|
||||
OMP_CANCELLATION_CONSTRUCT_Taskgroup,
|
||||
OMP_CANCELLATION_CONSTRUCT_None
|
||||
];
|
||||
let flangClass = "OmpCancellationConstructTypeClause";
|
||||
}
|
||||
def OMPC_Contains : Clause<"contains"> {
|
||||
let clangClass = "OMPContainsClause";
|
||||
@ -647,12 +648,16 @@ def OMP_BeginDeclareVariant : Directive<"begin declare variant"> {
|
||||
}
|
||||
def OMP_Cancel : Directive<"cancel"> {
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_CancellationConstructType>,
|
||||
VersionedClause<OMPC_If>,
|
||||
];
|
||||
let association = AS_None;
|
||||
let category = CA_Executable;
|
||||
}
|
||||
def OMP_CancellationPoint : Directive<"cancellation point"> {
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_CancellationConstructType>,
|
||||
];
|
||||
let association = AS_None;
|
||||
let category = CA_Executable;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user