Skip to content

[flang][OpenMP] Overhaul implementation of ATOMIC construct #137852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4aa88f8
[flang][OpenMP] Mark atomic clauses as unique
kparzysz Apr 26, 2025
69869a7
[flang][OpenACC][OpenMP] Separate implementations of ATOMIC constructs
kparzysz Apr 26, 2025
637d237
[flang][OpenMP] Allow UPDATE clause to not have any arguments
kparzysz Apr 27, 2025
02b4080
[flang][OpenMP] Overhaul implementation of ATOMIC construct
kparzysz Mar 17, 2025
5928e6c
Restart build
kparzysz Apr 29, 2025
5a9cb4a
Restart build
kparzysz Apr 29, 2025
6273bb8
Restart build
kparzysz Apr 30, 2025
3594a0f
Replace %openmp_flags with -fopenmp in tests, add REQUIRES where needed
kparzysz Apr 30, 2025
0142671
Fix examples
kparzysz Apr 30, 2025
c158867
Fix example
kparzysz Apr 30, 2025
ddacb71
Remove reference to *nullptr
kparzysz Apr 30, 2025
ec73e6f
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 1, 2025
71e7fbd
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 6, 2025
4546997
Updates and improvements
kparzysz May 2, 2025
c2e1653
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 7, 2025
7eec417
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 15, 2025
40510a3
DumpEvExpr: show type
kparzysz Mar 24, 2025
b40ba0e
Handle conversion from real to complex via complex constructor
kparzysz May 15, 2025
303aef7
Fix handling of insertion point
kparzysz May 15, 2025
d788d87
Allow conversion in update operations
kparzysz May 16, 2025
ce989c3
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 16, 2025
3417237
format
kparzysz May 16, 2025
2686207
Revert "DumpEvExpr: show type"
kparzysz May 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions flang/examples/FeatureList/FeatureList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,13 +445,6 @@ struct NodeVisitor {
READ_FEATURE(ObjectDecl)
READ_FEATURE(OldParameterStmt)
READ_FEATURE(OmpAlignedClause)
READ_FEATURE(OmpAtomic)
READ_FEATURE(OmpAtomicCapture)
READ_FEATURE(OmpAtomicCapture::Stmt1)
READ_FEATURE(OmpAtomicCapture::Stmt2)
READ_FEATURE(OmpAtomicRead)
READ_FEATURE(OmpAtomicUpdate)
READ_FEATURE(OmpAtomicWrite)
READ_FEATURE(OmpBeginBlockDirective)
READ_FEATURE(OmpBeginLoopDirective)
READ_FEATURE(OmpBeginSectionsDirective)
Expand Down Expand Up @@ -480,7 +473,6 @@ struct NodeVisitor {
READ_FEATURE(OmpIterationOffset)
READ_FEATURE(OmpIterationVector)
READ_FEATURE(OmpEndAllocators)
READ_FEATURE(OmpEndAtomic)
READ_FEATURE(OmpEndBlockDirective)
READ_FEATURE(OmpEndCriticalDirective)
READ_FEATURE(OmpEndLoopDirective)
Expand Down Expand Up @@ -566,8 +558,6 @@ struct NodeVisitor {
READ_FEATURE(OpenMPDeclareTargetConstruct)
READ_FEATURE(OmpMemoryOrderType)
READ_FEATURE(OmpMemoryOrderClause)
READ_FEATURE(OmpAtomicClause)
READ_FEATURE(OmpAtomicClauseList)
READ_FEATURE(OmpAtomicDefaultMemOrderClause)
READ_FEATURE(OpenMPFlushConstruct)
READ_FEATURE(OpenMPLoopConstruct)
Expand Down
27 changes: 8 additions & 19 deletions flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,25 +74,19 @@ SourcePosition OpenMPCounterVisitor::getLocation(const OpenMPConstruct &c) {
// the directive field.
[&](const auto &c) -> SourcePosition {
const CharBlock &source{std::get<0>(c.t).source};
return (parsing->allCooked().GetSourcePositionRange(source))->first;
return parsing->allCooked().GetSourcePositionRange(source)->first;
},
[&](const OpenMPAtomicConstruct &c) -> SourcePosition {
return std::visit(
[&](const auto &o) -> SourcePosition {
const CharBlock &source{std::get<Verbatim>(o.t).source};
return parsing->allCooked()
.GetSourcePositionRange(source)
->first;
},
c.u);
const CharBlock &source{c.source};
return parsing->allCooked().GetSourcePositionRange(source)->first;
},
[&](const OpenMPSectionConstruct &c) -> SourcePosition {
const CharBlock &source{c.source};
return (parsing->allCooked().GetSourcePositionRange(source))->first;
return parsing->allCooked().GetSourcePositionRange(source)->first;
},
[&](const OpenMPUtilityConstruct &c) -> SourcePosition {
const CharBlock &source{c.source};
return (parsing->allCooked().GetSourcePositionRange(source))->first;
return parsing->allCooked().GetSourcePositionRange(source)->first;
},
},
c.u);
Expand Down Expand Up @@ -157,14 +151,9 @@ std::string OpenMPCounterVisitor::getName(const OpenMPConstruct &c) {
return normalize_construct_name(source.ToString());
},
[&](const OpenMPAtomicConstruct &c) -> std::string {
return std::visit(
[&](const auto &c) {
// Get source from the verbatim fields
const CharBlock &source{std::get<Verbatim>(c.t).source};
return "atomic-" +
normalize_construct_name(source.ToString());
},
c.u);
auto &dirSpec = std::get<OmpDirectiveSpecification>(c.t);
auto &dirName = std::get<OmpDirectiveName>(dirSpec.t);
return normalize_construct_name(dirName.source.ToString());
},
[&](const OpenMPUtilityConstruct &c) -> std::string {
const CharBlock &source{c.source};
Expand Down
12 changes: 0 additions & 12 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,15 +532,6 @@ class ParseTreeDumper {
NODE(parser, OmpAtClause)
NODE_ENUM(OmpAtClause, ActionTime)
NODE_ENUM(OmpSeverityClause, Severity)
NODE(parser, OmpAtomic)
NODE(parser, OmpAtomicCapture)
NODE(OmpAtomicCapture, Stmt1)
NODE(OmpAtomicCapture, Stmt2)
NODE(parser, OmpAtomicCompare)
NODE(parser, OmpAtomicCompareIfStmt)
NODE(parser, OmpAtomicRead)
NODE(parser, OmpAtomicUpdate)
NODE(parser, OmpAtomicWrite)
NODE(parser, OmpBeginBlockDirective)
NODE(parser, OmpBeginLoopDirective)
NODE(parser, OmpBeginSectionsDirective)
Expand Down Expand Up @@ -587,7 +578,6 @@ class ParseTreeDumper {
NODE(parser, OmpDoacrossClause)
NODE(parser, OmpDestroyClause)
NODE(parser, OmpEndAllocators)
NODE(parser, OmpEndAtomic)
NODE(parser, OmpEndBlockDirective)
NODE(parser, OmpEndCriticalDirective)
NODE(parser, OmpEndLoopDirective)
Expand Down Expand Up @@ -716,8 +706,6 @@ class ParseTreeDumper {
NODE(parser, OpenMPDeclareMapperConstruct)
NODE_ENUM(common, OmpMemoryOrderType)
NODE(parser, OmpMemoryOrderClause)
NODE(parser, OmpAtomicClause)
NODE(parser, OmpAtomicClauseList)
NODE(parser, OmpAtomicDefaultMemOrderClause)
NODE(parser, OpenMPDepobjConstruct)
NODE(parser, OpenMPUtilityConstruct)
Expand Down
111 changes: 27 additions & 84 deletions flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -4857,94 +4857,37 @@ struct OmpMemoryOrderClause {
CharBlock source;
};

// 2.17.7 Atomic construct
// atomic-clause -> memory-order-clause | HINT(hint-expression) |
// FAIL(memory-order)
struct OmpAtomicClause {
UNION_CLASS_BOILERPLATE(OmpAtomicClause);
CharBlock source;
std::variant<OmpMemoryOrderClause, OmpFailClause, OmpHintClause> u;
};

// atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
struct OmpAtomicClauseList {
WRAPPER_CLASS_BOILERPLATE(OmpAtomicClauseList, std::list<OmpAtomicClause>);
CharBlock source;
};

// END ATOMIC
EMPTY_CLASS(OmpEndAtomic);

// ATOMIC READ
struct OmpAtomicRead {
TUPLE_CLASS_BOILERPLATE(OmpAtomicRead);
CharBlock source;
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
t;
};

// ATOMIC WRITE
struct OmpAtomicWrite {
TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite);
CharBlock source;
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
t;
};

// ATOMIC UPDATE
struct OmpAtomicUpdate {
TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate);
CharBlock source;
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
t;
};

// ATOMIC CAPTURE
struct OmpAtomicCapture {
TUPLE_CLASS_BOILERPLATE(OmpAtomicCapture);
CharBlock source;
WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList, Stmt1, Stmt2,
OmpEndAtomic>
t;
};

struct OmpAtomicCompareIfStmt {
UNION_CLASS_BOILERPLATE(OmpAtomicCompareIfStmt);
std::variant<common::Indirection<IfStmt>, common::Indirection<IfConstruct>> u;
};

// ATOMIC COMPARE (OpenMP 5.1, OPenMP 5.2 spec: 15.8.4)
struct OmpAtomicCompare {
TUPLE_CLASS_BOILERPLATE(OmpAtomicCompare);
struct OpenMPAtomicConstruct {
llvm::omp::Clause GetKind() const;
bool IsCapture() const;
bool IsCompare() const;
TUPLE_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
CharBlock source;
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
OmpAtomicCompareIfStmt, std::optional<OmpEndAtomic>>
std::tuple<OmpDirectiveSpecification, Block,
std::optional<OmpDirectiveSpecification>>
t;
};

// ATOMIC
struct OmpAtomic {
TUPLE_CLASS_BOILERPLATE(OmpAtomic);
CharBlock source;
std::tuple<Verbatim, OmpAtomicClauseList, Statement<AssignmentStmt>,
std::optional<OmpEndAtomic>>
t;
};
// Information filled out during semantic checks to avoid duplication
// of analyses.
struct Analysis {
static constexpr int None = 0;
static constexpr int Read = 1;
static constexpr int Write = 2;
static constexpr int Update = Read | Write;
static constexpr int Action = 3; // Bitmask for None, Read, Write, Update
static constexpr int IfTrue = 4;
static constexpr int IfFalse = 8;
static constexpr int Condition = 12; // Bitmask for IfTrue, IfFalse

struct Op {
int what;
AssignmentStmt::TypedAssignment assign;
};
TypedExpr atom, cond;
Op op0, op1;
};

// 2.17.7 atomic ->
// ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] |
// ATOMIC [atomic-clause-list]
// atomic-construct -> READ | WRITE | UPDATE | CAPTURE | COMPARE
struct OpenMPAtomicConstruct {
UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
std::variant<OmpAtomicRead, OmpAtomicWrite, OmpAtomicCapture, OmpAtomicUpdate,
OmpAtomicCompare, OmpAtomic>
u;
mutable Analysis analysis;
};

// OpenMP directives that associate with loop(s)
Expand Down
17 changes: 17 additions & 0 deletions flang/include/flang/Semantics/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -782,5 +782,22 @@ inline bool checkForSymbolMatch(
}
return false;
}

/// If the top-level operation (ignoring parentheses) is either an
/// evaluate::FunctionRef, or a specialization of evaluate::Operation,
/// then return the list of arguments (wrapped in SomeExpr). Otherwise,
/// return the "expr" but with top-level parentheses stripped.
std::vector<SomeExpr> GetOpenMPTopLevelArguments(const SomeExpr &expr);

/// Check if expr is same as x, or a sequence of Convert operations on x.
bool IsSameOrConvertOf(const SomeExpr &expr, const SomeExpr &x);

/// Strip away any top-level Convert operations (if any exist) and return
/// the input value. A ComplexConstructor(x, 0) is also considered as a
/// convert operation.
/// If the input is not Operation, Designator, FunctionRef or Constant,
/// is returns std::nullopt.
MaybeExpr GetConvertInput(const SomeExpr &x);

} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_TOOLS_H_
40 changes: 20 additions & 20 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,26 +334,26 @@ getSource(const semantics::SemanticsContext &semaCtx,
const parser::CharBlock *source = nullptr;

auto ompConsVisit = [&](const parser::OpenMPConstruct &x) {
std::visit(common::visitors{
[&](const parser::OpenMPSectionsConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const parser::OpenMPLoopConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const parser::OpenMPBlockConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const parser::OpenMPCriticalConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const parser::OpenMPAtomicConstruct &x) {
std::visit([&](const auto &x) { source = &x.source; },
x.u);
},
[&](const auto &x) { source = &x.source; },
},
x.u);
std::visit(
common::visitors{
[&](const parser::OpenMPSectionsConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const parser::OpenMPLoopConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const parser::OpenMPBlockConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const parser::OpenMPCriticalConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const parser::OpenMPAtomicConstruct &x) {
source = &std::get<parser::OmpDirectiveSpecification>(x.t).source;
},
[&](const auto &x) { source = &x.source; },
},
x.u);
};

eval.visit(common::visitors{
Expand Down
Loading