[flang] [OpenMP] parse tree changes for standalone directives (flang-compiler/f18#627)

* [OpenMP] parse tree changes for standalone directives

1. Put all standalone directives except FLUSH, CANCEL, and CANCELLATION POINT
   into one `OpenMPSimpleStandaloneConstruct` (for no-clause directive,
   validity checks will be deferred to Semantics). A top-level class will
   include all the standalone directive nodes. This simplies the logic a lot.

2. All the standalone directives now have their own source provenance for
   directive name itself.

3. Change check-omp-structure.* to avoid assertions

4. Add basic tests for standalone directives, more will be added during
   the clause validity checks in Semantics

* Resolve !$OMP ORDERED ambiguity by attempting block construct first - Peter

Original-commit: flang-compiler/f18@a77aa7ed84
Reviewed-on: https://github.com/flang-compiler/f18/pull/627
This commit is contained in:
Jinxin (Brian) Yang 2019-08-06 11:59:40 -07:00 committed by GitHub
parent fb30d812e7
commit c4e13f6be8
7 changed files with 169 additions and 81 deletions

View file

@ -512,8 +512,8 @@ public:
NODE(parser, OmpScheduleModifierType) NODE(parser, OmpScheduleModifierType)
NODE_ENUM(parser::OmpScheduleModifierType, ModType) NODE_ENUM(parser::OmpScheduleModifierType, ModType)
NODE(parser, OmpSection) NODE(parser, OmpSection)
NODE(parser, OmpStandaloneDirective) NODE(parser, OmpSimpleStandaloneDirective)
NODE_ENUM(parser::OmpStandaloneDirective, Directive) NODE_ENUM(parser::OmpSimpleStandaloneDirective, Directive)
NODE(parser, Only) NODE(parser, Only)
NODE(parser, OpenMPAtomicConstruct) NODE(parser, OpenMPAtomicConstruct)
NODE(parser, OpenMPBlockConstruct) NODE(parser, OpenMPBlockConstruct)
@ -535,8 +535,7 @@ public:
NODE(parser, OpenMPEndLoopDirective) NODE(parser, OpenMPEndLoopDirective)
NODE(parser, OpenMPFlushConstruct) NODE(parser, OpenMPFlushConstruct)
NODE(parser, OpenMPLoopConstruct) NODE(parser, OpenMPLoopConstruct)
NODE(parser, OpenMPSimpleConstruct) NODE(parser, OpenMPSimpleStandaloneConstruct)
NODE_ENUM(parser::OpenMPSimpleConstruct, Directive)
NODE(parser, OpenMPStandaloneConstruct) NODE(parser, OpenMPStandaloneConstruct)
NODE(parser, OpenMPSectionsConstruct) NODE(parser, OpenMPSectionsConstruct)
NODE(parser, OpenMPSingleConstruct) NODE(parser, OpenMPSingleConstruct)

View file

@ -297,25 +297,42 @@ TYPE_PARSER(sourced(construct<OmpCancelType>(
"TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup))))) "TASKGROUP" >> pure(OmpCancelType::Type::Taskgroup)))))
// Cancellation Point construct // Cancellation Point construct
TYPE_PARSER(construct<OpenMPCancellationPointConstruct>( TYPE_PARSER(sourced(construct<OpenMPCancellationPointConstruct>(
sourced("CANCELLATION POINT" >> Parser<OmpCancelType>{}))) verbatim("CANCELLATION POINT"_tok), Parser<OmpCancelType>{})))
// Cancel construct // Cancel construct
TYPE_PARSER(construct<OpenMPCancelConstruct>( TYPE_PARSER(sourced(construct<OpenMPCancelConstruct>(verbatim("CANCEL"_tok),
sourced("CANCEL" >> Parser<OmpCancelType>{}), Parser<OmpCancelType>{}, maybe("IF" >> parenthesized(scalarLogicalExpr)))))
maybe("IF" >> parenthesized(scalarLogicalExpr))))
// Flush construct // Flush construct
TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>( TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(
"FLUSH" >> maybe(parenthesized(Parser<OmpObjectList>{}))))) verbatim("FLUSH"_tok), maybe(parenthesized(Parser<OmpObjectList>{})))))
// Standalone directives // Simple Standalone Directives
TYPE_PARSER(sourced(construct<OmpStandaloneDirective>(first( TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first(
"BARRIER" >> pure(OmpSimpleStandaloneDirective::Directive::Barrier),
"ORDERED" >> pure(OmpSimpleStandaloneDirective::Directive::Ordered),
"TARGET ENTER DATA" >> "TARGET ENTER DATA" >>
pure(OmpStandaloneDirective::Directive::TargetEnterData), pure(OmpSimpleStandaloneDirective::Directive::TargetEnterData),
"TARGET EXIT DATA" >> "TARGET EXIT DATA" >>
pure(OmpStandaloneDirective::Directive::TargetExitData), pure(OmpSimpleStandaloneDirective::Directive::TargetExitData),
"TARGET UPDATE" >> pure(OmpStandaloneDirective::Directive::TargetUpdate))))) "TARGET UPDATE" >>
pure(OmpSimpleStandaloneDirective::Directive::TargetUpdate),
"TASKWAIT" >> pure(OmpSimpleStandaloneDirective::Directive::Taskwait),
"TASKYIELD" >> pure(OmpSimpleStandaloneDirective::Directive::Taskyield)))))
TYPE_PARSER(sourced(construct<OpenMPSimpleStandaloneConstruct>(
Parser<OmpSimpleStandaloneDirective>{}, Parser<OmpClauseList>{})))
// Standalone Constructs
TYPE_PARSER(
sourced(construct<OpenMPStandaloneConstruct>(
Parser<OpenMPSimpleStandaloneConstruct>{}) ||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||
construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
construct<OpenMPStandaloneConstruct>(
Parser<OpenMPCancellationPointConstruct>{})) /
endOfLine)
// Directives enclosing structured-block // Directives enclosing structured-block
TYPE_PARSER(sourced(construct<OmpBlockDirective>( TYPE_PARSER(sourced(construct<OmpBlockDirective>(
@ -454,17 +471,6 @@ TYPE_PARSER(construct<OpenMPBlockConstruct>(Parser<OmpBlockDirective>{},
Parser<OmpClauseList>{} / endOmpLine, block, Parser<OmpClauseList>{} / endOmpLine, block,
Parser<OmpEndBlockDirective>{})) Parser<OmpEndBlockDirective>{}))
// Simple constructs without clauses
TYPE_PARSER(
sourced(construct<OpenMPSimpleConstruct>(first(
"BARRIER" >> pure(OpenMPSimpleConstruct::Directive::Barrier),
"TASKWAIT" >> pure(OpenMPSimpleConstruct::Directive::Taskwait),
"TASKYIELD" >> pure(OpenMPSimpleConstruct::Directive::Taskyield)))) /
endOmpLine)
TYPE_PARSER(construct<OpenMPStandaloneConstruct>(
Parser<OmpStandaloneDirective>{}, Parser<OmpClauseList>{} / endOmpLine))
// OMP SINGLE // OMP SINGLE
TYPE_PARSER(startOmpLine >> construct<OmpEndSingle>(verbatim("END SINGLE"_tok), TYPE_PARSER(startOmpLine >> construct<OmpEndSingle>(verbatim("END SINGLE"_tok),
Parser<OmpClauseList>{}) / Parser<OmpClauseList>{}) /
@ -507,21 +513,18 @@ TYPE_PARSER(construct<OmpSection>(verbatim("SECTION"_tok) / endOmpLine))
TYPE_CONTEXT_PARSER("OpenMP construct"_en_US, TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
startOmpLine >> startOmpLine >>
first(construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}), first(construct<OpenMPConstruct>(Parser<OpenMPSingleConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPSimpleConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPSingleConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}), construct<OpenMPConstruct>(Parser<OpenMPSectionsConstruct>{}),
construct<OpenMPConstruct>( construct<OpenMPConstruct>(
Parser<OpenMPParallelSectionsConstruct>{}), Parser<OpenMPParallelSectionsConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPWorkshareConstruct>{}), construct<OpenMPConstruct>(Parser<OpenMPWorkshareConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}), construct<OpenMPConstruct>(Parser<OpenMPLoopConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPBlockConstruct>{}), construct<OpenMPConstruct>(Parser<OpenMPBlockConstruct>{}),
// OpenMPBlockConstruct is attempted before
// OpenMPStandaloneConstruct to resolve !$OMP ORDERED
construct<OpenMPConstruct>(Parser<OpenMPStandaloneConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}), construct<OpenMPConstruct>(Parser<OpenMPAtomicConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}), construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPCancelConstruct>{}),
construct<OpenMPConstruct>(
Parser<OpenMPCancellationPointConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPFlushConstruct>{}),
construct<OpenMPConstruct>(Parser<OmpSection>{}))) construct<OpenMPConstruct>(Parser<OmpSection>{})))
// END OMP Block directives // END OMP Block directives

View file

@ -3666,38 +3666,47 @@ struct OmpCancelType {
}; };
// CANCELLATION POINT // CANCELLATION POINT
WRAPPER_CLASS(OpenMPCancellationPointConstruct, OmpCancelType); struct OpenMPCancellationPointConstruct {
TUPLE_CLASS_BOILERPLATE(OpenMPCancellationPointConstruct);
CharBlock source;
std::tuple<Verbatim, OmpCancelType> t;
};
// CANCEL // CANCEL
struct OpenMPCancelConstruct { struct OpenMPCancelConstruct {
TUPLE_CLASS_BOILERPLATE(OpenMPCancelConstruct); TUPLE_CLASS_BOILERPLATE(OpenMPCancelConstruct);
WRAPPER_CLASS(If, ScalarLogicalExpr); WRAPPER_CLASS(If, ScalarLogicalExpr);
std::tuple<OmpCancelType, std::optional<If>> t; CharBlock source;
std::tuple<Verbatim, OmpCancelType, std::optional<If>> t;
}; };
// FLUSH // FLUSH
struct OpenMPFlushConstruct { struct OpenMPFlushConstruct {
WRAPPER_CLASS_BOILERPLATE(OpenMPFlushConstruct, std::optional<OmpObjectList>); TUPLE_CLASS_BOILERPLATE(OpenMPFlushConstruct);
CharBlock source; CharBlock source;
std::tuple<Verbatim, std::optional<OmpObjectList>> t;
}; };
// These simple constructs do not have clauses. // These simple constructs do not have clauses.
struct OpenMPSimpleConstruct { struct OmpSimpleStandaloneDirective {
ENUM_CLASS(Directive, Barrier, Taskwait, Taskyield) ENUM_CLASS(Directive, Barrier, Taskwait, Taskyield, TargetEnterData,
WRAPPER_CLASS_BOILERPLATE(OpenMPSimpleConstruct, Directive); TargetExitData, TargetUpdate, Ordered)
WRAPPER_CLASS_BOILERPLATE(OmpSimpleStandaloneDirective, Directive);
CharBlock source; CharBlock source;
}; };
// Standalone constructs; these can have clauses. struct OpenMPSimpleStandaloneConstruct {
struct OmpStandaloneDirective { TUPLE_CLASS_BOILERPLATE(OpenMPSimpleStandaloneConstruct);
ENUM_CLASS(Directive, TargetEnterData, TargetExitData, TargetUpdate)
WRAPPER_CLASS_BOILERPLATE(OmpStandaloneDirective, Directive);
CharBlock source; CharBlock source;
std::tuple<OmpSimpleStandaloneDirective, OmpClauseList> t;
}; };
struct OpenMPStandaloneConstruct { struct OpenMPStandaloneConstruct {
TUPLE_CLASS_BOILERPLATE(OpenMPStandaloneConstruct); UNION_CLASS_BOILERPLATE(OpenMPStandaloneConstruct);
std::tuple<OmpStandaloneDirective, OmpClauseList> t; CharBlock source;
std::variant<OpenMPSimpleStandaloneConstruct, OpenMPFlushConstruct,
OpenMPCancelConstruct, OpenMPCancellationPointConstruct>
u;
}; };
WRAPPER_CLASS(OmpEndBlockDirective, OmpBlockDirective); WRAPPER_CLASS(OmpEndBlockDirective, OmpBlockDirective);
@ -3722,13 +3731,10 @@ struct OpenMPLoopConstruct {
struct OpenMPConstruct { struct OpenMPConstruct {
UNION_CLASS_BOILERPLATE(OpenMPConstruct); UNION_CLASS_BOILERPLATE(OpenMPConstruct);
std::variant<OpenMPStandaloneConstruct, OpenMPSimpleConstruct, std::variant<OpenMPStandaloneConstruct, OpenMPSingleConstruct,
OpenMPSingleConstruct, OpenMPSectionsConstruct, OpenMPSectionsConstruct, OpenMPParallelSectionsConstruct,
OpenMPParallelSectionsConstruct, OpenMPWorkshareConstruct, OpenMPWorkshareConstruct, OpenMPLoopConstruct, OpenMPBlockConstruct,
OpenMPLoopConstruct, OpenMPBlockConstruct, OpenMPAtomicConstruct, OpenMPCriticalConstruct, OmpSection>
OpenMPCancellationPointConstruct, OpenMPCancelConstruct,
OpenMPFlushConstruct, OpenMPAtomicConstruct, OpenMPCriticalConstruct,
OmpSection>
u; u;
}; };
} }

View file

@ -2046,17 +2046,29 @@ public:
} }
} }
void Unparse(const OmpObjectList &x) { Walk(x.v, ","); } void Unparse(const OmpObjectList &x) { Walk(x.v, ","); }
void Unparse(const OmpStandaloneDirective &x) { void Unparse(const OmpSimpleStandaloneDirective &x) {
switch (x.v) { switch (x.v) {
case OmpStandaloneDirective::Directive::TargetEnterData: case OmpSimpleStandaloneDirective::Directive::Barrier:
Word("BARRIER ");
break;
case OmpSimpleStandaloneDirective::Directive::Taskwait:
Word("TASKWAIT ");
break;
case OmpSimpleStandaloneDirective::Directive::Taskyield:
Word("TASKYIELD ");
break;
case OmpSimpleStandaloneDirective::Directive::TargetEnterData:
Word("TARGET ENTER DATA "); Word("TARGET ENTER DATA ");
break; break;
case OmpStandaloneDirective::Directive::TargetExitData: case OmpSimpleStandaloneDirective::Directive::TargetExitData:
Word("TARGET EXIT DATA "); Word("TARGET EXIT DATA ");
break; break;
case OmpStandaloneDirective::Directive::TargetUpdate: case OmpSimpleStandaloneDirective::Directive::TargetUpdate:
Word("TARGET UPDATE "); Word("TARGET UPDATE ");
break; break;
case OmpSimpleStandaloneDirective::Directive::Ordered:
Word("ORDERED ");
break;
} }
} }
void Unparse(const OmpBlockDirective &x) { void Unparse(const OmpBlockDirective &x) {
@ -2305,7 +2317,7 @@ public:
void Unparse(const OpenMPCancellationPointConstruct &x) { void Unparse(const OpenMPCancellationPointConstruct &x) {
BeginOpenMP(); BeginOpenMP();
Word("!$OMP CANCELLATION POINT "); Word("!$OMP CANCELLATION POINT ");
Walk(x.v); Walk(std::get<OmpCancelType>(x.t));
Put("\n"); Put("\n");
EndOpenMP(); EndOpenMP();
} }
@ -2320,11 +2332,7 @@ public:
void Unparse(const OpenMPFlushConstruct &x) { void Unparse(const OpenMPFlushConstruct &x) {
BeginOpenMP(); BeginOpenMP();
Word("!$OMP FLUSH"); Word("!$OMP FLUSH");
if ((x.v).has_value()) { Walk("(", std::get<std::optional<OmpObjectList>>(x.t), ")");
Put("(");
Walk(x.v);
Put(")");
}
Put("\n"); Put("\n");
EndOpenMP(); EndOpenMP();
} }
@ -2338,21 +2346,10 @@ public:
EndOpenMP(); EndOpenMP();
} }
void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); } void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); }
void Unparse(const OpenMPSimpleConstruct &x) { void Unparse(const OpenMPSimpleStandaloneConstruct &x) {
BeginOpenMP(); BeginOpenMP();
Word("!$OMP "); Word("!$OMP ");
switch (x.v) { Walk(std::get<OmpSimpleStandaloneDirective>(x.t));
case OpenMPSimpleConstruct::Directive::Barrier: Word("BARRIER"); break;
case OpenMPSimpleConstruct::Directive::Taskwait: Word("TASKWAIT"); break;
case OpenMPSimpleConstruct::Directive::Taskyield: Word("TASKYIELD"); break;
}
Put("\n");
EndOpenMP();
}
void Unparse(const OpenMPStandaloneConstruct &x) {
BeginOpenMP();
Word("!$OMP ");
Walk(std::get<OmpStandaloneDirective>(x.t));
Walk(std::get<OmpClauseList>(x.t)); Walk(std::get<OmpClauseList>(x.t));
Put("\n"); Put("\n");
EndOpenMP(); EndOpenMP();

View file

@ -104,7 +104,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
SetContextAllowed(allowed); SetContextAllowed(allowed);
} }
void OmpStructureChecker::Leave(const parser::OpenMPSectionsConstruct &x) { void OmpStructureChecker::Leave(const parser::OpenMPSectionsConstruct &) {
ompContext_.pop_back(); ompContext_.pop_back();
} }
@ -126,7 +126,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPSingleConstruct &x) {
SetContextAllowed(allowed); SetContextAllowed(allowed);
} }
void OmpStructureChecker::Leave(const parser::OpenMPSingleConstruct &x) { void OmpStructureChecker::Leave(const parser::OpenMPSingleConstruct &) {
ompContext_.pop_back(); ompContext_.pop_back();
} }
@ -140,7 +140,7 @@ void OmpStructureChecker::Enter(const parser::OmpEndSingle &x) {
SetContextAllowedOnce(allowedOnce); SetContextAllowedOnce(allowedOnce);
} }
void OmpStructureChecker::Leave(const parser::OmpEndSingle &x) { void OmpStructureChecker::Leave(const parser::OmpEndSingle &) {
ompContext_.pop_back(); ompContext_.pop_back();
} }
@ -149,7 +149,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPWorkshareConstruct &x) {
PushContext(dir.source, OmpDirective::WORKSHARE); PushContext(dir.source, OmpDirective::WORKSHARE);
} }
void OmpStructureChecker::Leave(const parser::OpenMPWorkshareConstruct &x) { void OmpStructureChecker::Leave(const parser::OpenMPWorkshareConstruct &) {
ompContext_.pop_back(); ompContext_.pop_back();
} }
@ -158,10 +158,64 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) {
PushContext(dir.source, OmpDirective::DECLARE_SIMD); PushContext(dir.source, OmpDirective::DECLARE_SIMD);
} }
void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &x) { void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) {
ompContext_.pop_back(); ompContext_.pop_back();
} }
void OmpStructureChecker::Enter(
const parser::OpenMPSimpleStandaloneConstruct &x) {
const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
PushContext(dir.source);
}
void OmpStructureChecker::Leave(
const parser::OpenMPSimpleStandaloneConstruct &) {
ompContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OpenMPFlushConstruct &x) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
PushContext(dir.source, OmpDirective::FLUSH);
}
void OmpStructureChecker::Leave(const parser::OpenMPFlushConstruct &) {
ompContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
PushContext(dir.source, OmpDirective::CANCEL);
}
void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) {
ompContext_.pop_back();
}
void OmpStructureChecker::Enter(
const parser::OpenMPCancellationPointConstruct &x) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
PushContext(dir.source, OmpDirective::CANCELLATION_POINT);
}
void OmpStructureChecker::Leave(
const parser::OpenMPCancellationPointConstruct &) {
ompContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OmpSimpleStandaloneDirective &x) {
switch (x.v) {
case parser::OmpSimpleStandaloneDirective::Directive::Ordered: {
// 2.13.8 ordered-construct-clause -> depend-clause
SetContextDirectiveEnum(OmpDirective::ORDERED);
OmpClauseSet allowed{OmpClause::DEPEND};
SetContextAllowed(allowed);
}
default:
// TODO others
break;
}
}
void OmpStructureChecker::Enter(const parser::OmpBlockDirective &x) { void OmpStructureChecker::Enter(const parser::OmpBlockDirective &x) {
switch (x.v) { switch (x.v) {
// 2.5 parallel-clause -> if-clause | // 2.5 parallel-clause -> if-clause |

View file

@ -79,6 +79,16 @@ public:
void Enter(const parser::OpenMPDeclareSimdConstruct &); void Enter(const parser::OpenMPDeclareSimdConstruct &);
void Leave(const parser::OpenMPDeclareSimdConstruct &); void Leave(const parser::OpenMPDeclareSimdConstruct &);
void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
void Enter(const parser::OmpSimpleStandaloneDirective &);
void Enter(const parser::OpenMPFlushConstruct &);
void Leave(const parser::OpenMPFlushConstruct &);
void Enter(const parser::OpenMPCancelConstruct &);
void Leave(const parser::OpenMPCancelConstruct &);
void Enter(const parser::OpenMPCancellationPointConstruct &);
void Leave(const parser::OpenMPCancellationPointConstruct &);
void Leave(const parser::OmpClauseList &); void Leave(const parser::OmpClauseList &);
void Enter(const parser::OmpClause &); void Enter(const parser::OmpClause &);
void Enter(const parser::OmpNowait &); void Enter(const parser::OmpNowait &);

View file

@ -25,6 +25,10 @@
integer :: b = 128 integer :: b = 128
integer :: c = 32 integer :: c = 32
integer, parameter :: num = 16 integer, parameter :: num = 16
real(8) :: arrayA(256), arrayB(512)
arrayA = 1.414
arrayB = 3.14
N = 1024 N = 1024
! 2.5 parallel-clause -> if-clause | ! 2.5 parallel-clause -> if-clause |
@ -276,4 +280,19 @@
a = 3.14 a = 3.14
enddo enddo
enddo enddo
end
! Standalone Directives (basic)
!$omp taskyield
!$omp barrier
!$omp taskwait
! !$omp target enter data map(to:arrayA) map(alloc:arrayB)
! !$omp target update from(arrayA) to(arrayB)
! !$omp target exit data map(from:arrayA) map(delete:arrayB)
!$omp ordered depend(source)
!ERROR: Internal: no symbol found for 'i'
!$omp ordered depend(sink:i-1)
!$omp flush (c)
!$omp cancel DO
!$omp cancellation point parallel
end program