@@ -2722,58 +2722,129 @@ static mlir::IntegerAttr getAtomicHint(lower::AbstractConverter &converter,
2722
2722
return nullptr ;
2723
2723
}
2724
2724
2725
- static mlir::omp::ClauseMemoryOrderKindAttr
2726
- getAtomicMemoryOrder (lower::AbstractConverter &converter,
2727
- semantics::SemanticsContext &semaCtx,
2728
- const List<Clause> &clauses) {
2729
- std::optional<mlir::omp::ClauseMemoryOrderKind> kind;
2725
+ static mlir::omp::ClauseMemoryOrderKind
2726
+ getMemoryOrderKind (common::OmpMemoryOrderType kind) {
2727
+ switch (kind) {
2728
+ case common::OmpMemoryOrderType::Acq_Rel:
2729
+ return mlir::omp::ClauseMemoryOrderKind::Acq_rel;
2730
+ case common::OmpMemoryOrderType::Acquire:
2731
+ return mlir::omp::ClauseMemoryOrderKind::Acquire;
2732
+ case common::OmpMemoryOrderType::Relaxed:
2733
+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
2734
+ case common::OmpMemoryOrderType::Release:
2735
+ return mlir::omp::ClauseMemoryOrderKind::Release;
2736
+ case common::OmpMemoryOrderType::Seq_Cst:
2737
+ return mlir::omp::ClauseMemoryOrderKind::Seq_cst;
2738
+ }
2739
+ llvm_unreachable (" Unexpected kind" );
2740
+ }
2741
+
2742
+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2743
+ getMemoryOrderKind (llvm::omp::Clause clauseId) {
2744
+ switch (clauseId) {
2745
+ case llvm::omp::Clause::OMPC_acq_rel:
2746
+ return mlir::omp::ClauseMemoryOrderKind::Acq_rel;
2747
+ case llvm::omp::Clause::OMPC_acquire:
2748
+ return mlir::omp::ClauseMemoryOrderKind::Acquire;
2749
+ case llvm::omp::Clause::OMPC_relaxed:
2750
+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
2751
+ case llvm::omp::Clause::OMPC_release:
2752
+ return mlir::omp::ClauseMemoryOrderKind::Release;
2753
+ case llvm::omp::Clause::OMPC_seq_cst:
2754
+ return mlir::omp::ClauseMemoryOrderKind::Seq_cst;
2755
+ default :
2756
+ return std::nullopt;
2757
+ }
2758
+ }
2759
+
2760
+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2761
+ getMemoryOrderFromRequires (const semantics::Scope &scope) {
2762
+ // The REQUIRES construct is only allowed in the main program scope
2763
+ // and module scope, but seems like we also accept it in a subprogram
2764
+ // scope.
2765
+ // For safety, traverse all enclosing scopes and check if their symbol
2766
+ // contains REQUIRES.
2767
+ for (const auto *sc{&scope}; sc->kind () != semantics::Scope::Kind::Global;
2768
+ sc = &sc->parent ()) {
2769
+ const semantics::Symbol *sym = sc->symbol ();
2770
+ if (!sym)
2771
+ continue ;
2772
+
2773
+ const common::OmpMemoryOrderType *admo = common::visit (
2774
+ [](auto &&s) {
2775
+ using WithOmpDeclarative = semantics::WithOmpDeclarative;
2776
+ if constexpr (std::is_convertible_v<decltype (s),
2777
+ const WithOmpDeclarative &>) {
2778
+ return s.ompAtomicDefaultMemOrder ();
2779
+ }
2780
+ return static_cast <const common::OmpMemoryOrderType *>(nullptr );
2781
+ },
2782
+ sym->details ());
2783
+ if (admo)
2784
+ return getMemoryOrderKind (*admo);
2785
+ }
2786
+
2787
+ return std::nullopt;
2788
+ }
2789
+
2790
+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2791
+ getDefaultAtomicMemOrder (semantics::SemanticsContext &semaCtx) {
2730
2792
unsigned version = semaCtx.langOptions ().OpenMPVersion ;
2793
+ if (version > 50 )
2794
+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
2795
+ return std::nullopt;
2796
+ }
2731
2797
2798
+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2799
+ getAtomicMemoryOrder (semantics::SemanticsContext &semaCtx,
2800
+ const List<Clause> &clauses,
2801
+ const semantics::Scope &scope) {
2732
2802
for (const Clause &clause : clauses) {
2733
- switch (clause.id ) {
2734
- case llvm::omp::Clause::OMPC_acq_rel:
2735
- kind = mlir::omp::ClauseMemoryOrderKind::Acq_rel;
2736
- break ;
2737
- case llvm::omp::Clause::OMPC_acquire:
2738
- kind = mlir::omp::ClauseMemoryOrderKind::Acquire;
2739
- break ;
2740
- case llvm::omp::Clause::OMPC_relaxed:
2741
- kind = mlir::omp::ClauseMemoryOrderKind::Relaxed;
2742
- break ;
2743
- case llvm::omp::Clause::OMPC_release:
2744
- kind = mlir::omp::ClauseMemoryOrderKind::Release;
2745
- break ;
2746
- case llvm::omp::Clause::OMPC_seq_cst:
2747
- kind = mlir::omp::ClauseMemoryOrderKind::Seq_cst;
2748
- break ;
2749
- default :
2750
- break ;
2751
- }
2803
+ if (auto maybeKind = getMemoryOrderKind (clause.id ))
2804
+ return *maybeKind;
2752
2805
}
2753
2806
2754
- // Starting with 5.1, if no memory-order clause is present, the effect
2755
- // is as if "relaxed" was present.
2756
- if (!kind) {
2757
- if (version <= 50 )
2758
- return nullptr ;
2759
- kind = mlir::omp::ClauseMemoryOrderKind::Relaxed;
2807
+ if (auto maybeKind = getMemoryOrderFromRequires (scope))
2808
+ return *maybeKind;
2809
+
2810
+ return getDefaultAtomicMemOrder (semaCtx);
2811
+ }
2812
+
2813
+ static mlir::omp::ClauseMemoryOrderKindAttr
2814
+ makeMemOrderAttr (lower::AbstractConverter &converter,
2815
+ std::optional<mlir::omp::ClauseMemoryOrderKind> maybeKind) {
2816
+ if (maybeKind) {
2817
+ return mlir::omp::ClauseMemoryOrderKindAttr::get (
2818
+ converter.getFirOpBuilder ().getContext (), *maybeKind);
2760
2819
}
2761
- fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
2762
- return mlir::omp::ClauseMemoryOrderKindAttr::get (builder.getContext (), *kind);
2820
+ return nullptr ;
2763
2821
}
2764
2822
2765
2823
static mlir::Operation * //
2766
- genAtomicRead (lower::AbstractConverter &converter, mlir::Location loc,
2824
+ genAtomicRead (lower::AbstractConverter &converter,
2825
+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
2767
2826
lower::StatementContext &stmtCtx, mlir::Value atomAddr,
2768
2827
const semantics::SomeExpr &atom,
2769
2828
const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2770
- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2829
+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
2771
2830
fir::FirOpBuilder::InsertPoint preAt,
2772
2831
fir::FirOpBuilder::InsertPoint atomicAt,
2773
2832
fir::FirOpBuilder::InsertPoint postAt) {
2774
2833
fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
2775
2834
builder.restoreInsertionPoint (preAt);
2776
2835
2836
+ // If the atomic clause is read then the memory-order clause must
2837
+ // not be release.
2838
+ if (memOrder) {
2839
+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Release) {
2840
+ // Reset it back to the default.
2841
+ memOrder = getDefaultAtomicMemOrder (semaCtx);
2842
+ } else if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) {
2843
+ // The MLIR verifier doesn't like acq_rel either.
2844
+ memOrder = mlir::omp::ClauseMemoryOrderKind::Acquire;
2845
+ }
2846
+ }
2847
+
2777
2848
mlir::Value storeAddr =
2778
2849
fir::getBase (converter.genExprAddr (assign.lhs , stmtCtx, &loc));
2779
2850
mlir::Type atomType = fir::unwrapRefType (atomAddr.getType ());
@@ -2787,7 +2858,8 @@ genAtomicRead(lower::AbstractConverter &converter, mlir::Location loc,
2787
2858
2788
2859
builder.restoreInsertionPoint (atomicAt);
2789
2860
mlir::Operation *op = builder.create <mlir::omp::AtomicReadOp>(
2790
- loc, atomAddr, toAddr, mlir::TypeAttr::get (atomType), hint, memOrder);
2861
+ loc, atomAddr, toAddr, mlir::TypeAttr::get (atomType), hint,
2862
+ makeMemOrderAttr (converter, memOrder));
2791
2863
2792
2864
if (atomType != storeType) {
2793
2865
lower::ExprToValueMap overrides;
@@ -2808,34 +2880,48 @@ genAtomicRead(lower::AbstractConverter &converter, mlir::Location loc,
2808
2880
}
2809
2881
2810
2882
static mlir::Operation * //
2811
- genAtomicWrite (lower::AbstractConverter &converter, mlir::Location loc,
2883
+ genAtomicWrite (lower::AbstractConverter &converter,
2884
+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
2812
2885
lower::StatementContext &stmtCtx, mlir::Value atomAddr,
2813
2886
const semantics::SomeExpr &atom,
2814
2887
const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2815
- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2888
+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
2816
2889
fir::FirOpBuilder::InsertPoint preAt,
2817
2890
fir::FirOpBuilder::InsertPoint atomicAt,
2818
2891
fir::FirOpBuilder::InsertPoint postAt) {
2819
2892
fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
2820
2893
builder.restoreInsertionPoint (preAt);
2821
2894
2895
+ // If the atomic clause is write then the memory-order clause must
2896
+ // not be acquire.
2897
+ if (memOrder) {
2898
+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire) {
2899
+ // Reset it back to the default.
2900
+ memOrder = getDefaultAtomicMemOrder (semaCtx);
2901
+ } else if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) {
2902
+ // The MLIR verifier doesn't like acq_rel either.
2903
+ memOrder = mlir::omp::ClauseMemoryOrderKind::Release;
2904
+ }
2905
+ }
2906
+
2822
2907
mlir::Value value =
2823
2908
fir::getBase (converter.genExprValue (assign.rhs , stmtCtx, &loc));
2824
2909
mlir::Type atomType = fir::unwrapRefType (atomAddr.getType ());
2825
2910
mlir::Value converted = builder.createConvert (loc, atomType, value);
2826
2911
2827
2912
builder.restoreInsertionPoint (atomicAt);
2828
2913
mlir::Operation *op = builder.create <mlir::omp::AtomicWriteOp>(
2829
- loc, atomAddr, converted, hint, memOrder);
2914
+ loc, atomAddr, converted, hint, makeMemOrderAttr (converter, memOrder) );
2830
2915
return op;
2831
2916
}
2832
2917
2833
2918
static mlir::Operation *
2834
- genAtomicUpdate (lower::AbstractConverter &converter, mlir::Location loc,
2919
+ genAtomicUpdate (lower::AbstractConverter &converter,
2920
+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
2835
2921
lower::StatementContext &stmtCtx, mlir::Value atomAddr,
2836
2922
const semantics::SomeExpr &atom,
2837
2923
const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2838
- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2924
+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
2839
2925
fir::FirOpBuilder::InsertPoint preAt,
2840
2926
fir::FirOpBuilder::InsertPoint atomicAt,
2841
2927
fir::FirOpBuilder::InsertPoint postAt) {
@@ -2858,8 +2944,8 @@ genAtomicUpdate(lower::AbstractConverter &converter, mlir::Location loc,
2858
2944
}
2859
2945
2860
2946
builder.restoreInsertionPoint (atomicAt);
2861
- auto updateOp =
2862
- builder. create <mlir::omp::AtomicUpdateOp>( loc, atomAddr, hint, memOrder);
2947
+ auto updateOp = builder. create <mlir::omp::AtomicUpdateOp>(
2948
+ loc, atomAddr, hint, makeMemOrderAttr (converter, memOrder) );
2863
2949
2864
2950
mlir::Region ®ion = updateOp->getRegion (0 );
2865
2951
mlir::Block *block = builder.createBlock (®ion, {}, {atomType}, {loc});
@@ -2878,11 +2964,12 @@ genAtomicUpdate(lower::AbstractConverter &converter, mlir::Location loc,
2878
2964
}
2879
2965
2880
2966
static mlir::Operation *
2881
- genAtomicOperation (lower::AbstractConverter &converter, mlir::Location loc,
2967
+ genAtomicOperation (lower::AbstractConverter &converter,
2968
+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
2882
2969
lower::StatementContext &stmtCtx, int action,
2883
2970
mlir::Value atomAddr, const semantics::SomeExpr &atom,
2884
2971
const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2885
- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2972
+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
2886
2973
fir::FirOpBuilder::InsertPoint preAt,
2887
2974
fir::FirOpBuilder::InsertPoint atomicAt,
2888
2975
fir::FirOpBuilder::InsertPoint postAt) {
@@ -2894,14 +2981,14 @@ genAtomicOperation(lower::AbstractConverter &converter, mlir::Location loc,
2894
2981
// builder's insertion point, or set it to anything specific.
2895
2982
switch (action) {
2896
2983
case parser::OpenMPAtomicConstruct::Analysis::Read:
2897
- return genAtomicRead (converter, loc, stmtCtx, atomAddr, atom, assign, hint ,
2898
- memOrder, preAt, atomicAt, postAt);
2984
+ return genAtomicRead (converter, semaCtx, loc, stmtCtx, atomAddr, atom,
2985
+ assign, hint, memOrder, preAt, atomicAt, postAt);
2899
2986
case parser::OpenMPAtomicConstruct::Analysis::Write:
2900
- return genAtomicWrite (converter, loc, stmtCtx, atomAddr, atom, assign, hint ,
2901
- memOrder, preAt, atomicAt, postAt);
2987
+ return genAtomicWrite (converter, semaCtx, loc, stmtCtx, atomAddr, atom,
2988
+ assign, hint, memOrder, preAt, atomicAt, postAt);
2902
2989
case parser::OpenMPAtomicConstruct::Analysis::Update:
2903
- return genAtomicUpdate (converter, loc, stmtCtx, atomAddr, atom, assign ,
2904
- hint, memOrder, preAt, atomicAt, postAt);
2990
+ return genAtomicUpdate (converter, semaCtx, loc, stmtCtx, atomAddr, atom,
2991
+ assign, hint, memOrder, preAt, atomicAt, postAt);
2905
2992
default :
2906
2993
return nullptr ;
2907
2994
}
@@ -3899,8 +3986,9 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
3899
3986
mlir::Value atomAddr =
3900
3987
fir::getBase (converter.genExprAddr (atom, stmtCtx, &loc));
3901
3988
mlir::IntegerAttr hint = getAtomicHint (converter, clauses);
3902
- mlir::omp::ClauseMemoryOrderKindAttr memOrder =
3903
- getAtomicMemoryOrder (converter, semaCtx, clauses);
3989
+ std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder =
3990
+ getAtomicMemoryOrder (semaCtx, clauses,
3991
+ semaCtx.FindScope (construct.source ));
3904
3992
3905
3993
if (auto *cond = get (analysis.cond )) {
3906
3994
(void )cond;
@@ -3918,8 +4006,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
3918
4006
" Expexcing two actions" );
3919
4007
(void )action0;
3920
4008
(void )action1;
3921
- captureOp =
3922
- builder. create <mlir::omp::AtomicCaptureOp>( loc, hint, memOrder);
4009
+ captureOp = builder. create <mlir::omp::AtomicCaptureOp>(
4010
+ loc, hint, makeMemOrderAttr (converter, memOrder) );
3923
4011
// Set the non-atomic insertion point to before the atomic.capture.
3924
4012
preAt = getInsertionPointBefore (captureOp);
3925
4013
@@ -3931,7 +4019,7 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
3931
4019
atomicAt = getInsertionPointBefore (term);
3932
4020
postAt = getInsertionPointAfter (captureOp);
3933
4021
hint = nullptr ;
3934
- memOrder = nullptr ;
4022
+ memOrder = std::nullopt ;
3935
4023
} else {
3936
4024
// Non-capturing operation.
3937
4025
assert (action0 != analysis.None && action1 == analysis.None &&
@@ -3943,16 +4031,16 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
3943
4031
// The builder's insertion point needs to be specifically set before
3944
4032
// each call to `genAtomicOperation`.
3945
4033
mlir::Operation *firstOp = genAtomicOperation (
3946
- converter, loc, stmtCtx, analysis.op0 .what , atomAddr, atom,
4034
+ converter, semaCtx, loc, stmtCtx, analysis.op0 .what , atomAddr, atom,
3947
4035
*get (analysis.op0 .assign ), hint, memOrder, preAt, atomicAt, postAt);
3948
4036
assert (firstOp && " Should have created an atomic operation" );
3949
4037
atomicAt = getInsertionPointAfter (firstOp);
3950
4038
3951
4039
mlir::Operation *secondOp = nullptr ;
3952
4040
if (analysis.op1 .what != analysis.None ) {
3953
- secondOp = genAtomicOperation (converter, loc, stmtCtx, analysis. op1 . what ,
3954
- atomAddr, atom, * get ( analysis.op1 .assign ) ,
3955
- hint, memOrder, preAt, atomicAt, postAt);
4041
+ secondOp = genAtomicOperation (
4042
+ converter, semaCtx, loc, stmtCtx, analysis.op1 .what , atomAddr, atom ,
4043
+ * get (analysis. op1 . assign ), hint, memOrder, preAt, atomicAt, postAt);
3956
4044
}
3957
4045
3958
4046
if (construct.IsCapture ()) {
0 commit comments