Skip to content

Commit fdc6376

Browse files
committed
[flang][OpenMP] Overhaul implementation of ATOMIC construct
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" represen- tations, 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 637d237 commit fdc6376

34 files changed

+2838
-1769
lines changed

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

-12
Original file line numberDiff line numberDiff line change
@@ -526,15 +526,6 @@ class ParseTreeDumper {
526526
NODE(parser, OmpAtClause)
527527
NODE_ENUM(OmpAtClause, ActionTime)
528528
NODE_ENUM(OmpSeverityClause, Severity)
529-
NODE(parser, OmpAtomic)
530-
NODE(parser, OmpAtomicCapture)
531-
NODE(OmpAtomicCapture, Stmt1)
532-
NODE(OmpAtomicCapture, Stmt2)
533-
NODE(parser, OmpAtomicCompare)
534-
NODE(parser, OmpAtomicCompareIfStmt)
535-
NODE(parser, OmpAtomicRead)
536-
NODE(parser, OmpAtomicUpdate)
537-
NODE(parser, OmpAtomicWrite)
538529
NODE(parser, OmpBeginBlockDirective)
539530
NODE(parser, OmpBeginLoopDirective)
540531
NODE(parser, OmpBeginSectionsDirective)
@@ -581,7 +572,6 @@ class ParseTreeDumper {
581572
NODE(parser, OmpDoacrossClause)
582573
NODE(parser, OmpDestroyClause)
583574
NODE(parser, OmpEndAllocators)
584-
NODE(parser, OmpEndAtomic)
585575
NODE(parser, OmpEndBlockDirective)
586576
NODE(parser, OmpEndCriticalDirective)
587577
NODE(parser, OmpEndLoopDirective)
@@ -709,8 +699,6 @@ class ParseTreeDumper {
709699
NODE(parser, OpenMPDeclareMapperConstruct)
710700
NODE_ENUM(common, OmpMemoryOrderType)
711701
NODE(parser, OmpMemoryOrderClause)
712-
NODE(parser, OmpAtomicClause)
713-
NODE(parser, OmpAtomicClauseList)
714702
NODE(parser, OmpAtomicDefaultMemOrderClause)
715703
NODE(parser, OpenMPDepobjConstruct)
716704
NODE(parser, OpenMPUtilityConstruct)

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

+27-84
Original file line numberDiff line numberDiff line change
@@ -4835,94 +4835,37 @@ struct OmpMemoryOrderClause {
48354835
CharBlock source;
48364836
};
48374837

4838-
// 2.17.7 Atomic construct
4839-
// atomic-clause -> memory-order-clause | HINT(hint-expression) |
4840-
// FAIL(memory-order)
4841-
struct OmpAtomicClause {
4842-
UNION_CLASS_BOILERPLATE(OmpAtomicClause);
4843-
CharBlock source;
4844-
std::variant<OmpMemoryOrderClause, OmpFailClause, OmpHintClause> u;
4845-
};
4846-
4847-
// atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
4848-
struct OmpAtomicClauseList {
4849-
WRAPPER_CLASS_BOILERPLATE(OmpAtomicClauseList, std::list<OmpAtomicClause>);
4850-
CharBlock source;
4851-
};
4852-
4853-
// END ATOMIC
4854-
EMPTY_CLASS(OmpEndAtomic);
4855-
4856-
// ATOMIC READ
4857-
struct OmpAtomicRead {
4858-
TUPLE_CLASS_BOILERPLATE(OmpAtomicRead);
4859-
CharBlock source;
4860-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4861-
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4862-
t;
4863-
};
4864-
4865-
// ATOMIC WRITE
4866-
struct OmpAtomicWrite {
4867-
TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite);
4868-
CharBlock source;
4869-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4870-
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4871-
t;
4872-
};
4873-
4874-
// ATOMIC UPDATE
4875-
struct OmpAtomicUpdate {
4876-
TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate);
4877-
CharBlock source;
4878-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4879-
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
4880-
t;
4881-
};
4882-
4883-
// ATOMIC CAPTURE
4884-
struct OmpAtomicCapture {
4885-
TUPLE_CLASS_BOILERPLATE(OmpAtomicCapture);
4886-
CharBlock source;
4887-
WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
4888-
WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
4889-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList, Stmt1, Stmt2,
4890-
OmpEndAtomic>
4891-
t;
4892-
};
4893-
4894-
struct OmpAtomicCompareIfStmt {
4895-
UNION_CLASS_BOILERPLATE(OmpAtomicCompareIfStmt);
4896-
std::variant<common::Indirection<IfStmt>, common::Indirection<IfConstruct>> u;
4897-
};
4898-
4899-
// ATOMIC COMPARE (OpenMP 5.1, OPenMP 5.2 spec: 15.8.4)
4900-
struct OmpAtomicCompare {
4901-
TUPLE_CLASS_BOILERPLATE(OmpAtomicCompare);
4838+
struct OpenMPAtomicConstruct {
4839+
llvm::omp::Clause GetKind() const;
4840+
bool IsCapture() const;
4841+
bool IsCompare() const;
4842+
TUPLE_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
49024843
CharBlock source;
4903-
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4904-
OmpAtomicCompareIfStmt, std::optional<OmpEndAtomic>>
4844+
std::tuple<OmpDirectiveSpecification, Block,
4845+
std::optional<OmpDirectiveSpecification>>
49054846
t;
4906-
};
49074847

4908-
// ATOMIC
4909-
struct OmpAtomic {
4910-
TUPLE_CLASS_BOILERPLATE(OmpAtomic);
4911-
CharBlock source;
4912-
std::tuple<Verbatim, OmpAtomicClauseList, Statement<AssignmentStmt>,
4913-
std::optional<OmpEndAtomic>>
4914-
t;
4915-
};
4848+
// Information filled out during semantic checks to avoid duplication
4849+
// of analyses.
4850+
struct Analysis {
4851+
static constexpr int None = 0;
4852+
static constexpr int Read = 1;
4853+
static constexpr int Write = 2;
4854+
static constexpr int Update = Read | Write;
4855+
static constexpr int Action = 3; // Bitmask for None, Read, Write, Update
4856+
static constexpr int IfTrue = 4;
4857+
static constexpr int IfFalse = 8;
4858+
static constexpr int Condition = 12; // Bitmask for IfTrue, IfFalse
4859+
4860+
struct Op {
4861+
int what;
4862+
TypedExpr expr;
4863+
};
4864+
TypedExpr atom, cond;
4865+
Op op0, op1;
4866+
};
49164867

4917-
// 2.17.7 atomic ->
4918-
// ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] |
4919-
// ATOMIC [atomic-clause-list]
4920-
// atomic-construct -> READ | WRITE | UPDATE | CAPTURE | COMPARE
4921-
struct OpenMPAtomicConstruct {
4922-
UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
4923-
std::variant<OmpAtomicRead, OmpAtomicWrite, OmpAtomicCapture, OmpAtomicUpdate,
4924-
OmpAtomicCompare, OmpAtomic>
4925-
u;
4868+
mutable Analysis analysis;
49264869
};
49274870

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

flang/include/flang/Semantics/tools.h

+16
Original file line numberDiff line numberDiff line change
@@ -782,5 +782,21 @@ inline bool checkForSymbolMatch(
782782
}
783783
return false;
784784
}
785+
786+
/// If the top-level operation (ignoring parentheses) is either an
787+
/// evaluate::FunctionRef, or a specialization of evaluate::Operation,
788+
/// then return the list of arguments (wrapped in SomeExpr). Otherwise,
789+
/// return the "expr" but with top-level parentheses stripped.
790+
std::vector<SomeExpr> GetOpenMPTopLevelArguments(const SomeExpr &expr);
791+
792+
/// Both "expr" and "x" have the form of SomeType(SomeKind(...)[1]).
793+
/// Check if "expr" is
794+
/// SomeType(SomeKind(Type(
795+
/// Convert
796+
/// SomeKind(...)[2])))
797+
/// where SomeKind(...) [1] and [2] are equal, and the Convert preserves
798+
/// TypeCategory.
799+
bool IsSameOrResizeOf(const SomeExpr &expr, const SomeExpr &x);
800+
785801
} // namespace Fortran::semantics
786802
#endif // FORTRAN_SEMANTICS_TOOLS_H_

flang/lib/Lower/OpenMP/DataSharingProcessor.cpp

+20-20
Original file line numberDiff line numberDiff line change
@@ -332,26 +332,26 @@ getSource(const semantics::SemanticsContext &semaCtx,
332332
const parser::CharBlock *source = nullptr;
333333

334334
auto ompConsVisit = [&](const parser::OpenMPConstruct &x) {
335-
std::visit(common::visitors{
336-
[&](const parser::OpenMPSectionsConstruct &x) {
337-
source = &std::get<0>(x.t).source;
338-
},
339-
[&](const parser::OpenMPLoopConstruct &x) {
340-
source = &std::get<0>(x.t).source;
341-
},
342-
[&](const parser::OpenMPBlockConstruct &x) {
343-
source = &std::get<0>(x.t).source;
344-
},
345-
[&](const parser::OpenMPCriticalConstruct &x) {
346-
source = &std::get<0>(x.t).source;
347-
},
348-
[&](const parser::OpenMPAtomicConstruct &x) {
349-
std::visit([&](const auto &x) { source = &x.source; },
350-
x.u);
351-
},
352-
[&](const auto &x) { source = &x.source; },
353-
},
354-
x.u);
335+
std::visit(
336+
common::visitors{
337+
[&](const parser::OpenMPSectionsConstruct &x) {
338+
source = &std::get<0>(x.t).source;
339+
},
340+
[&](const parser::OpenMPLoopConstruct &x) {
341+
source = &std::get<0>(x.t).source;
342+
},
343+
[&](const parser::OpenMPBlockConstruct &x) {
344+
source = &std::get<0>(x.t).source;
345+
},
346+
[&](const parser::OpenMPCriticalConstruct &x) {
347+
source = &std::get<0>(x.t).source;
348+
},
349+
[&](const parser::OpenMPAtomicConstruct &x) {
350+
source = &std::get<parser::OmpDirectiveSpecification>(x.t).source;
351+
},
352+
[&](const auto &x) { source = &x.source; },
353+
},
354+
x.u);
355355
};
356356

357357
eval.visit(common::visitors{

0 commit comments

Comments
 (0)