@@ -974,6 +974,42 @@ void OmpStructureChecker::CheckDistLinear(
974
974
}
975
975
976
976
void OmpStructureChecker::Leave (const parser::OpenMPLoopConstruct &x) {
977
+ const auto &beginLoopDir = std::get<parser::OmpBeginLoopDirective>(x.t );
978
+ const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t )};
979
+ for (const auto &clause : clauseList.v ) {
980
+ if (const auto *reductionClause{
981
+ std::get_if<parser::OmpClause::Reduction>(&clause.u )}) {
982
+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
983
+ const auto &maybeModifier{
984
+ std::get<std::optional<ReductionModifier>>(reductionClause->v .t )};
985
+ if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
986
+
987
+ const auto &objectList{
988
+ std::get<parser::OmpObjectList>(reductionClause->v .t )};
989
+ for (const auto &ompObj : objectList.v ) {
990
+ common::visit (
991
+ common::visitors{
992
+ [&](const parser::Designator &designator) {
993
+ if (const auto *name{semantics::getDesignatorNameIfDataRef (
994
+ designator)}) {
995
+ std::string nameStr = name->symbol ->name ().ToString ();
996
+ if (GetContext ().usedInScanDirective .find (nameStr) ==
997
+ GetContext ().usedInScanDirective .end ()) {
998
+ context_.Say (name->source ,
999
+ " List item %s must appear in 'inclusive' or "
1000
+ " 'exclusive' clause of an "
1001
+ " enclosed scan directive" _err_en_US,
1002
+ nameStr);
1003
+ }
1004
+ }
1005
+ },
1006
+ [&](const auto &name) {},
1007
+ },
1008
+ ompObj.u );
1009
+ }
1010
+ }
1011
+ }
1012
+ }
977
1013
if (llvm::omp::allSimdSet.test (GetContext ().directive )) {
978
1014
ExitDirectiveNest (SIMDNest);
979
1015
}
@@ -1646,19 +1682,32 @@ void OmpStructureChecker::Leave(const parser::OpenMPAllocatorsConstruct &x) {
1646
1682
dirContext_.pop_back ();
1647
1683
}
1648
1684
1685
+ void OmpStructureChecker::CheckScan (
1686
+ const parser::OpenMPSimpleStandaloneConstruct &x) {
1687
+ if (std::get<parser::OmpClauseList>(x.t ).v .size () != 1 ) {
1688
+ context_.Say (x.source ,
1689
+ " Exactly one of `exclusive` or `inclusive` clause is expected" _err_en_US);
1690
+ }
1691
+ if (!CurrentDirectiveIsNested () ||
1692
+ !llvm::omp::scanParentAllowedSet.test (GetContextParent ().directive )) {
1693
+ context_.Say (x.source ,
1694
+ " Orphaned `omp scan` directives are prohibited; perhaps you forgot "
1695
+ " to enclose the directive in to a worksharing loop, a worksharing "
1696
+ " loop simd or a simd directive." _err_en_US);
1697
+ }
1698
+ }
1699
+
1649
1700
void OmpStructureChecker::CheckBarrierNesting (
1650
1701
const parser::OpenMPSimpleStandaloneConstruct &x) {
1651
1702
// A barrier region may not be `closely nested` inside a worksharing, loop,
1652
1703
// task, taskloop, critical, ordered, atomic, or master region.
1653
1704
// TODO: Expand the check to include `LOOP` construct as well when it is
1654
1705
// supported.
1655
- if (GetContext ().directive == llvm::omp::Directive::OMPD_barrier) {
1656
- if (IsCloselyNestedRegion (llvm::omp::nestedBarrierErrSet)) {
1657
- context_.Say (parser::FindSourceLocation (x),
1658
- " `BARRIER` region may not be closely nested inside of `WORKSHARING`, "
1659
- " `LOOP`, `TASK`, `TASKLOOP`,"
1660
- " `CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region." _err_en_US);
1661
- }
1706
+ if (IsCloselyNestedRegion (llvm::omp::nestedBarrierErrSet)) {
1707
+ context_.Say (parser::FindSourceLocation (x),
1708
+ " `BARRIER` region may not be closely nested inside of `WORKSHARING`, "
1709
+ " `LOOP`, `TASK`, `TASKLOOP`,"
1710
+ " `CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region." _err_en_US);
1662
1711
}
1663
1712
}
1664
1713
@@ -1842,7 +1891,16 @@ void OmpStructureChecker::Enter(
1842
1891
const parser::OpenMPSimpleStandaloneConstruct &x) {
1843
1892
const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t )};
1844
1893
PushContextAndClauseSets (dir.source , dir.v );
1845
- CheckBarrierNesting (x);
1894
+ switch (dir.v ) {
1895
+ case llvm::omp::Directive::OMPD_barrier:
1896
+ CheckBarrierNesting (x);
1897
+ break ;
1898
+ case llvm::omp::Directive::OMPD_scan:
1899
+ CheckScan (x);
1900
+ break ;
1901
+ default :
1902
+ break ;
1903
+ }
1846
1904
}
1847
1905
1848
1906
void OmpStructureChecker::Leave (
@@ -2674,15 +2732,13 @@ CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
2674
2732
CHECK_SIMPLE_CLAUSE (Detach, OMPC_detach)
2675
2733
CHECK_SIMPLE_CLAUSE (DeviceType, OMPC_device_type)
2676
2734
CHECK_SIMPLE_CLAUSE (DistSchedule, OMPC_dist_schedule)
2677
- CHECK_SIMPLE_CLAUSE (Exclusive, OMPC_exclusive)
2678
2735
CHECK_SIMPLE_CLAUSE (Final, OMPC_final)
2679
2736
CHECK_SIMPLE_CLAUSE (Flush, OMPC_flush)
2680
2737
CHECK_SIMPLE_CLAUSE (Full, OMPC_full)
2681
2738
CHECK_SIMPLE_CLAUSE (Grainsize, OMPC_grainsize)
2682
2739
CHECK_SIMPLE_CLAUSE (Hint, OMPC_hint)
2683
2740
CHECK_SIMPLE_CLAUSE (Holds, OMPC_holds)
2684
2741
CHECK_SIMPLE_CLAUSE (InReduction, OMPC_in_reduction)
2685
- CHECK_SIMPLE_CLAUSE (Inclusive, OMPC_inclusive)
2686
2742
CHECK_SIMPLE_CLAUSE (Match, OMPC_match)
2687
2743
CHECK_SIMPLE_CLAUSE (Nontemporal, OMPC_nontemporal)
2688
2744
CHECK_SIMPLE_CLAUSE (NumTasks, OMPC_num_tasks)
@@ -2775,7 +2831,24 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
2775
2831
if (CheckReductionOperators (x)) {
2776
2832
CheckReductionTypeList (x);
2777
2833
}
2778
- CheckReductionModifier (x);
2834
+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
2835
+ if (const auto &maybeModifier{
2836
+ std::get<std::optional<ReductionModifier>>(x.v .t )}) {
2837
+ ReductionModifier modifier{*maybeModifier};
2838
+ const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v .t )};
2839
+ addModifiertoMap (ompObjectList, modifier);
2840
+ CheckReductionModifier (modifier);
2841
+ }
2842
+ }
2843
+
2844
+ void OmpStructureChecker::Enter (const parser::OmpClause::Inclusive &x) {
2845
+ CheckAllowed (llvm::omp::Clause::OMPC_inclusive);
2846
+ checkAndAddSymbolsToUsedInScanList (x.v );
2847
+ }
2848
+
2849
+ void OmpStructureChecker::Enter (const parser::OmpClause::Exclusive &x) {
2850
+ CheckAllowed (llvm::omp::Clause::OMPC_exclusive);
2851
+ checkAndAddSymbolsToUsedInScanList (x.v );
2779
2852
}
2780
2853
2781
2854
bool OmpStructureChecker::CheckReductionOperators (
@@ -2818,6 +2891,49 @@ bool OmpStructureChecker::CheckReductionOperators(
2818
2891
2819
2892
return ok;
2820
2893
}
2894
+
2895
+ void OmpStructureChecker::addModifiertoMap (const parser::OmpObjectList &x,
2896
+ parser::OmpReductionClause::ReductionModifier &modifier) {
2897
+ for (const auto &ompObject : x.v ) {
2898
+ if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
2899
+ if (const auto *symbol{name->symbol }) {
2900
+ GetContext ().reductionMod [symbol->name ().ToString ()] = modifier;
2901
+ }
2902
+ }
2903
+ }
2904
+ }
2905
+
2906
+ void OmpStructureChecker::checkAndAddSymbolsToUsedInScanList (
2907
+ const parser::OmpObjectList &x) {
2908
+ for (const auto &ompObj : x.v ) {
2909
+ common::visit (
2910
+ common::visitors{
2911
+ [&](const parser::Designator &designator) {
2912
+ if (const auto *name{
2913
+ semantics::getDesignatorNameIfDataRef (designator)}) {
2914
+ if (name->symbol ) {
2915
+ if (CurrentDirectiveIsNested ()) {
2916
+ std::string nameStr = name->symbol ->name ().ToString ();
2917
+ if (GetContextParent ().reductionMod .find (nameStr) ==
2918
+ GetContextParent ().reductionMod .end ()) {
2919
+
2920
+ context_.Say (name->source ,
2921
+ " List item %s must appear in 'reduction' clause "
2922
+ " with the 'inscan' modifier of the parent "
2923
+ " directive" _err_en_US,
2924
+ nameStr);
2925
+ }
2926
+ GetContextParent ().usedInScanDirective .insert (nameStr);
2927
+ }
2928
+ }
2929
+ }
2930
+ },
2931
+ [&](const auto &name) {},
2932
+ },
2933
+ ompObj.u );
2934
+ }
2935
+ }
2936
+
2821
2937
bool OmpStructureChecker::CheckIntrinsicOperator (
2822
2938
const parser::DefinedOperator::IntrinsicOperator &op) {
2823
2939
@@ -2952,14 +3068,12 @@ void OmpStructureChecker::CheckReductionTypeList(
2952
3068
}
2953
3069
2954
3070
void OmpStructureChecker::CheckReductionModifier (
2955
- const parser::OmpClause::Reduction &x ) {
3071
+ const parser::OmpReductionClause::ReductionModifier &modifier ) {
2956
3072
using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
2957
- const auto &maybeModifier{std::get<std::optional<ReductionModifier>>(x.v .t )};
2958
- if (!maybeModifier || *maybeModifier == ReductionModifier::Default) {
2959
- // No modifier, or the default one is always ok.
3073
+ if (modifier == ReductionModifier::Default) {
3074
+ // the default one is always ok.
2960
3075
return ;
2961
3076
}
2962
- ReductionModifier modifier{*maybeModifier};
2963
3077
const DirectiveContext &dirCtx{GetContext ()};
2964
3078
if (dirCtx.directive == llvm::omp::Directive::OMPD_loop) {
2965
3079
// [5.2:257:33-34]
0 commit comments