@@ -2722,58 +2722,129 @@ static mlir::IntegerAttr getAtomicHint(lower::AbstractConverter &converter,
27222722 return nullptr ;
27232723}
27242724
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) {
27302792 unsigned version = semaCtx.langOptions ().OpenMPVersion ;
2793+ if (version > 50 )
2794+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
2795+ return std::nullopt ;
2796+ }
27312797
2798+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2799+ getAtomicMemoryOrder (semantics::SemanticsContext &semaCtx,
2800+ const List<Clause> &clauses,
2801+ const semantics::Scope &scope) {
27322802 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;
27522805 }
27532806
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);
27602819 }
2761- fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
2762- return mlir::omp::ClauseMemoryOrderKindAttr::get (builder.getContext (), *kind);
2820+ return nullptr ;
27632821}
27642822
27652823static mlir::Operation * //
2766- genAtomicRead (lower::AbstractConverter &converter, mlir::Location loc,
2824+ genAtomicRead (lower::AbstractConverter &converter,
2825+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
27672826 lower::StatementContext &stmtCtx, mlir::Value atomAddr,
27682827 const semantics::SomeExpr &atom,
27692828 const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2770- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2829+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
27712830 fir::FirOpBuilder::InsertPoint preAt,
27722831 fir::FirOpBuilder::InsertPoint atomicAt,
27732832 fir::FirOpBuilder::InsertPoint postAt) {
27742833 fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
27752834 builder.restoreInsertionPoint (preAt);
27762835
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+
27772848 mlir::Value storeAddr =
27782849 fir::getBase (converter.genExprAddr (assign.lhs , stmtCtx, &loc));
27792850 mlir::Type atomType = fir::unwrapRefType (atomAddr.getType ());
@@ -2787,7 +2858,8 @@ genAtomicRead(lower::AbstractConverter &converter, mlir::Location loc,
27872858
27882859 builder.restoreInsertionPoint (atomicAt);
27892860 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));
27912863
27922864 if (atomType != storeType) {
27932865 lower::ExprToValueMap overrides;
@@ -2808,34 +2880,48 @@ genAtomicRead(lower::AbstractConverter &converter, mlir::Location loc,
28082880}
28092881
28102882static mlir::Operation * //
2811- genAtomicWrite (lower::AbstractConverter &converter, mlir::Location loc,
2883+ genAtomicWrite (lower::AbstractConverter &converter,
2884+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
28122885 lower::StatementContext &stmtCtx, mlir::Value atomAddr,
28132886 const semantics::SomeExpr &atom,
28142887 const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2815- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2888+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
28162889 fir::FirOpBuilder::InsertPoint preAt,
28172890 fir::FirOpBuilder::InsertPoint atomicAt,
28182891 fir::FirOpBuilder::InsertPoint postAt) {
28192892 fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
28202893 builder.restoreInsertionPoint (preAt);
28212894
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+
28222907 mlir::Value value =
28232908 fir::getBase (converter.genExprValue (assign.rhs , stmtCtx, &loc));
28242909 mlir::Type atomType = fir::unwrapRefType (atomAddr.getType ());
28252910 mlir::Value converted = builder.createConvert (loc, atomType, value);
28262911
28272912 builder.restoreInsertionPoint (atomicAt);
28282913 mlir::Operation *op = builder.create <mlir::omp::AtomicWriteOp>(
2829- loc, atomAddr, converted, hint, memOrder);
2914+ loc, atomAddr, converted, hint, makeMemOrderAttr (converter, memOrder) );
28302915 return op;
28312916}
28322917
28332918static mlir::Operation *
2834- genAtomicUpdate (lower::AbstractConverter &converter, mlir::Location loc,
2919+ genAtomicUpdate (lower::AbstractConverter &converter,
2920+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
28352921 lower::StatementContext &stmtCtx, mlir::Value atomAddr,
28362922 const semantics::SomeExpr &atom,
28372923 const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2838- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2924+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
28392925 fir::FirOpBuilder::InsertPoint preAt,
28402926 fir::FirOpBuilder::InsertPoint atomicAt,
28412927 fir::FirOpBuilder::InsertPoint postAt) {
@@ -2858,8 +2944,8 @@ genAtomicUpdate(lower::AbstractConverter &converter, mlir::Location loc,
28582944 }
28592945
28602946 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) );
28632949
28642950 mlir::Region ®ion = updateOp->getRegion (0 );
28652951 mlir::Block *block = builder.createBlock (®ion, {}, {atomType}, {loc});
@@ -2878,11 +2964,12 @@ genAtomicUpdate(lower::AbstractConverter &converter, mlir::Location loc,
28782964}
28792965
28802966static mlir::Operation *
2881- genAtomicOperation (lower::AbstractConverter &converter, mlir::Location loc,
2967+ genAtomicOperation (lower::AbstractConverter &converter,
2968+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
28822969 lower::StatementContext &stmtCtx, int action,
28832970 mlir::Value atomAddr, const semantics::SomeExpr &atom,
28842971 const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2885- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2972+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
28862973 fir::FirOpBuilder::InsertPoint preAt,
28872974 fir::FirOpBuilder::InsertPoint atomicAt,
28882975 fir::FirOpBuilder::InsertPoint postAt) {
@@ -2894,14 +2981,14 @@ genAtomicOperation(lower::AbstractConverter &converter, mlir::Location loc,
28942981 // builder's insertion point, or set it to anything specific.
28952982 switch (action) {
28962983 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);
28992986 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);
29022989 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);
29052992 default :
29062993 return nullptr ;
29072994 }
@@ -3899,8 +3986,9 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
38993986 mlir::Value atomAddr =
39003987 fir::getBase (converter.genExprAddr (atom, stmtCtx, &loc));
39013988 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 ));
39043992
39053993 if (auto *cond = get (analysis.cond )) {
39063994 (void )cond;
@@ -3918,8 +4006,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
39184006 " Expexcing two actions" );
39194007 (void )action0;
39204008 (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) );
39234011 // Set the non-atomic insertion point to before the atomic.capture.
39244012 preAt = getInsertionPointBefore (captureOp);
39254013
@@ -3931,7 +4019,7 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
39314019 atomicAt = getInsertionPointBefore (term);
39324020 postAt = getInsertionPointAfter (captureOp);
39334021 hint = nullptr ;
3934- memOrder = nullptr ;
4022+ memOrder = std:: nullopt ;
39354023 } else {
39364024 // Non-capturing operation.
39374025 assert (action0 != analysis.None && action1 == analysis.None &&
@@ -3943,16 +4031,16 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
39434031 // The builder's insertion point needs to be specifically set before
39444032 // each call to `genAtomicOperation`.
39454033 mlir::Operation *firstOp = genAtomicOperation (
3946- converter, loc, stmtCtx, analysis.op0 .what , atomAddr, atom,
4034+ converter, semaCtx, loc, stmtCtx, analysis.op0 .what , atomAddr, atom,
39474035 *get (analysis.op0 .assign ), hint, memOrder, preAt, atomicAt, postAt);
39484036 assert (firstOp && " Should have created an atomic operation" );
39494037 atomicAt = getInsertionPointAfter (firstOp);
39504038
39514039 mlir::Operation *secondOp = nullptr ;
39524040 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);
39564044 }
39574045
39584046 if (construct.IsCapture ()) {
0 commit comments