//===- OpenMP/OMPContext.h ----- OpenMP context helper functions - C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// /// \file /// /// This file provides helper functions and classes to deal with OpenMP /// contexts as used by `[begin/end] declare variant` and `metadirective`. /// //===----------------------------------------------------------------------===// #ifndef LLVM_OPENMP_CONTEXT_H #define LLVM_OPENMP_CONTEXT_H #include "llvm/ADT/APSInt.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Triple.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" namespace llvm { namespace omp { /// OpenMP Context related IDs and helpers /// ///{ /// IDs for all OpenMP context selector trait sets (construct/device/...). enum class TraitSet { #define OMP_TRAIT_SET(Enum, ...) Enum, #include "llvm/Frontend/OpenMP/OMPKinds.def" }; /// IDs for all OpenMP context selector trait (device={kind/isa...}/...). enum class TraitSelector { #define OMP_TRAIT_SELECTOR(Enum, ...) Enum, #include "llvm/Frontend/OpenMP/OMPKinds.def" }; /// IDs for all OpenMP context trait properties (host/gpu/bsc/llvm/...) enum class TraitProperty { #define OMP_TRAIT_PROPERTY(Enum, ...) Enum, #define OMP_LAST_TRAIT_PROPERTY(Enum) Last = Enum #include "llvm/Frontend/OpenMP/OMPKinds.def" }; /// Parse \p Str and return the trait set it matches or TraitSet::invalid. TraitSet getOpenMPContextTraitSetKind(StringRef Str); /// Return the trait set for which \p Selector is a selector. TraitSet getOpenMPContextTraitSetForSelector(TraitSelector Selector); /// Return the trait set for which \p Property is a property. TraitSet getOpenMPContextTraitSetForProperty(TraitProperty Property); /// Return a textual representation of the trait set \p Kind. StringRef getOpenMPContextTraitSetName(TraitSet Kind); /// Parse \p Str and return the trait set it matches or /// TraitSelector::invalid. TraitSelector getOpenMPContextTraitSelectorKind(StringRef Str); /// Return the trait selector for which \p Property is a property. TraitSelector getOpenMPContextTraitSelectorForProperty(TraitProperty Property); /// Return a textual representation of the trait selector \p Kind. StringRef getOpenMPContextTraitSelectorName(TraitSelector Kind); /// Parse \p Str and return the trait property it matches in the set \p Set and /// selector \p Selector or TraitProperty::invalid. TraitProperty getOpenMPContextTraitPropertyKind(TraitSet Set, TraitSelector Selector, StringRef Str); /// Return the trait property for a singleton selector \p Selector. TraitProperty getOpenMPContextTraitPropertyForSelector(TraitSelector Selector); /// Return a textual representation of the trait property \p Kind, which might /// be the raw string we parsed (\p RawString) if we do not translate the /// property into a (distinct) enum. StringRef getOpenMPContextTraitPropertyName(TraitProperty Kind, StringRef RawString); /// Return a textual representation of the trait property \p Kind with selector /// and set name included. StringRef getOpenMPContextTraitPropertyFullName(TraitProperty Kind); /// Return a string listing all trait sets. std::string listOpenMPContextTraitSets(); /// Return a string listing all trait selectors for \p Set. std::string listOpenMPContextTraitSelectors(TraitSet Set); /// Return a string listing all trait properties for \p Set and \p Selector. std::string listOpenMPContextTraitProperties(TraitSet Set, TraitSelector Selector); ///} /// Return true if \p Selector can be nested in \p Set. Also sets /// \p AllowsTraitScore and \p RequiresProperty to true/false if the user can /// specify a score for properties in \p Selector and if the \p Selector /// requires at least one property. bool isValidTraitSelectorForTraitSet(TraitSelector Selector, TraitSet Set, bool &AllowsTraitScore, bool &RequiresProperty); /// Return true if \p Property can be nested in \p Selector and \p Set. bool isValidTraitPropertyForTraitSetAndSelector(TraitProperty Property, TraitSelector Selector, TraitSet Set); /// Variant match information describes the required traits and how they are /// scored (via the ScoresMap). In addition, the required consturct nesting is /// decribed as well. struct VariantMatchInfo { /// Add the trait \p Property to the required trait set. \p RawString is the /// string we parsed and derived \p Property from. If \p Score is not null, it /// recorded as well. If \p Property is in the `construct` set it is recorded /// in-order in the ConstructTraits as well. void addTrait(TraitProperty Property, StringRef RawString, APInt *Score = nullptr) { addTrait(getOpenMPContextTraitSetForProperty(Property), Property, RawString, Score); } /// Add the trait \p Property which is in set \p Set to the required trait /// set. \p RawString is the string we parsed and derived \p Property from. If /// \p Score is not null, it recorded as well. If \p Set is the `construct` /// set it is recorded in-order in the ConstructTraits as well. void addTrait(TraitSet Set, TraitProperty Property, StringRef RawString, APInt *Score = nullptr) { if (Score) ScoreMap[Property] = *Score; // Special handling for `device={isa(...)}` as we do not match the enum but // the raw string. if (Property == TraitProperty::device_isa___ANY) ISATraits.push_back(RawString); RequiredTraits.set(unsigned(Property)); if (Set == TraitSet::construct) ConstructTraits.push_back(Property); } BitVector RequiredTraits = BitVector(unsigned(TraitProperty::Last) + 1); SmallVector ISATraits; SmallVector ConstructTraits; SmallDenseMap ScoreMap; }; /// The context for a source location is made up of active property traits, /// e.g., device={kind(host)}, and constructs traits which describe the nesting /// in OpenMP constructs at the location. struct OMPContext { OMPContext(bool IsDeviceCompilation, Triple TargetTriple); virtual ~OMPContext() = default; void addTrait(TraitProperty Property) { addTrait(getOpenMPContextTraitSetForProperty(Property), Property); } void addTrait(TraitSet Set, TraitProperty Property) { ActiveTraits.set(unsigned(Property)); if (Set == TraitSet::construct) ConstructTraits.push_back(Property); } /// Hook for users to check if an ISA trait matches. The trait is described as /// the string that got parsed and it depends on the target and context if /// this matches or not. virtual bool matchesISATrait(StringRef) const { return false; } BitVector ActiveTraits = BitVector(unsigned(TraitProperty::Last) + 1); SmallVector ConstructTraits; }; /// Return true if \p VMI is applicable in \p Ctx, that is, all traits required /// by \p VMI are available in the OpenMP context \p Ctx. If \p DeviceSetOnly is /// true, only the device selector set, if present, are checked. Note that we /// still honor extension traits provided by the user. bool isVariantApplicableInContext(const VariantMatchInfo &VMI, const OMPContext &Ctx, bool DeviceSetOnly = false); /// Return the index (into \p VMIs) of the variant with the highest score /// from the ones applicble in \p Ctx. See llvm::isVariantApplicableInContext. int getBestVariantMatchForContext(const SmallVectorImpl &VMIs, const OMPContext &Ctx); } // namespace omp template <> struct DenseMapInfo { static inline omp::TraitProperty getEmptyKey() { return omp::TraitProperty(-1); } static inline omp::TraitProperty getTombstoneKey() { return omp::TraitProperty(-2); } static unsigned getHashValue(omp::TraitProperty val) { return std::hash{}(unsigned(val)); } static bool isEqual(omp::TraitProperty LHS, omp::TraitProperty RHS) { return LHS == RHS; } }; } // end namespace llvm #endif // LLVM_OPENMP_CONTEXT_H