[flang-commits] [flang] [flang][OpenMP] Implement flexible OpenMP clause representation (PR #81621)
Sergio Afonso via flang-commits
flang-commits at lists.llvm.org
Tue Feb 20 04:28:38 PST 2024
================
@@ -142,6 +142,1122 @@ static void genNestedEvaluations(Fortran::lower::AbstractConverter &converter,
converter.genEval(e);
}
+//===----------------------------------------------------------------------===//
+// Clauses
+//===----------------------------------------------------------------------===//
+
+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 namespace Fortran;
+using SomeType = evaluate::SomeType;
+using SomeExpr = semantics::SomeExpr;
+using MaybeExpr = semantics::MaybeExpr;
+
+template <typename T> //
+using List = std::vector<T>;
+
+struct SymDsgExtractor {
+ using SymDsg = std::tuple<semantics::Symbol *, MaybeExpr>;
+
+ template <typename T> //
+ static T &&AsRvalueRef(T &&t) {
+ return std::move(t);
+ }
+ template <typename T> //
+ static T AsRvalueRef(const T &t) {
+ return t;
+ }
+
+ template <typename T> //
+ static SymDsg visit(T &&) {
+ // Use this to see missing overloads:
+ // llvm::errs() << "NULL: " << __PRETTY_FUNCTION__ << '\n';
+ return SymDsg{};
+ }
+
+ template <typename T> //
+ static SymDsg visit(const evaluate::Designator<T> &e) {
+ // 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 std::make_tuple(const_cast<semantics::Symbol *>(e.GetLastSymbol()),
+ evaluate::AsGenericExpr(AsRvalueRef(e)));
+ }
+
+ static SymDsg visit(const evaluate::ProcedureDesignator &e) {
+ // See comment above regarding const_cast.
+ return std::make_tuple(const_cast<semantics::Symbol *>(e.GetSymbol()),
+ std::nullopt);
+ }
+
+ template <typename T> //
+ static SymDsg visit(const evaluate::Expr<T> &e) {
+ return std::visit([](auto &&s) { return visit(s); }, e.u);
+ }
+
+ static bool verify(const SymDsg &sd) {
+ const semantics::Symbol *symbol = std::get<0>(sd);
+ assert(symbol && "Expecting Symbol");
+ auto &maybeDsg = std::get<1>(sd);
+ if (!maybeDsg)
+ return true;
+ std::optional<evaluate::DataRef> maybeRef =
+ evaluate::ExtractDataRef(*maybeDsg);
+ if (maybeRef) {
+ assert(&maybeRef->GetLastSymbol() == symbol &&
+ "Designator not for symbol");
+ return true;
+ }
+
+ // This could still be a Substring or ComplexPart, but at least Substring
+ // is not allowed in OpenMP.
+ maybeDsg->dump();
+ llvm_unreachable("Expecting DataRef");
+ }
+};
+
+SymDsgExtractor::SymDsg getSymbolAndDesignator(const MaybeExpr &expr) {
+ if (!expr)
+ return SymDsgExtractor::SymDsg{};
+ return std::visit([](auto &&s) { return SymDsgExtractor::visit(s); },
+ expr->u);
+}
+
+struct Object {
+ semantics::Symbol *sym; // symbol
+ MaybeExpr dsg; // designator ending with symbol
+};
+
+using ObjectList = List<Object>;
+
+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};
+ }
+ evaluate::ExpressionAnalyzer ea{semaCtx};
+ SymDsgExtractor::SymDsg sd = std::visit(
+ [&](auto &&s) { return getSymbolAndDesignator(ea.Analyze(s)); },
+ object.u);
+ SymDsgExtractor::verify(sd);
+ return Object{std::get<0>(sd), std::move(std::get<1>(sd))};
+}
+
+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};
+ SymDsgExtractor::SymDsg 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};
+ SymDsgExtractor::SymDsg sd = getSymbolAndDesignator(ea.Analyze(comp));
+ SymDsgExtractor::verify(sd);
+ return Object{std::get<0>(sd), std::move(std::get<1>(sd))};
+}
+
+auto makeObject(semantics::SemanticsContext &semaCtx) {
+ return [&](auto &&s) { return makeObject(s, semaCtx); };
+}
+
+template <typename T>
+SomeExpr makeExpr(T &&inp, semantics::SemanticsContext &semaCtx) {
+ auto maybeExpr = evaluate::ExpressionAnalyzer(semaCtx).Analyze(inp);
+ assert(maybeExpr);
+ return std::move(*maybeExpr);
+}
+
+auto makeExpr(semantics::SemanticsContext &semaCtx) {
+ return [&](auto &&s) { return makeExpr(s, semaCtx); };
+}
+
+template <typename C, typename F,
+ typename E = typename llvm::remove_cvref_t<C>::value_type,
+ typename R = std::invoke_result_t<F, E>>
+List<R> makeList(C &&container, F &&func) {
+ List<R> v;
----------------
skatrak wrote:
It should be possible (if `container` becomes an `llvm::ArrayRef`) to pre-allocate space in `v` to prevent multiple allocations below if the container has many elements (i.e. `v.reserve(container.size())`).
https://github.com/llvm/llvm-project/pull/81621
More information about the flang-commits
mailing list