@@ -2715,58 +2715,129 @@ static mlir::IntegerAttr getAtomicHint(lower::AbstractConverter &converter,
27152715 return nullptr ;
27162716}
27172717
2718- static mlir::omp::ClauseMemoryOrderKindAttr
2719- getAtomicMemoryOrder (lower::AbstractConverter &converter,
2720- semantics::SemanticsContext &semaCtx,
2721- const List<Clause> &clauses) {
2722- std::optional<mlir::omp::ClauseMemoryOrderKind> kind;
2718+ static mlir::omp::ClauseMemoryOrderKind
2719+ getMemoryOrderKind (common::OmpMemoryOrderType kind) {
2720+ switch (kind) {
2721+ case common::OmpMemoryOrderType::Acq_Rel:
2722+ return mlir::omp::ClauseMemoryOrderKind::Acq_rel;
2723+ case common::OmpMemoryOrderType::Acquire:
2724+ return mlir::omp::ClauseMemoryOrderKind::Acquire;
2725+ case common::OmpMemoryOrderType::Relaxed:
2726+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
2727+ case common::OmpMemoryOrderType::Release:
2728+ return mlir::omp::ClauseMemoryOrderKind::Release;
2729+ case common::OmpMemoryOrderType::Seq_Cst:
2730+ return mlir::omp::ClauseMemoryOrderKind::Seq_cst;
2731+ }
2732+ llvm_unreachable (" Unexpected kind" );
2733+ }
2734+
2735+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2736+ getMemoryOrderKind (llvm::omp::Clause clauseId) {
2737+ switch (clauseId) {
2738+ case llvm::omp::Clause::OMPC_acq_rel:
2739+ return mlir::omp::ClauseMemoryOrderKind::Acq_rel;
2740+ case llvm::omp::Clause::OMPC_acquire:
2741+ return mlir::omp::ClauseMemoryOrderKind::Acquire;
2742+ case llvm::omp::Clause::OMPC_relaxed:
2743+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
2744+ case llvm::omp::Clause::OMPC_release:
2745+ return mlir::omp::ClauseMemoryOrderKind::Release;
2746+ case llvm::omp::Clause::OMPC_seq_cst:
2747+ return mlir::omp::ClauseMemoryOrderKind::Seq_cst;
2748+ default :
2749+ return std::nullopt ;
2750+ }
2751+ }
2752+
2753+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2754+ getMemoryOrderFromRequires (const semantics::Scope &scope) {
2755+ // The REQUIRES construct is only allowed in the main program scope
2756+ // and module scope, but seems like we also accept it in a subprogram
2757+ // scope.
2758+ // For safety, traverse all enclosing scopes and check if their symbol
2759+ // contains REQUIRES.
2760+ for (const auto *sc{&scope}; sc->kind () != semantics::Scope::Kind::Global;
2761+ sc = &sc->parent ()) {
2762+ const semantics::Symbol *sym = sc->symbol ();
2763+ if (!sym)
2764+ continue ;
2765+
2766+ const common::OmpMemoryOrderType *admo = common::visit (
2767+ [](auto &&s) {
2768+ using WithOmpDeclarative = semantics::WithOmpDeclarative;
2769+ if constexpr (std::is_convertible_v<decltype (s),
2770+ const WithOmpDeclarative &>) {
2771+ return s.ompAtomicDefaultMemOrder ();
2772+ }
2773+ return static_cast <const common::OmpMemoryOrderType *>(nullptr );
2774+ },
2775+ sym->details ());
2776+ if (admo)
2777+ return getMemoryOrderKind (*admo);
2778+ }
2779+
2780+ return std::nullopt ;
2781+ }
2782+
2783+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2784+ getDefaultAtomicMemOrder (semantics::SemanticsContext &semaCtx) {
27232785 unsigned version = semaCtx.langOptions ().OpenMPVersion ;
2786+ if (version > 50 )
2787+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
2788+ return std::nullopt ;
2789+ }
27242790
2791+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
2792+ getAtomicMemoryOrder (semantics::SemanticsContext &semaCtx,
2793+ const List<Clause> &clauses,
2794+ const semantics::Scope &scope) {
27252795 for (const Clause &clause : clauses) {
2726- switch (clause.id ) {
2727- case llvm::omp::Clause::OMPC_acq_rel:
2728- kind = mlir::omp::ClauseMemoryOrderKind::Acq_rel;
2729- break ;
2730- case llvm::omp::Clause::OMPC_acquire:
2731- kind = mlir::omp::ClauseMemoryOrderKind::Acquire;
2732- break ;
2733- case llvm::omp::Clause::OMPC_relaxed:
2734- kind = mlir::omp::ClauseMemoryOrderKind::Relaxed;
2735- break ;
2736- case llvm::omp::Clause::OMPC_release:
2737- kind = mlir::omp::ClauseMemoryOrderKind::Release;
2738- break ;
2739- case llvm::omp::Clause::OMPC_seq_cst:
2740- kind = mlir::omp::ClauseMemoryOrderKind::Seq_cst;
2741- break ;
2742- default :
2743- break ;
2744- }
2796+ if (auto maybeKind = getMemoryOrderKind (clause.id ))
2797+ return *maybeKind;
27452798 }
27462799
2747- // Starting with 5.1, if no memory-order clause is present, the effect
2748- // is as if "relaxed" was present.
2749- if (!kind) {
2750- if (version <= 50 )
2751- return nullptr ;
2752- kind = mlir::omp::ClauseMemoryOrderKind::Relaxed;
2800+ if (auto maybeKind = getMemoryOrderFromRequires (scope))
2801+ return *maybeKind;
2802+
2803+ return getDefaultAtomicMemOrder (semaCtx);
2804+ }
2805+
2806+ static mlir::omp::ClauseMemoryOrderKindAttr
2807+ makeMemOrderAttr (lower::AbstractConverter &converter,
2808+ std::optional<mlir::omp::ClauseMemoryOrderKind> maybeKind) {
2809+ if (maybeKind) {
2810+ return mlir::omp::ClauseMemoryOrderKindAttr::get (
2811+ converter.getFirOpBuilder ().getContext (), *maybeKind);
27532812 }
2754- fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
2755- return mlir::omp::ClauseMemoryOrderKindAttr::get (builder.getContext (), *kind);
2813+ return nullptr ;
27562814}
27572815
27582816static mlir::Operation * //
2759- genAtomicRead (lower::AbstractConverter &converter, mlir::Location loc,
2817+ genAtomicRead (lower::AbstractConverter &converter,
2818+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
27602819 lower::StatementContext &stmtCtx, mlir::Value atomAddr,
27612820 const semantics::SomeExpr &atom,
27622821 const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2763- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2822+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
27642823 fir::FirOpBuilder::InsertPoint preAt,
27652824 fir::FirOpBuilder::InsertPoint atomicAt,
27662825 fir::FirOpBuilder::InsertPoint postAt) {
27672826 fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
27682827 builder.restoreInsertionPoint (preAt);
27692828
2829+ // If the atomic clause is read then the memory-order clause must
2830+ // not be release.
2831+ if (memOrder) {
2832+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Release) {
2833+ // Reset it back to the default.
2834+ memOrder = getDefaultAtomicMemOrder (semaCtx);
2835+ } else if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) {
2836+ // The MLIR verifier doesn't like acq_rel either.
2837+ memOrder = mlir::omp::ClauseMemoryOrderKind::Acquire;
2838+ }
2839+ }
2840+
27702841 mlir::Value storeAddr =
27712842 fir::getBase (converter.genExprAddr (assign.lhs , stmtCtx, &loc));
27722843 mlir::Type atomType = fir::unwrapRefType (atomAddr.getType ());
@@ -2780,7 +2851,8 @@ genAtomicRead(lower::AbstractConverter &converter, mlir::Location loc,
27802851
27812852 builder.restoreInsertionPoint (atomicAt);
27822853 mlir::Operation *op = builder.create <mlir::omp::AtomicReadOp>(
2783- loc, atomAddr, toAddr, mlir::TypeAttr::get (atomType), hint, memOrder);
2854+ loc, atomAddr, toAddr, mlir::TypeAttr::get (atomType), hint,
2855+ makeMemOrderAttr (converter, memOrder));
27842856
27852857 if (atomType != storeType) {
27862858 lower::ExprToValueMap overrides;
@@ -2801,34 +2873,48 @@ genAtomicRead(lower::AbstractConverter &converter, mlir::Location loc,
28012873}
28022874
28032875static mlir::Operation * //
2804- genAtomicWrite (lower::AbstractConverter &converter, mlir::Location loc,
2876+ genAtomicWrite (lower::AbstractConverter &converter,
2877+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
28052878 lower::StatementContext &stmtCtx, mlir::Value atomAddr,
28062879 const semantics::SomeExpr &atom,
28072880 const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2808- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2881+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
28092882 fir::FirOpBuilder::InsertPoint preAt,
28102883 fir::FirOpBuilder::InsertPoint atomicAt,
28112884 fir::FirOpBuilder::InsertPoint postAt) {
28122885 fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
28132886 builder.restoreInsertionPoint (preAt);
28142887
2888+ // If the atomic clause is write then the memory-order clause must
2889+ // not be acquire.
2890+ if (memOrder) {
2891+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire) {
2892+ // Reset it back to the default.
2893+ memOrder = getDefaultAtomicMemOrder (semaCtx);
2894+ } else if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel) {
2895+ // The MLIR verifier doesn't like acq_rel either.
2896+ memOrder = mlir::omp::ClauseMemoryOrderKind::Release;
2897+ }
2898+ }
2899+
28152900 mlir::Value value =
28162901 fir::getBase (converter.genExprValue (assign.rhs , stmtCtx, &loc));
28172902 mlir::Type atomType = fir::unwrapRefType (atomAddr.getType ());
28182903 mlir::Value converted = builder.createConvert (loc, atomType, value);
28192904
28202905 builder.restoreInsertionPoint (atomicAt);
28212906 mlir::Operation *op = builder.create <mlir::omp::AtomicWriteOp>(
2822- loc, atomAddr, converted, hint, memOrder);
2907+ loc, atomAddr, converted, hint, makeMemOrderAttr (converter, memOrder) );
28232908 return op;
28242909}
28252910
28262911static mlir::Operation *
2827- genAtomicUpdate (lower::AbstractConverter &converter, mlir::Location loc,
2912+ genAtomicUpdate (lower::AbstractConverter &converter,
2913+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
28282914 lower::StatementContext &stmtCtx, mlir::Value atomAddr,
28292915 const semantics::SomeExpr &atom,
28302916 const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2831- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2917+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
28322918 fir::FirOpBuilder::InsertPoint preAt,
28332919 fir::FirOpBuilder::InsertPoint atomicAt,
28342920 fir::FirOpBuilder::InsertPoint postAt) {
@@ -2851,8 +2937,8 @@ genAtomicUpdate(lower::AbstractConverter &converter, mlir::Location loc,
28512937 }
28522938
28532939 builder.restoreInsertionPoint (atomicAt);
2854- auto updateOp =
2855- builder. create <mlir::omp::AtomicUpdateOp>( loc, atomAddr, hint, memOrder);
2940+ auto updateOp = builder. create <mlir::omp::AtomicUpdateOp>(
2941+ loc, atomAddr, hint, makeMemOrderAttr (converter, memOrder) );
28562942
28572943 mlir::Region ®ion = updateOp->getRegion (0 );
28582944 mlir::Block *block = builder.createBlock (®ion, {}, {atomType}, {loc});
@@ -2871,11 +2957,12 @@ genAtomicUpdate(lower::AbstractConverter &converter, mlir::Location loc,
28712957}
28722958
28732959static mlir::Operation *
2874- genAtomicOperation (lower::AbstractConverter &converter, mlir::Location loc,
2960+ genAtomicOperation (lower::AbstractConverter &converter,
2961+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
28752962 lower::StatementContext &stmtCtx, int action,
28762963 mlir::Value atomAddr, const semantics::SomeExpr &atom,
28772964 const evaluate::Assignment &assign, mlir::IntegerAttr hint,
2878- mlir::omp::ClauseMemoryOrderKindAttr memOrder,
2965+ std::optional< mlir::omp::ClauseMemoryOrderKind> memOrder,
28792966 fir::FirOpBuilder::InsertPoint preAt,
28802967 fir::FirOpBuilder::InsertPoint atomicAt,
28812968 fir::FirOpBuilder::InsertPoint postAt) {
@@ -2887,14 +2974,14 @@ genAtomicOperation(lower::AbstractConverter &converter, mlir::Location loc,
28872974 // builder's insertion point, or set it to anything specific.
28882975 switch (action) {
28892976 case parser::OpenMPAtomicConstruct::Analysis::Read:
2890- return genAtomicRead (converter, loc, stmtCtx, atomAddr, atom, assign, hint ,
2891- memOrder, preAt, atomicAt, postAt);
2977+ return genAtomicRead (converter, semaCtx, loc, stmtCtx, atomAddr, atom,
2978+ assign, hint, memOrder, preAt, atomicAt, postAt);
28922979 case parser::OpenMPAtomicConstruct::Analysis::Write:
2893- return genAtomicWrite (converter, loc, stmtCtx, atomAddr, atom, assign, hint ,
2894- memOrder, preAt, atomicAt, postAt);
2980+ return genAtomicWrite (converter, semaCtx, loc, stmtCtx, atomAddr, atom,
2981+ assign, hint, memOrder, preAt, atomicAt, postAt);
28952982 case parser::OpenMPAtomicConstruct::Analysis::Update:
2896- return genAtomicUpdate (converter, loc, stmtCtx, atomAddr, atom, assign ,
2897- hint, memOrder, preAt, atomicAt, postAt);
2983+ return genAtomicUpdate (converter, semaCtx, loc, stmtCtx, atomAddr, atom,
2984+ assign, hint, memOrder, preAt, atomicAt, postAt);
28982985 default :
28992986 return nullptr ;
29002987 }
@@ -3894,8 +3981,9 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
38943981 mlir::Value atomAddr =
38953982 fir::getBase (converter.genExprAddr (atom, stmtCtx, &loc));
38963983 mlir::IntegerAttr hint = getAtomicHint (converter, clauses);
3897- mlir::omp::ClauseMemoryOrderKindAttr memOrder =
3898- getAtomicMemoryOrder (converter, semaCtx, clauses);
3984+ std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder =
3985+ getAtomicMemoryOrder (semaCtx, clauses,
3986+ semaCtx.FindScope (construct.source ));
38993987
39003988 if (auto *cond = get (analysis.cond )) {
39013989 (void )cond;
@@ -3913,8 +4001,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
39134001 " Expexcing two actions" );
39144002 (void )action0;
39154003 (void )action1;
3916- captureOp =
3917- builder. create <mlir::omp::AtomicCaptureOp>( loc, hint, memOrder);
4004+ captureOp = builder. create <mlir::omp::AtomicCaptureOp>(
4005+ loc, hint, makeMemOrderAttr (converter, memOrder) );
39184006 // Set the non-atomic insertion point to before the atomic.capture.
39194007 preAt = getInsertionPointBefore (captureOp);
39204008
@@ -3926,7 +4014,7 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
39264014 atomicAt = getInsertionPointBefore (term);
39274015 postAt = getInsertionPointAfter (captureOp);
39284016 hint = nullptr ;
3929- memOrder = nullptr ;
4017+ memOrder = std:: nullopt ;
39304018 } else {
39314019 // Non-capturing operation.
39324020 assert (action0 != analysis.None && action1 == analysis.None &&
@@ -3938,16 +4026,16 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
39384026 // The builder's insertion point needs to be specifically set before
39394027 // each call to `genAtomicOperation`.
39404028 mlir::Operation *firstOp = genAtomicOperation (
3941- converter, loc, stmtCtx, analysis.op0 .what , atomAddr, atom,
4029+ converter, semaCtx, loc, stmtCtx, analysis.op0 .what , atomAddr, atom,
39424030 *get (analysis.op0 .assign ), hint, memOrder, preAt, atomicAt, postAt);
39434031 assert (firstOp && " Should have created an atomic operation" );
39444032 atomicAt = getInsertionPointAfter (firstOp);
39454033
39464034 mlir::Operation *secondOp = nullptr ;
39474035 if (analysis.op1 .what != analysis.None ) {
3948- secondOp = genAtomicOperation (converter, loc, stmtCtx, analysis. op1 . what ,
3949- atomAddr, atom, * get ( analysis.op1 .assign ) ,
3950- hint, memOrder, preAt, atomicAt, postAt);
4036+ secondOp = genAtomicOperation (
4037+ converter, semaCtx, loc, stmtCtx, analysis.op1 .what , atomAddr, atom ,
4038+ * get (analysis. op1 . assign ), hint, memOrder, preAt, atomicAt, postAt);
39514039 }
39524040
39534041 if (construct.IsCapture ()) {
0 commit comments