1097a140dSpatrick //===- OpenMP/OMPContext.h ----- OpenMP context helper functions  - C++ -*-===//
2097a140dSpatrick //
3097a140dSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4097a140dSpatrick // See https://llvm.org/LICENSE.txt for license information.
5097a140dSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6097a140dSpatrick //
7097a140dSpatrick //===----------------------------------------------------------------------===//
8097a140dSpatrick /// \file
9097a140dSpatrick ///
10097a140dSpatrick /// This file provides helper functions and classes to deal with OpenMP
11097a140dSpatrick /// contexts as used by `[begin/end] declare variant` and `metadirective`.
12097a140dSpatrick ///
13097a140dSpatrick //===----------------------------------------------------------------------===//
14097a140dSpatrick 
1573471bf0Spatrick #ifndef LLVM_FRONTEND_OPENMP_OMPCONTEXT_H
1673471bf0Spatrick #define LLVM_FRONTEND_OPENMP_OMPCONTEXT_H
17097a140dSpatrick 
18*d415bd75Srobert #include "llvm/ADT/APInt.h"
19097a140dSpatrick #include "llvm/ADT/BitVector.h"
20*d415bd75Srobert #include "llvm/ADT/DenseMap.h"
21*d415bd75Srobert #include "llvm/ADT/DenseMapInfo.h"
22097a140dSpatrick #include "llvm/Frontend/OpenMP/OMPConstants.h"
23097a140dSpatrick 
24097a140dSpatrick namespace llvm {
25*d415bd75Srobert class Triple;
26097a140dSpatrick namespace omp {
27097a140dSpatrick 
28097a140dSpatrick /// OpenMP Context related IDs and helpers
29097a140dSpatrick ///
30097a140dSpatrick ///{
31097a140dSpatrick 
32097a140dSpatrick /// IDs for all OpenMP context selector trait sets (construct/device/...).
33097a140dSpatrick enum class TraitSet {
34097a140dSpatrick #define OMP_TRAIT_SET(Enum, ...) Enum,
35097a140dSpatrick #include "llvm/Frontend/OpenMP/OMPKinds.def"
36097a140dSpatrick };
37097a140dSpatrick 
38097a140dSpatrick /// IDs for all OpenMP context selector trait (device={kind/isa...}/...).
39097a140dSpatrick enum class TraitSelector {
40097a140dSpatrick #define OMP_TRAIT_SELECTOR(Enum, ...) Enum,
41097a140dSpatrick #include "llvm/Frontend/OpenMP/OMPKinds.def"
42097a140dSpatrick };
43097a140dSpatrick 
44097a140dSpatrick /// IDs for all OpenMP context trait properties (host/gpu/bsc/llvm/...)
45097a140dSpatrick enum class TraitProperty {
46097a140dSpatrick #define OMP_TRAIT_PROPERTY(Enum, ...) Enum,
47097a140dSpatrick #define OMP_LAST_TRAIT_PROPERTY(Enum) Last = Enum
48097a140dSpatrick #include "llvm/Frontend/OpenMP/OMPKinds.def"
49097a140dSpatrick };
50097a140dSpatrick 
51097a140dSpatrick /// Parse \p Str and return the trait set it matches or TraitSet::invalid.
52097a140dSpatrick TraitSet getOpenMPContextTraitSetKind(StringRef Str);
53097a140dSpatrick 
54097a140dSpatrick /// Return the trait set for which \p Selector is a selector.
55097a140dSpatrick TraitSet getOpenMPContextTraitSetForSelector(TraitSelector Selector);
56097a140dSpatrick 
57097a140dSpatrick /// Return the trait set for which \p Property is a property.
58097a140dSpatrick TraitSet getOpenMPContextTraitSetForProperty(TraitProperty Property);
59097a140dSpatrick 
60097a140dSpatrick /// Return a textual representation of the trait set \p Kind.
61097a140dSpatrick StringRef getOpenMPContextTraitSetName(TraitSet Kind);
62097a140dSpatrick 
63097a140dSpatrick /// Parse \p Str and return the trait set it matches or
64097a140dSpatrick /// TraitSelector::invalid.
65097a140dSpatrick TraitSelector getOpenMPContextTraitSelectorKind(StringRef Str);
66097a140dSpatrick 
67097a140dSpatrick /// Return the trait selector for which \p Property is a property.
68097a140dSpatrick TraitSelector getOpenMPContextTraitSelectorForProperty(TraitProperty Property);
69097a140dSpatrick 
70097a140dSpatrick /// Return a textual representation of the trait selector \p Kind.
71097a140dSpatrick StringRef getOpenMPContextTraitSelectorName(TraitSelector Kind);
72097a140dSpatrick 
7373471bf0Spatrick /// Parse \p Str and return the trait property it matches in the set \p Set and
7473471bf0Spatrick /// selector \p Selector or TraitProperty::invalid.
7573471bf0Spatrick TraitProperty getOpenMPContextTraitPropertyKind(TraitSet Set,
7673471bf0Spatrick                                                 TraitSelector Selector,
7773471bf0Spatrick                                                 StringRef Str);
78097a140dSpatrick 
79097a140dSpatrick /// Return the trait property for a singleton selector \p Selector.
80097a140dSpatrick TraitProperty getOpenMPContextTraitPropertyForSelector(TraitSelector Selector);
81097a140dSpatrick 
8273471bf0Spatrick /// Return a textual representation of the trait property \p Kind, which might
8373471bf0Spatrick /// be the raw string we parsed (\p RawString) if we do not translate the
8473471bf0Spatrick /// property into a (distinct) enum.
8573471bf0Spatrick StringRef getOpenMPContextTraitPropertyName(TraitProperty Kind,
8673471bf0Spatrick                                             StringRef RawString);
87097a140dSpatrick 
88097a140dSpatrick /// Return a textual representation of the trait property \p Kind with selector
89097a140dSpatrick /// and set name included.
90097a140dSpatrick StringRef getOpenMPContextTraitPropertyFullName(TraitProperty Kind);
91097a140dSpatrick 
92097a140dSpatrick /// Return a string listing all trait sets.
93097a140dSpatrick std::string listOpenMPContextTraitSets();
94097a140dSpatrick 
95097a140dSpatrick /// Return a string listing all trait selectors for \p Set.
96097a140dSpatrick std::string listOpenMPContextTraitSelectors(TraitSet Set);
97097a140dSpatrick 
98097a140dSpatrick /// Return a string listing all trait properties for \p Set and \p Selector.
99097a140dSpatrick std::string listOpenMPContextTraitProperties(TraitSet Set,
100097a140dSpatrick                                              TraitSelector Selector);
101097a140dSpatrick ///}
102097a140dSpatrick 
103097a140dSpatrick /// Return true if \p Selector can be nested in \p Set. Also sets
104097a140dSpatrick /// \p AllowsTraitScore and \p RequiresProperty to true/false if the user can
105097a140dSpatrick /// specify a score for properties in \p Selector and if the \p Selector
106097a140dSpatrick /// requires at least one property.
107097a140dSpatrick bool isValidTraitSelectorForTraitSet(TraitSelector Selector, TraitSet Set,
108097a140dSpatrick                                      bool &AllowsTraitScore,
109097a140dSpatrick                                      bool &RequiresProperty);
110097a140dSpatrick 
111097a140dSpatrick /// Return true if \p Property can be nested in \p Selector and \p Set.
112097a140dSpatrick bool isValidTraitPropertyForTraitSetAndSelector(TraitProperty Property,
113097a140dSpatrick                                                 TraitSelector Selector,
114097a140dSpatrick                                                 TraitSet Set);
115097a140dSpatrick 
116097a140dSpatrick /// Variant match information describes the required traits and how they are
117097a140dSpatrick /// scored (via the ScoresMap). In addition, the required consturct nesting is
118097a140dSpatrick /// decribed as well.
119097a140dSpatrick struct VariantMatchInfo {
12073471bf0Spatrick   /// Add the trait \p Property to the required trait set. \p RawString is the
12173471bf0Spatrick   /// string we parsed and derived \p Property from. If \p Score is not null, it
12273471bf0Spatrick   /// recorded as well. If \p Property is in the `construct` set it is recorded
12373471bf0Spatrick   /// in-order in the ConstructTraits as well.
12473471bf0Spatrick   void addTrait(TraitProperty Property, StringRef RawString,
12573471bf0Spatrick                 APInt *Score = nullptr) {
12673471bf0Spatrick     addTrait(getOpenMPContextTraitSetForProperty(Property), Property, RawString,
12773471bf0Spatrick              Score);
128097a140dSpatrick   }
129097a140dSpatrick   /// Add the trait \p Property which is in set \p Set to the required trait
13073471bf0Spatrick   /// set. \p RawString is the string we parsed and derived \p Property from. If
13173471bf0Spatrick   /// \p Score is not null, it recorded as well. If \p Set is the `construct`
13273471bf0Spatrick   /// set it is recorded in-order in the ConstructTraits as well.
13373471bf0Spatrick   void addTrait(TraitSet Set, TraitProperty Property, StringRef RawString,
13473471bf0Spatrick                 APInt *Score = nullptr) {
135097a140dSpatrick     if (Score)
136097a140dSpatrick       ScoreMap[Property] = *Score;
13773471bf0Spatrick 
13873471bf0Spatrick     // Special handling for `device={isa(...)}` as we do not match the enum but
13973471bf0Spatrick     // the raw string.
14073471bf0Spatrick     if (Property == TraitProperty::device_isa___ANY)
14173471bf0Spatrick       ISATraits.push_back(RawString);
14273471bf0Spatrick 
143097a140dSpatrick     RequiredTraits.set(unsigned(Property));
144097a140dSpatrick     if (Set == TraitSet::construct)
145097a140dSpatrick       ConstructTraits.push_back(Property);
146097a140dSpatrick   }
147097a140dSpatrick 
148097a140dSpatrick   BitVector RequiredTraits = BitVector(unsigned(TraitProperty::Last) + 1);
14973471bf0Spatrick   SmallVector<StringRef, 8> ISATraits;
150097a140dSpatrick   SmallVector<TraitProperty, 8> ConstructTraits;
151097a140dSpatrick   SmallDenseMap<TraitProperty, APInt> ScoreMap;
152097a140dSpatrick };
153097a140dSpatrick 
154097a140dSpatrick /// The context for a source location is made up of active property traits,
155097a140dSpatrick /// e.g., device={kind(host)}, and constructs traits which describe the nesting
156097a140dSpatrick /// in OpenMP constructs at the location.
157097a140dSpatrick struct OMPContext {
158097a140dSpatrick   OMPContext(bool IsDeviceCompilation, Triple TargetTriple);
15973471bf0Spatrick   virtual ~OMPContext() = default;
160097a140dSpatrick 
addTraitOMPContext161097a140dSpatrick   void addTrait(TraitProperty Property) {
162097a140dSpatrick     addTrait(getOpenMPContextTraitSetForProperty(Property), Property);
163097a140dSpatrick   }
addTraitOMPContext164097a140dSpatrick   void addTrait(TraitSet Set, TraitProperty Property) {
165097a140dSpatrick     ActiveTraits.set(unsigned(Property));
166097a140dSpatrick     if (Set == TraitSet::construct)
167097a140dSpatrick       ConstructTraits.push_back(Property);
168097a140dSpatrick   }
169097a140dSpatrick 
17073471bf0Spatrick   /// Hook for users to check if an ISA trait matches. The trait is described as
17173471bf0Spatrick   /// the string that got parsed and it depends on the target and context if
17273471bf0Spatrick   /// this matches or not.
matchesISATraitOMPContext17373471bf0Spatrick   virtual bool matchesISATrait(StringRef) const { return false; }
17473471bf0Spatrick 
175097a140dSpatrick   BitVector ActiveTraits = BitVector(unsigned(TraitProperty::Last) + 1);
176097a140dSpatrick   SmallVector<TraitProperty, 8> ConstructTraits;
177097a140dSpatrick };
178097a140dSpatrick 
179097a140dSpatrick /// Return true if \p VMI is applicable in \p Ctx, that is, all traits required
180097a140dSpatrick /// by \p VMI are available in the OpenMP context \p Ctx. If \p DeviceSetOnly is
181097a140dSpatrick /// true, only the device selector set, if present, are checked. Note that we
182097a140dSpatrick /// still honor extension traits provided by the user.
183097a140dSpatrick bool isVariantApplicableInContext(const VariantMatchInfo &VMI,
184097a140dSpatrick                                   const OMPContext &Ctx,
185097a140dSpatrick                                   bool DeviceSetOnly = false);
186097a140dSpatrick 
187097a140dSpatrick /// Return the index (into \p VMIs) of the variant with the highest score
188097a140dSpatrick /// from the ones applicble in \p Ctx. See llvm::isVariantApplicableInContext.
189097a140dSpatrick int getBestVariantMatchForContext(const SmallVectorImpl<VariantMatchInfo> &VMIs,
190097a140dSpatrick                                   const OMPContext &Ctx);
191097a140dSpatrick 
192097a140dSpatrick } // namespace omp
193097a140dSpatrick 
194097a140dSpatrick template <> struct DenseMapInfo<omp::TraitProperty> {
195097a140dSpatrick   static inline omp::TraitProperty getEmptyKey() {
196097a140dSpatrick     return omp::TraitProperty(-1);
197097a140dSpatrick   }
198097a140dSpatrick   static inline omp::TraitProperty getTombstoneKey() {
199097a140dSpatrick     return omp::TraitProperty(-2);
200097a140dSpatrick   }
201097a140dSpatrick   static unsigned getHashValue(omp::TraitProperty val) {
202097a140dSpatrick     return std::hash<unsigned>{}(unsigned(val));
203097a140dSpatrick   }
204097a140dSpatrick   static bool isEqual(omp::TraitProperty LHS, omp::TraitProperty RHS) {
205097a140dSpatrick     return LHS == RHS;
206097a140dSpatrick   }
207097a140dSpatrick };
208097a140dSpatrick 
209097a140dSpatrick } // end namespace llvm
21073471bf0Spatrick #endif // LLVM_FRONTEND_OPENMP_OMPCONTEXT_H
211