Skip to content

Commit 141d390

Browse files
authored
[flang][OpenMP] Overhaul implementation of ATOMIC construct (#137852)
The parser will accept a wide variety of illegal attempts at forming an ATOMIC construct, leaving it to the semantic analysis to diagnose any issues. This consolidates the analysis into one place and allows us to produce more informative diagnostics. The parser's outcome will be parser::OpenMPAtomicConstruct object holding the directive, parser::Body, and an optional end-directive. The prior variety of OmpAtomicXyz classes, as well as OmpAtomicClause have been removed. READ, WRITE, etc. are now proper clauses. The semantic analysis consistently operates on "evaluation" representations, mainly evaluate::Expr (as SomeExpr) and evaluate::Assignment. The results of the semantic analysis are stored in a mutable member of the OpenMPAtomicConstruct node. This follows a precedent of having `typedExpr` member in parser::Expr, for example. This allows the lowering code to avoid duplicated handling of AST nodes. Using a BLOCK construct containing multiple statements for an ATOMIC construct that requires multiple statements is now allowed. In fact, any nesting of such BLOCK constructs is allowed. This implementation will parse, and perform semantic checks for both conditional-update and conditional-update-capture, although no MLIR will be generated for those. Instead, a TODO error will be issues prior to lowering. The allowed forms of the ATOMIC construct were based on the OpenMP 6.0 spec.
1 parent 3ca6ea0 commit 141d390

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3753
-1998
lines changed

flang/docs/OpenMPSupport.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,16 @@ Note : No distinction is made between the support in Parser/Semantics, MLIR, Low
6060
| target teams distribute parallel loop construct | P | device, reduction and dist_schedule clauses are not supported |
6161
| teams distribute parallel loop simd construct | P | reduction, dist_schedule, and linear clauses are not supported |
6262
| target teams distribute parallel loop simd construct | P | device, reduction, dist_schedule and linear clauses are not supported |
63+
64+
## Extensions
65+
### ATOMIC construct
66+
The implementation of the ATOMIC construct follows OpenMP 6.0 with the following extensions:
67+
- `x = x` is an allowed form of ATOMIC UPDATE.
68+
This is motivated by the fact that the equivalent forms `x = x+0` or `x = x*1` are allowed.
69+
- Explicit type conversions are allowed in ATOMIC READ, WRITE or UPDATE constructs, and in the capture statement in ATOMIC UPDATE CAPTURE.
70+
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.
71+
- A literal `.true.` or `.false.` is an allowed condition in ATOMIC UPDATE COMPARE. [1]
72+
- A logical variable is an allowed form of the condition even if its value is not computed within the ATOMIC UPDATE COMPARE construct [1].
73+
- `expr equalop x` is an allowed condition in ATOMIC UPDATE COMPARE. [1]
74+
75+
[1] Code generation for ATOMIC UPDATE COMPARE is not implemented yet.

flang/examples/FeatureList/FeatureList.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -445,13 +445,6 @@ struct NodeVisitor {
445445
READ_FEATURE(ObjectDecl)
446446
READ_FEATURE(OldParameterStmt)
447447
READ_FEATURE(OmpAlignedClause)
448-
READ_FEATURE(OmpAtomic)
449-
READ_FEATURE(OmpAtomicCapture)
450-
READ_FEATURE(OmpAtomicCapture::Stmt1)
451-
READ_FEATURE(OmpAtomicCapture::Stmt2)
452-
READ_FEATURE(OmpAtomicRead)
453-
READ_FEATURE(OmpAtomicUpdate)
454-
READ_FEATURE(OmpAtomicWrite)
455448
READ_FEATURE(OmpBeginBlockDirective)
456449
READ_FEATURE(OmpBeginLoopDirective)
457450
READ_FEATURE(OmpBeginSectionsDirective)
@@ -480,7 +473,6 @@ struct NodeVisitor {
480473
READ_FEATURE(OmpIterationOffset)
481474
READ_FEATURE(OmpIterationVector)
482475
READ_FEATURE(OmpEndAllocators)
483-
READ_FEATURE(OmpEndAtomic)
484476
READ_FEATURE(OmpEndBlockDirective)
485477
READ_FEATURE(OmpEndCriticalDirective)
486478
READ_FEATURE(OmpEndLoopDirective)
@@ -566,8 +558,6 @@ struct NodeVisitor {
566558
READ_FEATURE(OpenMPDeclareTargetConstruct)
567559
READ_FEATURE(OmpMemoryOrderType)
568560
READ_FEATURE(OmpMemoryOrderClause)
569-
READ_FEATURE(OmpAtomicClause)
570-
READ_FEATURE(OmpAtomicClauseList)
571561
READ_FEATURE(OmpAtomicDefaultMemOrderClause)
572562
READ_FEATURE(OpenMPFlushConstruct)
573563
READ_FEATURE(OpenMPLoopConstruct)

flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -74,25 +74,19 @@ SourcePosition OpenMPCounterVisitor::getLocation(const OpenMPConstruct &c) {
7474
// the directive field.
7575
[&](const auto &c) -> SourcePosition {
7676
const CharBlock &source{std::get<0>(c.t).source};
77-
return (parsing->allCooked().GetSourcePositionRange(source))->first;
77+
return parsing->allCooked().GetSourcePositionRange(source)->first;
7878
},
7979
[&](const OpenMPAtomicConstruct &c) -> SourcePosition {
80-
return std::visit(
81-
[&](const auto &o) -> SourcePosition {
82-
const CharBlock &source{std::get<Verbatim>(o.t).source};
83-
return parsing->allCooked()
84-
.GetSourcePositionRange(source)
85-
->first;
86-
},
87-
c.u);
80+
const CharBlock &source{c.source};
81+
return parsing->allCooked().GetSourcePositionRange(source)->first;
8882
},
8983
[&](const OpenMPSectionConstruct &c) -> SourcePosition {
9084
const CharBlock &source{c.source};
91-
return (parsing->allCooked().GetSourcePositionRange(source))->first;
85+
return parsing->allCooked().GetSourcePositionRange(source)->first;
9286
},
9387
[&](const OpenMPUtilityConstruct &c) -> SourcePosition {
9488
const CharBlock &source{c.source};
95-
return (parsing->allCooked().GetSourcePositionRange(source))->first;
89+
return parsing->allCooked().GetSourcePositionRange(source)->first;
9690
},
9791
},
9892
c.u);
@@ -157,14 +151,9 @@ std::string OpenMPCounterVisitor::getName(const OpenMPConstruct &c) {
157151
return normalize_construct_name(source.ToString());
158152
},
159153
[&](const OpenMPAtomicConstruct &c) -> std::string {
160-
return std::visit(
161-
[&](const auto &c) {
162-
// Get source from the verbatim fields
163-
const CharBlock &source{std::get<Verbatim>(c.t).source};
164-
return "atomic-" +
165-
normalize_construct_name(source.ToString());
166-
},
167-
c.u);
154+
auto &dirSpec = std::get<OmpDirectiveSpecification>(c.t);
155+
auto &dirName = std::get<OmpDirectiveName>(dirSpec.t);
156+
return normalize_construct_name(dirName.source.ToString());
168157
},
169158
[&](const OpenMPUtilityConstruct &c) -> std::string {
170159
const CharBlock &source{c.source};

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -532,15 +532,6 @@ class ParseTreeDumper {
532532
NODE(parser, OmpAtClause)
533533
NODE_ENUM(OmpAtClause, ActionTime)
534534
NODE_ENUM(OmpSeverityClause, Severity)
535-
NODE(parser, OmpAtomic)
536-
NODE(parser, OmpAtomicCapture)
537-
NODE(OmpAtomicCapture, Stmt1)
538-
NODE(OmpAtomicCapture, Stmt2)
539-
NODE(parser, OmpAtomicCompare)
540-
NODE(parser, OmpAtomicCompareIfStmt)
541-
NODE(parser, OmpAtomicRead)
542-
NODE(parser, OmpAtomicUpdate)
543-
NODE(parser, OmpAtomicWrite)
544535
NODE(parser, OmpBeginBlockDirective)
545536
NODE(parser, OmpBeginLoopDirective)
546537
NODE(parser, OmpBeginSectionsDirective)
@@ -587,7 +578,6 @@ class ParseTreeDumper {
587578
NODE(parser, OmpDoacrossClause)
588579
NODE(parser, OmpDestroyClause)
589580
NODE(parser, OmpEndAllocators)
590-
NODE(parser, OmpEndAtomic)
591581
NODE(parser, OmpEndBlockDirective)
592582
NODE(parser, OmpEndCriticalDirective)
593583
NODE(parser, OmpEndLoopDirective)
@@ -716,8 +706,6 @@ class ParseTreeDumper {
716706
NODE(parser, OpenMPDeclareMapperConstruct)
717707
NODE_ENUM(common, OmpMemoryOrderType)
718708
NODE(parser, OmpMemoryOrderClause)
719-
NODE(parser, OmpAtomicClause)
720-
NODE(parser, OmpAtomicClauseList)
721709
NODE(parser, OmpAtomicDefaultMemOrderClause)
722710
NODE(parser, OpenMPDepobjConstruct)
723711
NODE(parser, OpenMPUtilityConstruct)

flang/include/flang/Parser/parse-tree.h

Lines changed: 27 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4857,94 +4857,37 @@ struct OmpMemoryOrderClause {
48574857
CharBlock source;
48584858
};
48594859

4860-
// 2.17.7 Atomic construct
4861-
// atomic-clause -> memory-order-clause | HINT(hint-expression) |
4862-
// FAIL(memory-order)
4863-
struct OmpAtomicClause {
4864-
UNION_CLASS_BOILERPLATE(OmpAtomicClause);
4865-
CharBlock source;
4866-
std::variant<OmpMemoryOrderClause, OmpFailClause, OmpHintClause> u;
4867-
};
4868-
4869-
// atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
4870-
struct OmpAtomicClauseList {
4871-
WRAPPER_CLASS_BOILERPLATE(OmpAtomicClauseList, std::list<OmpAtomicClause>);
4872-
CharBlock source;
4873-
};
4874-
4875-
// END ATOMIC
4876-
EMPTY_CLASS(OmpEndAtomic);
4877-
4878-
// ATOMIC READ
4879-
struct OmpAtomicRead {
4880-
TUPLE_CLASS_BOILERPLATE(OmpAtomicRead);
4881-
CharBlock source;
4882-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4883-
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4884-
t;
4885-
};
4886-
4887-
// ATOMIC WRITE
4888-
struct OmpAtomicWrite {
4889-
TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite);
4890-
CharBlock source;
4891-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4892-
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4893-
t;
4894-
};
4895-
4896-
// ATOMIC UPDATE
4897-
struct OmpAtomicUpdate {
4898-
TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate);
4899-
CharBlock source;
4900-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4901-
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4902-
t;
4903-
};
4904-
4905-
// ATOMIC CAPTURE
4906-
struct OmpAtomicCapture {
4907-
TUPLE_CLASS_BOILERPLATE(OmpAtomicCapture);
4908-
CharBlock source;
4909-
WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
4910-
WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
4911-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList, Stmt1, Stmt2,
4912-
OmpEndAtomic>
4913-
t;
4914-
};
4915-
4916-
struct OmpAtomicCompareIfStmt {
4917-
UNION_CLASS_BOILERPLATE(OmpAtomicCompareIfStmt);
4918-
std::variant<common::Indirection<IfStmt>, common::Indirection<IfConstruct>> u;
4919-
};
4920-
4921-
// ATOMIC COMPARE (OpenMP 5.1, OPenMP 5.2 spec: 15.8.4)
4922-
struct OmpAtomicCompare {
4923-
TUPLE_CLASS_BOILERPLATE(OmpAtomicCompare);
4860+
struct OpenMPAtomicConstruct {
4861+
llvm::omp::Clause GetKind() const;
4862+
bool IsCapture() const;
4863+
bool IsCompare() const;
4864+
TUPLE_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
49244865
CharBlock source;
4925-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4926-
OmpAtomicCompareIfStmt, std::optional<OmpEndAtomic>>
4866+
std::tuple<OmpDirectiveSpecification, Block,
4867+
std::optional<OmpDirectiveSpecification>>
49274868
t;
4928-
};
49294869

4930-
// ATOMIC
4931-
struct OmpAtomic {
4932-
TUPLE_CLASS_BOILERPLATE(OmpAtomic);
4933-
CharBlock source;
4934-
std::tuple<Verbatim, OmpAtomicClauseList, Statement<AssignmentStmt>,
4935-
std::optional<OmpEndAtomic>>
4936-
t;
4937-
};
4870+
// Information filled out during semantic checks to avoid duplication
4871+
// of analyses.
4872+
struct Analysis {
4873+
static constexpr int None = 0;
4874+
static constexpr int Read = 1;
4875+
static constexpr int Write = 2;
4876+
static constexpr int Update = Read | Write;
4877+
static constexpr int Action = 3; // Bitmask for None, Read, Write, Update
4878+
static constexpr int IfTrue = 4;
4879+
static constexpr int IfFalse = 8;
4880+
static constexpr int Condition = 12; // Bitmask for IfTrue, IfFalse
4881+
4882+
struct Op {
4883+
int what;
4884+
AssignmentStmt::TypedAssignment assign;
4885+
};
4886+
TypedExpr atom, cond;
4887+
Op op0, op1;
4888+
};
49384889

4939-
// 2.17.7 atomic ->
4940-
// ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] |
4941-
// ATOMIC [atomic-clause-list]
4942-
// atomic-construct -> READ | WRITE | UPDATE | CAPTURE | COMPARE
4943-
struct OpenMPAtomicConstruct {
4944-
UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
4945-
std::variant<OmpAtomicRead, OmpAtomicWrite, OmpAtomicCapture, OmpAtomicUpdate,
4946-
OmpAtomicCompare, OmpAtomic>
4947-
u;
4890+
mutable Analysis analysis;
49484891
};
49494892

49504893
// OpenMP directives that associate with loop(s)

0 commit comments

Comments
 (0)