[flang-commits] [flang] [llvm] [flang][OpenMP] Overhaul implementation of ATOMIC construct (PR #137852)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Mon Jun 2 06:22:33 PDT 2025
================
@@ -2666,422 +2673,1391 @@ void OmpStructureChecker::Leave(const parser::OmpEndBlockDirective &x) {
}
}
-inline void OmpStructureChecker::ErrIfAllocatableVariable(
- const parser::Variable &var) {
- // Err out if the given symbol has
- // ALLOCATABLE attribute
- if (const auto *e{GetExpr(context_, var)})
- for (const Symbol &symbol : evaluate::CollectSymbols(*e))
- if (IsAllocatable(symbol)) {
- const auto &designator =
- std::get<common::Indirection<parser::Designator>>(var.u);
- const auto *dataRef =
- std::get_if<parser::DataRef>(&designator.value().u);
- const parser::Name *name =
- dataRef ? std::get_if<parser::Name>(&dataRef->u) : nullptr;
- if (name)
- context_.Say(name->source,
- "%s must not have ALLOCATABLE "
- "attribute"_err_en_US,
- name->ToString());
+/// parser::Block is a list of executable constructs, parser::BlockConstruct
+/// is Fortran's BLOCK/ENDBLOCK construct.
+/// Strip the outermost BlockConstructs, return the reference to the Block
+/// in the executable part of the innermost of the stripped constructs.
+/// Specifically, if the given `block` has a single entry (it's a list), and
+/// the entry is a BlockConstruct, get the Block contained within. Repeat
+/// this step as many times as possible.
+static const parser::Block &GetInnermostExecPart(const parser::Block &block) {
+ const parser::Block *iter{&block};
+ while (iter->size() == 1) {
+ const parser::ExecutionPartConstruct &ep{iter->front()};
+ if (auto *exec{std::get_if<parser::ExecutableConstruct>(&ep.u)}) {
+ using BlockConstruct = common::Indirection<parser::BlockConstruct>;
+ if (auto *bc{std::get_if<BlockConstruct>(&exec->u)}) {
+ iter = &std::get<parser::Block>(bc->value().t);
+ continue;
}
+ }
+ break;
+ }
+ return *iter;
}
-inline void OmpStructureChecker::ErrIfLHSAndRHSSymbolsMatch(
- const parser::Variable &var, const parser::Expr &expr) {
- // Err out if the symbol on the LHS is also used on the RHS of the assignment
- // statement
- const auto *e{GetExpr(context_, expr)};
- const auto *v{GetExpr(context_, var)};
- if (e && v) {
- auto vSyms{evaluate::GetSymbolVector(*v)};
- const Symbol &varSymbol = vSyms.front();
- for (const Symbol &symbol : evaluate::GetSymbolVector(*e)) {
- if (varSymbol == symbol) {
- const common::Indirection<parser::Designator> *designator =
- std::get_if<common::Indirection<parser::Designator>>(&expr.u);
- if (designator) {
- auto *z{var.typedExpr.get()};
- auto *c{expr.typedExpr.get()};
- if (z->v == c->v) {
- context_.Say(expr.source,
- "RHS expression on atomic assignment statement cannot access '%s'"_err_en_US,
- var.GetSource());
- }
+// There is no consistent way to get the source of a given ActionStmt, so
+// extract the source information from Statement<ActionStmt> when we can,
+// and keep it around for error reporting in further analyses.
+struct SourcedActionStmt {
+ const parser::ActionStmt *stmt{nullptr};
+ parser::CharBlock source;
+
+ operator bool() const { return stmt != nullptr; }
+};
+
+struct AnalyzedCondStmt {
+ SomeExpr cond{evaluate::NullPointer{}}; // Default ctor is deleted
+ parser::CharBlock source;
+ SourcedActionStmt ift, iff;
+};
+
+static SourcedActionStmt GetActionStmt(
+ const parser::ExecutionPartConstruct *x) {
+ if (x == nullptr) {
+ return SourcedActionStmt{};
+ }
+ if (auto *exec{std::get_if<parser::ExecutableConstruct>(&x->u)}) {
+ using ActionStmt = parser::Statement<parser::ActionStmt>;
+ if (auto *stmt{std::get_if<ActionStmt>(&exec->u)}) {
+ return SourcedActionStmt{&stmt->statement, stmt->source};
+ }
+ }
+ return SourcedActionStmt{};
+}
+
+static SourcedActionStmt GetActionStmt(const parser::Block &block) {
+ if (block.size() == 1) {
+ return GetActionStmt(&block.front());
+ }
+ return SourcedActionStmt{};
+}
+
+// Compute the `evaluate::Assignment` from parser::ActionStmt. The assumption
+// is that the ActionStmt will be either an assignment or a pointer-assignment,
+// otherwise return std::nullopt.
+// Note: This function can return std::nullopt on [Pointer]AssignmentStmt where
+// the "typedAssignment" is unset. This can happen is there are semantic errors
----------------
kparzysz wrote:
Done
https://github.com/llvm/llvm-project/pull/137852
More information about the flang-commits
mailing list