2020#include " flang/Optimizer/Builder/FIRBuilder.h"
2121#include " flang/Optimizer/Builder/Todo.h"
2222#include " flang/Parser/parse-tree.h"
23+ #include " flang/Semantics/openmp-utils.h"
2324#include " flang/Semantics/semantics.h"
2425#include " flang/Semantics/type.h"
2526#include " flang/Support/Fortran.h"
@@ -183,12 +184,8 @@ getMemoryOrderFromRequires(const semantics::Scope &scope) {
183184 // scope.
184185 // For safety, traverse all enclosing scopes and check if their symbol
185186 // contains REQUIRES.
186- for (const auto *sc{&scope}; sc->kind () != semantics::Scope::Kind::Global;
187- sc = &sc->parent ()) {
188- const semantics::Symbol *sym = sc->symbol ();
189- if (!sym)
190- continue ;
191-
187+ const semantics::Scope &unitScope = semantics::omp::GetProgramUnit (scope);
188+ if (auto *symbol = unitScope.symbol ()) {
192189 const common::OmpMemoryOrderType *admo = common::visit (
193190 [](auto &&s) {
194191 using WithOmpDeclarative = semantics::WithOmpDeclarative;
@@ -198,7 +195,8 @@ getMemoryOrderFromRequires(const semantics::Scope &scope) {
198195 }
199196 return static_cast <const common::OmpMemoryOrderType *>(nullptr );
200197 },
201- sym->details ());
198+ symbol->details ());
199+
202200 if (admo)
203201 return getMemoryOrderKind (*admo);
204202 }
@@ -214,19 +212,83 @@ getDefaultAtomicMemOrder(semantics::SemanticsContext &semaCtx) {
214212 return std::nullopt ;
215213}
216214
217- static std::optional<mlir::omp::ClauseMemoryOrderKind>
215+ static std::pair<std:: optional<mlir::omp::ClauseMemoryOrderKind>, bool >
218216getAtomicMemoryOrder (semantics::SemanticsContext &semaCtx,
219217 const omp::List<omp::Clause> &clauses,
220218 const semantics::Scope &scope) {
221219 for (const omp::Clause &clause : clauses) {
222220 if (auto maybeKind = getMemoryOrderKind (clause.id ))
223- return *maybeKind;
221+ return std::make_pair ( *maybeKind, /* canOverride= */ false ) ;
224222 }
225223
226224 if (auto maybeKind = getMemoryOrderFromRequires (scope))
227- return *maybeKind;
225+ return std::make_pair ( *maybeKind, /* canOverride= */ true ) ;
228226
229- return getDefaultAtomicMemOrder (semaCtx);
227+ return std::make_pair (getDefaultAtomicMemOrder (semaCtx),
228+ /* canOverride=*/ false );
229+ }
230+
231+ static std::optional<mlir::omp::ClauseMemoryOrderKind>
232+ makeValidForAction (std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder,
233+ int action0, int action1, unsigned version) {
234+ // When the atomic default memory order specified on a REQUIRES directive is
235+ // disallowed on a given ATOMIC operation, and it's not ACQ_REL, the order
236+ // reverts to RELAXED. ACQ_REL decays to either ACQUIRE or RELEASE, depending
237+ // on the operation.
238+
239+ if (!memOrder) {
240+ return memOrder;
241+ }
242+
243+ using Analysis = parser::OpenMPAtomicConstruct::Analysis;
244+ // Figure out the main action (i.e. disregard a potential capture operation)
245+ int action = action0;
246+ if (action1 != Analysis::None)
247+ action = action0 == Analysis::Read ? action1 : action0;
248+
249+ // Avaliable orderings: acquire, acq_rel, relaxed, release, seq_cst
250+
251+ if (action == Analysis::Read) {
252+ // "acq_rel" decays to "acquire"
253+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
254+ return mlir::omp::ClauseMemoryOrderKind::Acquire;
255+ } else if (action == Analysis::Write) {
256+ // "acq_rel" decays to "release"
257+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
258+ return mlir::omp::ClauseMemoryOrderKind::Release;
259+ }
260+
261+ if (version > 50 ) {
262+ if (action == Analysis::Read) {
263+ // "release" prohibited
264+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Release)
265+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
266+ }
267+ if (action == Analysis::Write) {
268+ // "acquire" prohibited
269+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire)
270+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
271+ }
272+ } else {
273+ if (action == Analysis::Read) {
274+ // "release" prohibited
275+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Release)
276+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
277+ } else {
278+ if (action & Analysis::Write) { // include "update"
279+ // "acquire" prohibited
280+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acquire)
281+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
282+ if (action == Analysis::Update) {
283+ // "acq_rel" prohibited
284+ if (*memOrder == mlir::omp::ClauseMemoryOrderKind::Acq_rel)
285+ return mlir::omp::ClauseMemoryOrderKind::Relaxed;
286+ }
287+ }
288+ }
289+ }
290+
291+ return memOrder;
230292}
231293
232294static mlir::omp::ClauseMemoryOrderKindAttr
@@ -449,16 +511,19 @@ void Fortran::lower::omp::lowerAtomic(
449511 mlir::Value atomAddr =
450512 fir::getBase (converter.genExprAddr (atom, stmtCtx, &loc));
451513 mlir::IntegerAttr hint = getAtomicHint (converter, clauses);
452- std::optional<mlir::omp::ClauseMemoryOrderKind> memOrder =
453- getAtomicMemoryOrder (semaCtx, clauses,
454- semaCtx.FindScope (construct.source ));
514+ auto [memOrder, canOverride] = getAtomicMemoryOrder (
515+ semaCtx, clauses, semaCtx.FindScope (construct.source ));
516+
517+ unsigned version = semaCtx.langOptions ().OpenMPVersion ;
518+ int action0 = analysis.op0 .what & analysis.Action ;
519+ int action1 = analysis.op1 .what & analysis.Action ;
520+ if (canOverride)
521+ memOrder = makeValidForAction (memOrder, action0, action1, version);
455522
456523 if (auto *cond = get (analysis.cond )) {
457524 (void )cond;
458525 TODO (loc, " OpenMP ATOMIC COMPARE" );
459526 } else {
460- int action0 = analysis.op0 .what & analysis.Action ;
461- int action1 = analysis.op1 .what & analysis.Action ;
462527 mlir::Operation *captureOp = nullptr ;
463528 fir::FirOpBuilder::InsertPoint preAt = builder.saveInsertionPoint ();
464529 fir::FirOpBuilder::InsertPoint atomicAt, postAt;
0 commit comments