[flang-commits] [flang] [flang][OpenMP] Implement flexible OpenMP clause representation (PR #81621)
Sergio Afonso via flang-commits
flang-commits at lists.llvm.org
Tue Mar 12 07:08:48 PDT 2024
================
@@ -0,0 +1,727 @@
+//===-- Clauses.cpp -- OpenMP clause handling -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Clauses.h"
+
+#include "flang/Common/idioms.h"
+#include "flang/Evaluate/expression.h"
+#include "flang/Parser/parse-tree.h"
+#include "flang/Semantics/expression.h"
+#include "flang/Semantics/symbol.h"
+
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+
+#include <list>
+#include <optional>
+#include <tuple>
+#include <utility>
+#include <variant>
+
+namespace detail {
+template <typename C>
+llvm::omp::Clause getClauseIdForClass(C &&) {
+ using namespace Fortran;
+ using A = llvm::remove_cvref_t<C>; // A is referenced in OMP.inc
+ // The code included below contains a sequence of checks like the following
+ // for each OpenMP clause
+ // if constexpr (std::is_same_v<A, parser::OmpClause::AcqRel>)
+ // return llvm::omp::Clause::OMPC_acq_rel;
+ // [...]
+#define GEN_FLANG_CLAUSE_PARSER_KIND_MAP
+#include "llvm/Frontend/OpenMP/OMP.inc"
+}
+} // namespace detail
+
+static llvm::omp::Clause getClauseId(const Fortran::parser::OmpClause &clause) {
+ return std::visit([](auto &&s) { return detail::getClauseIdForClass(s); },
+ clause.u);
+}
+
+namespace omp {
+using SymbolWithDesignator = std::tuple<semantics::Symbol *, MaybeExpr>;
+
+struct SymDsgExtractor {
+ template <typename T>
+ static T &&AsRvalueRef(T &&t) {
+ return std::move(t);
+ }
+ template <typename T>
+ static T AsRvalueRef(const T &t) {
+ return t;
+ }
+
+ static semantics::Symbol *symbol_addr(const evaluate::SymbolRef &ref) {
+ // Symbols cannot be created after semantic checks, so all symbol
+ // pointers that are non-null must point to one of those pre-existing
+ // objects. Throughout the code, symbols are often pointed to by
+ // non-const pointers, so there is no harm in casting the constness
+ // away.
+ return const_cast<semantics::Symbol *>(&ref.get());
+ }
+
+ template <typename T>
+ static SymbolWithDesignator visit(T &&) {
+ // Use this to see missing overloads:
+ // llvm::errs() << "NULL: " << __PRETTY_FUNCTION__ << '\n';
+ return SymbolWithDesignator{};
+ }
+
+ template <typename T>
+ static SymbolWithDesignator visit(const evaluate::Designator<T> &e) {
+ return std::make_tuple(symbol_addr(*e.GetLastSymbol()),
+ evaluate::AsGenericExpr(AsRvalueRef(e)));
+ }
+
+ static SymbolWithDesignator visit(const evaluate::ProcedureDesignator &e) {
+ return std::make_tuple(symbol_addr(*e.GetSymbol()), std::nullopt);
+ }
+
+ template <typename T>
+ static SymbolWithDesignator visit(const evaluate::Expr<T> &e) {
+ return std::visit([](auto &&s) { return visit(s); }, e.u);
+ }
+
+ static void verify(const SymbolWithDesignator &sd) {
+ const semantics::Symbol *symbol = std::get<0>(sd);
+ assert(symbol && "Expecting symbol");
+ auto &maybeDsg = std::get<1>(sd);
+ if (!maybeDsg)
+ return; // Symbol with no designator -> OK
+ std::optional<evaluate::DataRef> maybeRef =
+ evaluate::ExtractDataRef(*maybeDsg);
+ if (maybeRef) {
+ if (&maybeRef->GetLastSymbol() == symbol)
+ return; // Symbol with a designator for it -> OK
+ llvm_unreachable("Expecting designator for given symbol");
+ } else {
+ // This could still be a Substring or ComplexPart, but at least Substring
+ // is not allowed in OpenMP.
+ maybeDsg->dump();
+ llvm_unreachable("Expecting DataRef designator");
+ }
+ }
+};
+
+SymbolWithDesignator getSymbolAndDesignator(const MaybeExpr &expr) {
+ if (!expr)
+ return SymbolWithDesignator{};
+ return std::visit([](auto &&s) { return SymDsgExtractor::visit(s); },
+ expr->u);
+}
+
+Object makeObject(const parser::Name &name,
+ semantics::SemanticsContext &semaCtx) {
+ assert(name.symbol && "Expecting Symbol");
+ return Object{name.symbol, std::nullopt};
+}
+
+Object makeObject(const parser::Designator &dsg,
+ semantics::SemanticsContext &semaCtx) {
+ evaluate::ExpressionAnalyzer ea{semaCtx};
+ SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(dsg));
+ SymDsgExtractor::verify(sd);
+ return Object{std::get<0>(sd), std::move(std::get<1>(sd))};
+}
+
+Object makeObject(const parser::StructureComponent &comp,
+ semantics::SemanticsContext &semaCtx) {
+ evaluate::ExpressionAnalyzer ea{semaCtx};
+ SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(comp));
+ SymDsgExtractor::verify(sd);
+ return Object{std::get<0>(sd), std::move(std::get<1>(sd))};
+}
+
+Object makeObject(const parser::OmpObject &object,
+ semantics::SemanticsContext &semaCtx) {
+ // If object is a common block, expression analyzer won't be able to
+ // do anything.
+ if (const auto *name = std::get_if<parser::Name>(&object.u)) {
+ assert(name->symbol && "Expecting Symbol");
+ return Object{name->symbol, std::nullopt};
+ }
+ // OmpObject is std::variant<Designator, /*common block*/ Name>;
+ return makeObject(std::get<parser::Designator>(object.u), semaCtx);
+}
+
+std::optional<Object>
+getBaseObject(const Object &object,
+ Fortran::semantics::SemanticsContext &semaCtx) {
+ // If it's just the symbol, then there is no base.
+ if (!object.id())
+ return std::nullopt;
+
+ auto maybeRef = evaluate::ExtractDataRef(*object.ref());
+ if (!maybeRef)
+ return std::nullopt;
+
+ evaluate::DataRef ref = *maybeRef;
+
+ if (std::get_if<evaluate::SymbolRef>(&ref.u)) {
+ return std::nullopt;
+ } else if (auto *comp = std::get_if<evaluate::Component>(&ref.u)) {
+ const evaluate::DataRef &base = comp->base();
+ return Object{SymDsgExtractor::symbol_addr(base.GetLastSymbol()),
+ evaluate::AsGenericExpr(SymDsgExtractor::AsRvalueRef(base))};
+ } else if (auto *arr = std::get_if<evaluate::ArrayRef>(&ref.u)) {
+ const evaluate::NamedEntity &base = arr->base();
+ evaluate::ExpressionAnalyzer ea{semaCtx};
+ if (auto *comp = base.UnwrapComponent()) {
+ return Object{
+ SymDsgExtractor::symbol_addr(comp->symbol()),
+ ea.Designate(evaluate::DataRef{SymDsgExtractor::AsRvalueRef(*comp)})};
+ } else if (base.UnwrapSymbolRef()) {
+ return std::nullopt;
+ }
+ } else {
+ assert(std::holds_alternative<evaluate::CoarrayRef>(ref.u));
+ llvm_unreachable("Coarray reference not supported at the moment");
+ }
+ return std::nullopt;
+}
+
+namespace clause {
+// Helper objects
+#ifdef EMPTY_CLASS
+#undef EMPTY_CLASS
+#endif
+#define EMPTY_CLASS(cls) \
+ cls make(const parser::OmpClause::cls &, semantics::SemanticsContext &) { \
+ return cls{}; \
+ } \
+ [[maybe_unused]] extern int xyzzy_semicolon_absorber
+
+#ifdef WRAPPER_CLASS
+#undef WRAPPER_CLASS
+#endif
+#define WRAPPER_CLASS(cls, content) \
+ [[maybe_unused]] extern int xyzzy_semicolon_absorber
+#define GEN_FLANG_CLAUSE_PARSER_CLASSES
+#include "llvm/Frontend/OpenMP/OMP.inc"
+#undef EMPTY_CLASS
+#undef WRAPPER_CLASS
+
+using DefinedOperator = tomp::clause::DefinedOperatorT<SymIdent, SymReference>;
+using ProcedureDesignator =
+ tomp::clause::ProcedureDesignatorT<SymIdent, SymReference>;
+using ReductionOperator =
+ tomp::clause::ReductionOperatorT<SymIdent, SymReference>;
+
+DefinedOperator makeDefOp(const parser::DefinedOperator &inp,
+ semantics::SemanticsContext &semaCtx) {
+ return DefinedOperator{
+ std::visit(common::visitors{
+ [&](const parser::DefinedOpName &s) {
+ return DefinedOperator{DefinedOperator::DefinedOpName{
+ makeObject(s.v, semaCtx)}};
+ },
+ [&](const parser::DefinedOperator::IntrinsicOperator &s) {
+ return DefinedOperator{s};
+ },
+ },
+ inp.u),
+ };
+}
+
+ProcedureDesignator makeProcDsg(const parser::ProcedureDesignator &inp,
+ semantics::SemanticsContext &semaCtx) {
+ return ProcedureDesignator{std::visit(
+ common::visitors{
+ [&](const parser::Name &t) { return makeObject(t, semaCtx); },
+ [&](const parser::ProcComponentRef &t) {
+ return makeObject(t.v.thing, semaCtx);
+ },
+ },
+ inp.u)};
+}
+
+ReductionOperator makeRedOp(const parser::OmpReductionOperator &inp,
----------------
skatrak wrote:
```suggestion
ReductionOperator makeReductionOperator(const parser::OmpReductionOperator &inp,
```
https://github.com/llvm/llvm-project/pull/81621
More information about the flang-commits
mailing list