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

Merged
merged 61 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 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
41fd27b
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 27, 2025
c00fc53
Delete unnecessary static_assert
kparzysz May 29, 2025
45b012c
Add missing initializer for 'iff'
kparzysz May 29, 2025
daeac25
Add asserts for printing "Identity" as top-level operator
kparzysz May 29, 2025
ae121e5
Explain the use of determinant
kparzysz May 29, 2025
81810ec
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 29, 2025
cae0e8f
Deal with assignments that failed Fortran semantic checks
kparzysz May 30, 2025
6bc8c10
Move common functions to tools.cpp
kparzysz May 30, 2025
be61b8c
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 30, 2025
a83a1cf
format
kparzysz May 30, 2025
9770e4d
Restore accidentally removed Le
kparzysz May 30, 2025
9b8aaa5
Recognize constants as "operations"
kparzysz May 30, 2025
f7bc109
Add lit tests for dumping atomic analysis
kparzysz May 30, 2025
4d7e622
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz May 30, 2025
7355186
format
kparzysz May 30, 2025
dbe7a52
Fix test maybe
kparzysz May 30, 2025
bb5356f
Fix typos
kparzysz Jun 2, 2025
1f40fe5
Remove default from switch
kparzysz Jun 2, 2025
3d01f74
Add unparse tests for compare
kparzysz Jun 2, 2025
76624e6
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 2, 2025
1ae3898
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 2, 2025
1cd6253
Document atomic extensions
kparzysz Jun 2, 2025
069308f
Allow elements of allocatable arrays
kparzysz Jun 2, 2025
fefc34f
Fix typos
kparzysz Jun 4, 2025
44cc971
Fix test RUN line
kparzysz Jun 4, 2025
b27c7cb
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 4, 2025
2636fd6
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 4, 2025
144170c
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 4, 2025
1456802
Improve type checks, add testcases
kparzysz Jun 4, 2025
1b352f6
Fail with some grace on pointer assignments
kparzysz Jun 4, 2025
591e1d6
format
kparzysz Jun 4, 2025
e5e4288
Accept both "end atomic" and "endatomic"
kparzysz Jun 5, 2025
7515f07
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 5, 2025
b299049
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 10, 2025
e463f77
Update test
kparzysz Jun 10, 2025
9e49784
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 10, 2025
3c38618
Update tools.h
kparzysz Jun 10, 2025
39ba888
Merge branch 'main' into users/kparzysz/spr/a04-atomic-one
kparzysz Jun 11, 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
13 changes: 13 additions & 0 deletions flang/docs/OpenMPSupport.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,16 @@ Note : No distinction is made between the support in Parser/Semantics, MLIR, Low
| target teams distribute parallel loop construct | P | device, reduction and dist_schedule clauses are not supported |
| teams distribute parallel loop simd construct | P | reduction, dist_schedule, and linear clauses are not supported |
| target teams distribute parallel loop simd construct | P | device, reduction, dist_schedule and linear clauses are not supported |

## Extensions
### ATOMIC construct
The implementation of the ATOMIC construct follows OpenMP 6.0 with the following extensions:
- `x = x` is an allowed form of ATOMIC UPDATE.
This is motivated by the fact that the equivalent forms `x = x+0` or `x = x*1` are allowed.
- Explicit type conversions are allowed in ATOMIC READ, WRITE or UPDATE constructs, and in the capture statement in ATOMIC UPDATE CAPTURE.
The OpenMP spec requires intrinsic- or pointer-assignments, which include (as per the Fortran standard) implicit type conversions. Since such conversions need to be handled, allowing explicit conversions comes at no extra cost.
- A literal `.true.` or `.false.` is an allowed condition in ATOMIC UPDATE COMPARE. [1]
- A logical variable is an allowed form of the condition even if its value is not computed within the ATOMIC UPDATE COMPARE construct [1].
- `expr equalop x` is an allowed condition in ATOMIC UPDATE COMPARE. [1]

[1] Code generation for ATOMIC UPDATE COMPARE is not implemented yet.
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
Loading