[flang][OpenMP] Extend common::AtomicDefaultMemOrderType enumeration (#136312)

Add "Acquire" and "Release", and rename it to OmpMemoryOrderType, since
memory order type is a concept extending beyond the
ATOMIC_DEFAULT_MEM_ORDER clause.

When processing a REQUIRES directive (in rewrite-directives.cpp), do not
add Acquire or Release to ATOMIC constructs, because handling of those
types depends on the OpenMP version, which is not available in that
file. This issue will be addressed later.
This commit is contained in:
Krzysztof Parzyszek
2025-04-23 05:57:52 -05:00
committed by GitHub
parent 71ce9e26ae
commit 05b7e97c78
11 changed files with 85 additions and 70 deletions

View File

@@ -564,11 +564,11 @@ public:
READ_FEATURE(OpenMPDeclareReductionConstruct)
READ_FEATURE(OpenMPDeclareSimdConstruct)
READ_FEATURE(OpenMPDeclareTargetConstruct)
READ_FEATURE(OmpMemoryOrderType)
READ_FEATURE(OmpMemoryOrderClause)
READ_FEATURE(OmpAtomicClause)
READ_FEATURE(OmpAtomicClauseList)
READ_FEATURE(OmpAtomicDefaultMemOrderClause)
READ_FEATURE(OmpAtomicDefaultMemOrderType)
READ_FEATURE(OpenMPFlushConstruct)
READ_FEATURE(OpenMPLoopConstruct)
READ_FEATURE(OpenMPExecutableAllocate)

View File

@@ -55,36 +55,42 @@ static inline void genOmpAtomicHintAndMemoryOrderClauses(
mlir::omp::ClauseMemoryOrderKindAttr &memoryOrder) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
for (const Fortran::parser::OmpAtomicClause &clause : clauseList.v) {
if (const auto *hintClause =
std::get_if<Fortran::parser::OmpHintClause>(&clause.u)) {
const auto *expr = Fortran::semantics::GetExpr(hintClause->v);
uint64_t hintExprValue = *Fortran::evaluate::ToInt64(*expr);
hint = firOpBuilder.getI64IntegerAttr(hintExprValue);
} else if (const auto *ompMemoryOrderClause =
std::get_if<Fortran::parser::OmpMemoryOrderClause>(
&clause.u)) {
if (std::get_if<Fortran::parser::OmpClause::Acquire>(
&ompMemoryOrderClause->v.u)) {
memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
firOpBuilder.getContext(),
mlir::omp::ClauseMemoryOrderKind::Acquire);
} else if (std::get_if<Fortran::parser::OmpClause::Relaxed>(
&ompMemoryOrderClause->v.u)) {
memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
firOpBuilder.getContext(),
mlir::omp::ClauseMemoryOrderKind::Relaxed);
} else if (std::get_if<Fortran::parser::OmpClause::SeqCst>(
&ompMemoryOrderClause->v.u)) {
memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
firOpBuilder.getContext(),
mlir::omp::ClauseMemoryOrderKind::Seq_cst);
} else if (std::get_if<Fortran::parser::OmpClause::Release>(
&ompMemoryOrderClause->v.u)) {
memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
firOpBuilder.getContext(),
mlir::omp::ClauseMemoryOrderKind::Release);
}
}
common::visit(
common::visitors{
[&](const parser::OmpMemoryOrderClause &s) {
auto kind = common::visit(
common::visitors{
[&](const parser::OmpClause::AcqRel &) {
return mlir::omp::ClauseMemoryOrderKind::Acq_rel;
},
[&](const parser::OmpClause::Acquire &) {
return mlir::omp::ClauseMemoryOrderKind::Acquire;
},
[&](const parser::OmpClause::Relaxed &) {
return mlir::omp::ClauseMemoryOrderKind::Relaxed;
},
[&](const parser::OmpClause::Release &) {
return mlir::omp::ClauseMemoryOrderKind::Release;
},
[&](const parser::OmpClause::SeqCst &) {
return mlir::omp::ClauseMemoryOrderKind::Seq_cst;
},
[&](auto &&) -> mlir::omp::ClauseMemoryOrderKind {
llvm_unreachable("Unexpected clause");
},
},
s.v.u);
memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
firOpBuilder.getContext(), kind);
},
[&](const parser::OmpHintClause &s) {
const auto *expr = Fortran::semantics::GetExpr(s.v);
uint64_t hintExprValue = *Fortran::evaluate::ToInt64(*expr);
hint = firOpBuilder.getI64IntegerAttr(hintExprValue);
},
[&](const parser::OmpFailClause &) {},
},
clause.u);
}
}

View File

@@ -707,11 +707,11 @@ public:
NODE(parser, OpenMPDeclareSimdConstruct)
NODE(parser, OpenMPDeclareTargetConstruct)
NODE(parser, OpenMPDeclareMapperConstruct)
NODE_ENUM(common, OmpMemoryOrderType)
NODE(parser, OmpMemoryOrderClause)
NODE(parser, OmpAtomicClause)
NODE(parser, OmpAtomicClauseList)
NODE(parser, OmpAtomicDefaultMemOrderClause)
NODE_ENUM(common, OmpAtomicDefaultMemOrderType)
NODE(parser, OpenMPDepobjConstruct)
NODE(parser, OpenMPUtilityConstruct)
NODE(parser, OpenMPDispatchConstruct)

View File

@@ -4071,7 +4071,7 @@ struct OmpAtClause {
// SEQ_CST | ACQ_REL | RELAXED | // since 5.0
// ACQUIRE | RELEASE // since 5.2
struct OmpAtomicDefaultMemOrderClause {
using MemoryOrder = common::OmpAtomicDefaultMemOrderType;
using MemoryOrder = common::OmpMemoryOrderType;
WRAPPER_CLASS_BOILERPLATE(OmpAtomicDefaultMemOrderClause, MemoryOrder);
};
@@ -4822,10 +4822,10 @@ struct OpenMPAllocatorsConstruct {
// 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0]
// memory-order-clause -> acq_rel
// release
// acquire
// seq_cst
// release
// relaxed
// seq_cst
struct OmpMemoryOrderClause {
WRAPPER_CLASS_BOILERPLATE(OmpMemoryOrderClause, OmpClause);
CharBlock source;

View File

@@ -48,7 +48,7 @@ using MutableSymbolVector = std::vector<MutableSymbolRef>;
// Mixin for details with OpenMP declarative constructs.
class WithOmpDeclarative {
using OmpAtomicOrderType = common::OmpAtomicDefaultMemOrderType;
using OmpAtomicOrderType = common::OmpMemoryOrderType;
public:
ENUM_CLASS(RequiresFlag, ReverseOffload, UnifiedAddress, UnifiedSharedMemory,

View File

@@ -72,8 +72,8 @@ ENUM_CLASS(
ENUM_CLASS(
OpenACCDeviceType, Star, Default, Nvidia, Radeon, Host, Multicore, None)
// OpenMP atomic_default_mem_order clause allowed values
ENUM_CLASS(OmpAtomicDefaultMemOrderType, SeqCst, AcqRel, Relaxed)
// OpenMP memory-order types
ENUM_CLASS(OmpMemoryOrderType, Acq_Rel, Acquire, Relaxed, Release, Seq_Cst)
// Fortran names may have up to 63 characters (See Fortran 2018 C601).
static constexpr int maxNameLen{63};

View File

@@ -494,12 +494,13 @@ AtomicDefaultMemOrder make(const parser::OmpClause::AtomicDefaultMemOrder &inp,
semantics::SemanticsContext &semaCtx) {
// inp.v -> parser::OmpAtomicDefaultMemOrderClause
CLAUSET_ENUM_CONVERT( //
convert, common::OmpAtomicDefaultMemOrderType,
AtomicDefaultMemOrder::MemoryOrder,
convert, common::OmpMemoryOrderType, AtomicDefaultMemOrder::MemoryOrder,
// clang-format off
MS(AcqRel, AcqRel)
MS(Acq_Rel, AcqRel)
MS(Acquire, Acquire)
MS(Relaxed, Relaxed)
MS(SeqCst, SeqCst)
MS(Release, Release)
MS(Seq_Cst, SeqCst)
// clang-format on
);

View File

@@ -636,6 +636,20 @@ TYPE_PARSER(construct<OmpAffinityClause>(
maybe(nonemptyList(Parser<OmpAffinityClause::Modifier>{}) / ":"),
Parser<OmpObjectList>{}))
// 2.4 Requires construct [OpenMP 5.0]
// atomic-default-mem-order-clause ->
// acq_rel
// acquire
// relaxed
// release
// seq_cst
TYPE_PARSER(construct<OmpAtomicDefaultMemOrderClause>(
"ACQ_REL" >> pure(common::OmpMemoryOrderType::Acq_Rel) ||
"ACQUIRE" >> pure(common::OmpMemoryOrderType::Acquire) ||
"RELAXED" >> pure(common::OmpMemoryOrderType::Relaxed) ||
"RELEASE" >> pure(common::OmpMemoryOrderType::Release) ||
"SEQ_CST" >> pure(common::OmpMemoryOrderType::Seq_Cst)))
TYPE_PARSER(construct<OmpCancellationConstructTypeClause>(
OmpDirectiveNameParser{}, maybe(parenthesized(scalarLogicalExpr))))
@@ -1192,27 +1206,17 @@ TYPE_PARSER(sourced(construct<OmpFailClause>(
// 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0]
// memory-order-clause ->
// seq_cst
// acq_rel
// release
// acquire
// relaxed
TYPE_PARSER(sourced(construct<OmpMemoryOrderClause>(
sourced("SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>()) ||
"ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
"RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||
"ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
"RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>())))))
// 2.4 Requires construct [OpenMP 5.0]
// atomic-default-mem-order-clause ->
// release
// seq_cst
// acq_rel
// relaxed
TYPE_PARSER(construct<OmpAtomicDefaultMemOrderClause>(
"SEQ_CST" >> pure(common::OmpAtomicDefaultMemOrderType::SeqCst) ||
"ACQ_REL" >> pure(common::OmpAtomicDefaultMemOrderType::AcqRel) ||
"RELAXED" >> pure(common::OmpAtomicDefaultMemOrderType::Relaxed)))
TYPE_PARSER(sourced(construct<OmpMemoryOrderClause>(
sourced("ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
"ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
"RELAXED" >> construct<OmpClause>(construct<OmpClause::Relaxed>()) ||
"RELEASE" >> construct<OmpClause>(construct<OmpClause::Release>()) ||
"SEQ_CST" >> construct<OmpClause>(construct<OmpClause::SeqCst>())))))
// 2.17.7 Atomic construct
// atomic-clause -> memory-order-clause | HINT(hint-expression)

View File

@@ -2558,8 +2558,8 @@ public:
}
}
void Unparse(const OmpAtomicDefaultMemOrderClause &x) {
Word(ToUpperCaseLetters(common::EnumToString(x.v)));
void Unparse(const common::OmpMemoryOrderType &x) {
Word(ToUpperCaseLetters(common::EnumToString(x)));
}
void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); }

View File

@@ -416,7 +416,7 @@ public:
// Gather information from the clauses.
Flags flags;
std::optional<common::OmpAtomicDefaultMemOrderType> memOrder;
std::optional<common::OmpMemoryOrderType> memOrder;
for (const auto &clause : std::get<parser::OmpClauseList>(x.t).v) {
flags |= common::visit(
common::visitors{
@@ -799,7 +799,7 @@ private:
std::int64_t ordCollapseLevel{0};
void AddOmpRequiresToScope(Scope &, WithOmpDeclarative::RequiresFlags,
std::optional<common::OmpAtomicDefaultMemOrderType>);
std::optional<common::OmpMemoryOrderType>);
void IssueNonConformanceWarning(
llvm::omp::Directive D, parser::CharBlock source);
@@ -2721,7 +2721,7 @@ void ResolveOmpTopLevelParts(
// program units. Modules are skipped because their REQUIRES clauses should be
// propagated via USE statements instead.
WithOmpDeclarative::RequiresFlags combinedFlags;
std::optional<common::OmpAtomicDefaultMemOrderType> combinedMemOrder;
std::optional<common::OmpMemoryOrderType> combinedMemOrder;
// Function to go through non-module top level program units and extract
// REQUIRES information to be processed by a function-like argument.
@@ -2764,7 +2764,7 @@ void ResolveOmpTopLevelParts(
flags{details.ompRequires()}) {
combinedFlags |= *flags;
}
if (const common::OmpAtomicDefaultMemOrderType *
if (const common::OmpMemoryOrderType *
memOrder{details.ompAtomicDefaultMemOrder()}) {
if (combinedMemOrder && *combinedMemOrder != *memOrder) {
context.Say(symbol.scope()->sourceRange(),
@@ -2983,7 +2983,7 @@ void OmpAttributeVisitor::CheckNameInAllocateStmt(
void OmpAttributeVisitor::AddOmpRequiresToScope(Scope &scope,
WithOmpDeclarative::RequiresFlags flags,
std::optional<common::OmpAtomicDefaultMemOrderType> memOrder) {
std::optional<common::OmpMemoryOrderType> memOrder) {
Scope *scopeIter = &scope;
do {
if (Symbol * symbol{scopeIter->symbol()}) {

View File

@@ -70,7 +70,7 @@ bool OmpRewriteMutator::Pre(parser::OpenMPAtomicConstruct &x) {
x.u)};
// Get the `atomic_default_mem_order` clause from the top-level parent.
std::optional<common::OmpAtomicDefaultMemOrderType> defaultMemOrder;
std::optional<common::OmpMemoryOrderType> defaultMemOrder;
common::visit(
[&](auto &details) {
if constexpr (std::is_convertible_v<decltype(&details),
@@ -119,7 +119,7 @@ bool OmpRewriteMutator::Pre(parser::OpenMPAtomicConstruct &x) {
if (clauseList) {
atomicDirectiveDefaultOrderFound_ = true;
switch (*defaultMemOrder) {
case common::OmpAtomicDefaultMemOrderType::AcqRel:
case common::OmpMemoryOrderType::Acq_Rel:
clauseList->emplace_back<parser::OmpMemoryOrderClause>(common::visit(
common::visitors{[](parser::OmpAtomicRead &) -> parser::OmpClause {
return parser::OmpClause::Acquire{};
@@ -133,14 +133,18 @@ bool OmpRewriteMutator::Pre(parser::OpenMPAtomicConstruct &x) {
}},
x.u));
break;
case common::OmpAtomicDefaultMemOrderType::Relaxed:
case common::OmpMemoryOrderType::Relaxed:
clauseList->emplace_back<parser::OmpMemoryOrderClause>(
parser::OmpClause{parser::OmpClause::Relaxed{}});
break;
case common::OmpAtomicDefaultMemOrderType::SeqCst:
case common::OmpMemoryOrderType::Seq_Cst:
clauseList->emplace_back<parser::OmpMemoryOrderClause>(
parser::OmpClause{parser::OmpClause::SeqCst{}});
break;
default:
// FIXME: Don't process other values at the moment since their validity
// depends on the OpenMP version (which is unavailable here).
break;
}
}