diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -514,6 +514,10 @@ } NODE(parser, OmpObject) NODE(parser, OmpObjectList) + NODE(parser, OmpOrderClause) + NODE_ENUM(OmpOrderClause, Type) + NODE(parser, OmpOrderModifier) + NODE_ENUM(OmpOrderModifier, Kind) NODE(parser, OmpProcBindClause) NODE_ENUM(OmpProcBindClause, Type) NODE(parser, OmpReductionClause) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3417,6 +3417,19 @@ std::tuple, std::optional> t; }; +// 2.9.5 order-clause -> ORDER ([order-modifier :]concurrent) +struct OmpOrderModifier { + UNION_CLASS_BOILERPLATE(OmpOrderModifier); + ENUM_CLASS(Kind, Reproducible, Unconstrained) + std::variant u; +}; + +struct OmpOrderClause { + TUPLE_CLASS_BOILERPLATE(OmpOrderClause); + ENUM_CLASS(Type, Concurrent) + std::tuple, Type> t; +}; + // 2.15.3.7 linear-modifier -> REF | VAL | UVAL struct OmpLinearModifier { ENUM_CLASS(Type, Ref, Val, Uval) diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -185,6 +185,16 @@ TYPE_PARSER(construct( nonemptyList(name), maybe(":" >> scalarIntConstantExpr))) +// 2.9.5 ORDER ([order-modifier :]concurrent) +TYPE_PARSER(construct( + "REPRODUCIBLE" >> pure(OmpOrderModifier::Kind::Reproducible)) || + construct( + "UNCONSTRAINED" >> pure(OmpOrderModifier::Kind::Unconstrained))) + +TYPE_PARSER(construct( + maybe(Parser{} / ":"), + "CONCURRENT" >> pure(OmpOrderClause::Type::Concurrent))) + TYPE_PARSER( construct(designator) || construct("/" >> name / "/")) @@ -258,6 +268,8 @@ parenthesized(scalarIntExpr))) || "NUM_THREADS" >> construct(construct( parenthesized(scalarIntExpr))) || + "ORDER" >> construct(construct( + parenthesized(Parser{}))) || "ORDERED" >> construct(construct( maybe(parenthesized(scalarIntConstantExpr)))) || "PARTIAL" >> construct(construct( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2046,6 +2046,10 @@ Put(":"); Walk(std::get(x.t)); } + void Unparse(const OmpOrderClause &x) { + Walk(std::get>(x.t), ":"); + Walk(std::get(x.t)); + } void Unparse(const OmpDependSinkVecLength &x) { Walk(std::get(x.t)); Walk(std::get(x.t)); @@ -2619,6 +2623,8 @@ WALK_NESTED_ENUM(OmpDeviceTypeClause, Type) // OMP DEVICE_TYPE WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type + WALK_NESTED_ENUM(OmpOrderClause, Type) // OMP order-type + WALK_NESTED_ENUM(OmpOrderModifier, Kind) // OMP order-modifier #undef WALK_NESTED_ENUM void Done() const { CHECK(indent_ == 0); } diff --git a/flang/test/Examples/omp-order-clause.f90 b/flang/test/Examples/omp-order-clause.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Examples/omp-order-clause.f90 @@ -0,0 +1,53 @@ +! REQUIRES: plugins, examples, shell + +! RUN: %flang_fc1 -load %llvmshlibdir/flangOmpReport.so -plugin flang-omp-report -fopenmp %s -o - | FileCheck %s + +! Check for ORDER([order-modifier :]concurrent) clause on OpenMP constructs + +subroutine test_order() + integer :: i, j = 1 + !$omp do order(concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end do +end subroutine + +!CHECK: - file: {{.*}} +!CHECK: line: 9 +!CHECK: construct: do +!CHECK: clauses: +!CHECK: - clause: order +!CHECK: details: concurrent + +subroutine test_order_reproducible() + integer :: i, j = 1 + !$omp simd order(reproducible:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end simd +end subroutine + +!CHECK: - file: {{.*}} +!CHECK: line: 25 +!CHECK: construct: simd +!CHECK: clauses: +!CHECK: - clause: order +!CHECK: details: 'reproducible:concurrent' + +subroutine test_order_unconstrained() + integer :: i, j = 1 + !$omp target teams distribute parallel do simd order(unconstrained:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end target teams distribute parallel do simd +end subroutine + +!CHECK: - file: {{.*}} +!CHECK: line: 41 +!CHECK: construct: target teams distribute parallel do simd +!CHECK: clauses: +!CHECK: - clause: order +!CHECK: details: 'unconstrained:concurrent' diff --git a/flang/test/Parser/omp-order-clause01.f90 b/flang/test/Parser/omp-order-clause01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Parser/omp-order-clause01.f90 @@ -0,0 +1,254 @@ +! RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case %s +! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s + +! Check for ORDER([order-modifier :]concurrent) clause on OpenMP constructs + +subroutine test_do_order() + integer :: i, j = 1 + !CHECK: !$omp do order(concurrent) + !$omp do order(concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end do +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = do +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_simd_order_reproducible() + integer :: i, j = 1 + !CHECK: !$omp simd order(reproducible:concurrent) + !$omp simd order(reproducible:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Reproducible +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_do_simd_order_unconstrained() + integer :: i, j = 1 + !CHECK: !$omp do simd order(unconstrained:concurrent) + !$omp do simd order(unconstrained:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end do simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = do simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Unconstrained +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_parallel_do_order() + integer :: i, j = 1 + !CHECK: !$omp parallel do order(concurrent) + !$omp parallel do order(concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end parallel do +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = parallel do +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_parallel_do_simd_order_reproducible() + integer :: i, j = 1 + !CHECK: !$omp parallel do simd order(reproducible:concurrent) + !$omp parallel do simd order(reproducible:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end parallel do simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = parallel do simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Reproducible +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_target_simd_order_unconstrained() + integer :: i, j = 1 + !CHECK: !$omp target simd order(unconstrained:concurrent) + !$omp target simd order(unconstrained:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end target simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = target simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Unconstrained +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_target_parallel_do_order() + integer :: i, j = 1 + !CHECK: !$omp target parallel do order(concurrent) + !$omp target parallel do order(concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end target parallel do +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = target parallel do +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_target_parallel_do_simd_order_reproducible() + integer :: i, j = 1 + !CHECK: !$omp target parallel do simd order(reproducible:concurrent) + !$omp target parallel do simd order(reproducible:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end target parallel do simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = target parallel do simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Reproducible +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_teams_distribute_simd_order_unconstrained() + integer :: i, j = 1 + !CHECK: !$omp teams distribute simd order(unconstrained:concurrent) + !$omp teams distribute simd order(unconstrained:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end teams distribute simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = teams distribute simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Unconstrained +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_teams_distribute_parallel_do_order() + integer :: i, j = 1 + !CHECK: !$omp teams distribute parallel do order(concurrent) + !$omp teams distribute parallel do order(concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end teams distribute parallel do +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = teams distribute parallel do +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_teams_distribute_parallel_do_simd_order_reproducible() + integer :: i, j = 1 + !CHECK: !$omp teams distribute parallel do simd order(reproducible:concurrent) + !$omp teams distribute parallel do simd order(reproducible:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end teams distribute parallel do simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = teams distribute parallel do simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Reproducible +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_target_teams_distribute_simd_order_unconstrained() + integer :: i, j = 1 + !CHECK: !$omp target teams distribute simd order(unconstrained:concurrent) + !$omp target teams distribute simd order(unconstrained:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end target teams distribute simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = target teams distribute simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Unconstrained +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_target_teams_distribute_parallel_do_order() + integer :: i, j = 1 + !CHECK: !$omp target teams distribute parallel do order(concurrent) + !$omp target teams distribute parallel do order(concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end target teams distribute parallel do +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = target teams distribute parallel do +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_target_teams_distribute_parallel_do_simd_order_reproducible() + integer :: i, j = 1 + !CHECK: !$omp target teams distribute parallel do simd order(reproducible:concurrent) + !$omp target teams distribute parallel do simd order(reproducible:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end target teams distribute parallel do simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = target teams distribute parallel do simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Reproducible +!PARSE-TREE-NEXT: Type = Concurrent + +subroutine test_taskloop_simd_order_unconstrained() + integer :: i, j = 1 + !CHECK: !$omp taskloop simd order(unconstrained:concurrent) + !$omp taskloop simd order(unconstrained:concurrent) + do i=1,10 + j = j + 1 + end do + !$omp end taskloop simd +end subroutine + +!PARSE-TREE: OpenMPConstruct -> OpenMPLoopConstruct +!PARSE-TREE-NEXT: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = taskloop simd +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Order -> OmpOrderClause +!PARSE-TREE-NEXT: Kind = Unconstrained +!PARSE-TREE-NEXT: Type = Concurrent diff --git a/flang/test/Semantics/OpenMP/omp-order-clause01.f90 b/flang/test/Semantics/OpenMP/omp-order-clause01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/omp-order-clause01.f90 @@ -0,0 +1,10 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp + +subroutine omp_order() + integer :: i, j = 1 + !ERROR: At most one ORDER clause can appear on the SIMD directive + !$omp simd order(concurrent) order(concurrent) + do i=1,10 + j = j + 1 + end do +end subroutine omp_order diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -355,6 +355,7 @@ def OMP_ORDER_unknown : ClauseVal<"unknown",2,0> { let isDefault = 1; } def OMPC_Order : Clause<"order"> { let clangClass = "OMPOrderClause"; + let flangClass = "OmpOrderClause"; let enumClauseValue = "OrderKind"; let allowedClauseValues = [ OMP_ORDER_unknown, @@ -493,13 +494,13 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause ]; let allowedOnceClauses = [ VersionedClause, VersionedClause, VersionedClause, VersionedClause, + VersionedClause ]; } def OMP_Tile : Directive<"tile"> { @@ -540,7 +541,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_Sections : Directive<"sections"> { @@ -791,7 +793,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause, VersionedClause @@ -805,7 +806,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_TargetUpdate : Directive<"target update"> { @@ -857,7 +859,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_ParallelForSimd : Directive<"parallel for simd"> { @@ -897,7 +900,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause ]; let allowedOnceClauses = [ VersionedClause, @@ -907,7 +909,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_ParallelMaster : Directive<"parallel master"> { @@ -973,7 +976,7 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, + VersionedClause ]; } def OMP_DoSimd : Directive<"do simd"> { @@ -991,7 +994,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_CancellationPoint : Directive<"cancellation point"> {} @@ -1052,7 +1056,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause, VersionedClause, @@ -1064,7 +1067,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; let allowedExclusiveClauses = [ VersionedClause, @@ -1127,7 +1131,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause, VersionedClause, @@ -1141,7 +1144,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_DistributeParallelForSimd : Directive<"distribute parallel for simd"> { @@ -1189,7 +1193,7 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause ]; } def OMP_DistributeSimd : Directive<"distribute simd"> { @@ -1202,7 +1206,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause ]; @@ -1215,7 +1218,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } @@ -1280,7 +1284,7 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, + VersionedClause, VersionedClause ]; } @@ -1297,7 +1301,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause, VersionedClause, @@ -1314,6 +1317,7 @@ VersionedClause, VersionedClause, VersionedClause, + VersionedClause ]; } def OMP_TeamsDistribute : Directive<"teams distribute"> { @@ -1339,7 +1343,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause, VersionedClause @@ -1352,7 +1355,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } @@ -1392,7 +1396,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause ]; @@ -1408,6 +1411,7 @@ VersionedClause, VersionedClause, VersionedClause, + VersionedClause ]; } def OMP_TeamsDistributeParallelFor : @@ -1451,11 +1455,11 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_TargetTeams : Directive<"target teams"> { @@ -1561,7 +1565,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause ]; let allowedOnceClauses = [ VersionedClause, @@ -1575,6 +1578,7 @@ VersionedClause, VersionedClause, VersionedClause, + VersionedClause ]; } def OMP_TargetTeamsDistributeParallelForSimd : @@ -1631,7 +1635,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause ]; @@ -1649,7 +1652,8 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_TargetTeamsDistributeSimd : @@ -1666,7 +1670,6 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause, VersionedClause, @@ -1683,6 +1686,7 @@ VersionedClause, VersionedClause, VersionedClause, + VersionedClause ]; } def OMP_Allocate : Directive<"allocate"> { @@ -2001,7 +2005,7 @@ let allowedOnceClauses = [ VersionedClause, VersionedClause, - VersionedClause, + VersionedClause ]; } def OMP_teams_loop : Directive<"teams loop"> {