| //===-- flang/lib/Semantics/openmp-modifiers.cpp --------------------------===// | |
| // | |
| // 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 "flang/Semantics/openmp-modifiers.h" | |
| #include "flang/Parser/parse-tree.h" | |
| #include "llvm/ADT/ArrayRef.h" | |
| #include "llvm/Frontend/OpenMP/OMP.h" | |
| #include <algorithm> | |
| #include <cassert> | |
| #include <map> | |
| namespace Fortran::semantics { | |
| using namespace llvm::omp; | |
| /// Find the highest version that exists as a key in the given map, | |
| /// and is less than or equal to `version`. | |
| /// Account for "version" not being a value from getOpenMPVersions(). | |
| template <typename ValueTy> | |
| static unsigned findVersion( | |
| unsigned version, const std::map<unsigned, ValueTy> &map) { | |
| llvm::ArrayRef<unsigned> versions{llvm::omp::getOpenMPVersions()}; | |
| assert(!versions.empty() && "getOpenMPVersions returned empty list"); | |
| version = std::clamp(version, versions.front(), versions.back()); | |
| // std::map is sorted with respect to keys, by default in the ascending | |
| // order. | |
| unsigned found{0}; | |
| for (auto &[v, _] : map) { | |
| if (v <= version) { | |
| found = v; | |
| } else { | |
| break; | |
| } | |
| } | |
| // It can happen that the above search will not find any version, for | |
| // example when the minimum version in the map is higher than the current | |
| // version. This is really an error, but this situation should be handled | |
| // gracefully, so make some sensible choice and return it. | |
| if (found == 0) { | |
| found = !map.empty() ? map.begin()->first : versions.front(); | |
| } | |
| return found; | |
| } | |
| const OmpProperties &OmpModifierDescriptor::props(unsigned version) const { | |
| return props_.at(findVersion(version, props_)); | |
| } | |
| const OmpClauses &OmpModifierDescriptor::clauses(unsigned version) const { | |
| return clauses_.at(findVersion(version, clauses_)); | |
| } | |
| unsigned OmpModifierDescriptor::since(llvm::omp::Clause id) const { | |
| unsigned found{[&]() { | |
| for (auto &[v, cs] : clauses_) { | |
| if (cs.test(id)) { | |
| return v; | |
| } | |
| } | |
| return ~0u; | |
| }()}; | |
| return found <= 45 ? 0 : found; | |
| } | |
| // Note: The intent for these functions is to have them be automatically- | |
| // generated in the future. | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAccessGroup>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"access-group", | |
| /*props=*/ | |
| { | |
| {61, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {61, {Clause::OMPC_dyn_groupprivate}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlignment>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"alignment", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique, OmpProperty::Ultimate, OmpProperty::Post}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_aligned}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlignModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"align-modifier", | |
| /*props=*/ | |
| { | |
| {51, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {51, {Clause::OMPC_allocate}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor & | |
| OmpGetDescriptor<parser::OmpAllocatorComplexModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"allocator-complex-modifier", | |
| /*props=*/ | |
| { | |
| {51, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {51, {Clause::OMPC_allocate}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor & | |
| OmpGetDescriptor<parser::OmpAllocatorSimpleModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"allocator-simple-modifier", | |
| /*props=*/ | |
| { | |
| {50, {OmpProperty::Exclusive, OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {50, {Clause::OMPC_allocate}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlwaysModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"always-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAttachModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"attach-modifier", | |
| /*props=*/ | |
| { | |
| {61, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {61, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAutomapModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"automap-modifier", | |
| /*props=*/ | |
| { | |
| {60, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {60, {Clause::OMPC_enter}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpChunkModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"chunk-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_schedule}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpCloseModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"close-modifier", | |
| /*props=*/ | |
| { | |
| {50, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {50, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpContextSelector>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"context-selector", | |
| /*props=*/ | |
| { | |
| {50, {OmpProperty::Required, OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| // The MATCH clause takes a selector as an argument, not modifier. | |
| {50, {Clause::OMPC_when}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDeleteModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"delete-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique, OmpProperty::Ultimate}}, | |
| {60, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDependenceType>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"dependence-type", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Required, OmpProperty::Ultimate}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_depend}}, | |
| {51, {Clause::OMPC_depend, Clause::OMPC_update}}, | |
| {52, {Clause::OMPC_doacross}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDepinfoModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"depinfo-modifier", | |
| /*props=*/ | |
| { | |
| {60, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {60, {Clause::OMPC_init}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDimsModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"dims-modifier", | |
| /*props=*/ | |
| { | |
| {61, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {61, | |
| {Clause::OMPC_num_teams, Clause::OMPC_num_threads, | |
| Clause::OMPC_thread_limit}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDeviceModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"device-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_device}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor & | |
| OmpGetDescriptor<parser::OmpDirectiveNameModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"directive-name-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_if}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpExpectation>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"expectation", | |
| /*props=*/ | |
| { | |
| {51, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {51, {Clause::OMPC_from, Clause::OMPC_to}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpFallbackModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"fallback-modifier", | |
| /*props=*/ | |
| { | |
| {61, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {61, {Clause::OMPC_dyn_groupprivate}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpInteropType>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"interop-type", | |
| /*props=*/ | |
| { | |
| {52, {OmpProperty::Required}}, | |
| {60, {}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {52, {Clause::OMPC_init}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpIterator>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"iterator", | |
| /*props=*/ | |
| { | |
| {50, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {50, {Clause::OMPC_affinity, Clause::OMPC_depend}}, | |
| {51, | |
| {Clause::OMPC_affinity, Clause::OMPC_depend, Clause::OMPC_from, | |
| Clause::OMPC_map, Clause::OMPC_to}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor & | |
| OmpGetDescriptor<parser::OmpLastprivateModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"lastprivate-modifier", | |
| /*props=*/ | |
| { | |
| {50, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {50, {Clause::OMPC_lastprivate}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLinearModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"linear-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_linear}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLowerBound>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"lower-bound", | |
| /*props=*/ | |
| { | |
| {51, {OmpProperty::Unique, OmpProperty::Ultimate}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {51, {Clause::OMPC_num_teams}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> // | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapper>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"mapper", | |
| /*props=*/ | |
| { | |
| {50, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {50, {Clause::OMPC_from, Clause::OMPC_map, Clause::OMPC_to}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapType>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"map-type", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Ultimate}}, | |
| {60, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapTypeModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"map-type-modifier", | |
| /*props=*/ | |
| { | |
| {45, {}}, // Repeatable | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_map}}, | |
| {60, {}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpOrderModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"order-modifier", | |
| /*props=*/ | |
| { | |
| {51, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {51, {Clause::OMPC_order}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpOrderingModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"ordering-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_schedule}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPreferType>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"prefer-type", | |
| /*props=*/ | |
| { | |
| {52, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {52, {Clause::OMPC_init}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPrescriptiveness>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"prescriptiveness", | |
| /*props=*/ | |
| { | |
| {51, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {51, {Clause::OMPC_grainsize, Clause::OMPC_num_tasks}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPresentModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"present-modifier", | |
| /*props=*/ | |
| { | |
| {51, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {51, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor & | |
| OmpGetDescriptor<parser::OmpReductionIdentifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"reduction-identifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Required, OmpProperty::Ultimate}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_reduction}}, | |
| {50, | |
| {Clause::OMPC_in_reduction, Clause::OMPC_reduction, | |
| Clause::OMPC_task_reduction}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpReductionModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"reduction-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_reduction}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpRefModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"ref-modifier", | |
| /*props=*/ | |
| { | |
| {60, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {60, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpSelfModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"self-modifier", | |
| /*props=*/ | |
| { | |
| {60, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {60, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor & | |
| OmpGetDescriptor<parser::OmpStepComplexModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"step-complex-modifier", | |
| /*props=*/ | |
| { | |
| {52, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {52, {Clause::OMPC_linear}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpStepSimpleModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"step-simple-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| {52, {OmpProperty::Unique, OmpProperty::Exclusive}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_linear}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpTaskDependenceType>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"task-dependence-type", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Required, OmpProperty::Ultimate}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_depend}}, | |
| {51, {Clause::OMPC_depend, Clause::OMPC_update}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpVariableCategory>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"variable-category", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Required, OmpProperty::Unique}}, | |
| {50, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_defaultmap}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| template <> | |
| const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpxHoldModifier>() { | |
| static const OmpModifierDescriptor desc{ | |
| /*name=*/"ompx-hold-modifier", | |
| /*props=*/ | |
| { | |
| {45, {OmpProperty::Unique}}, | |
| }, | |
| /*clauses=*/ | |
| { | |
| {45, {Clause::OMPC_map}}, | |
| }, | |
| }; | |
| return desc; | |
| } | |
| } // namespace Fortran::semantics |