1 //===- OpenMP/OMPContext.h ----- OpenMP context helper functions  - C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 ///
10 /// This file provides helper functions and classes to deal with OpenMP
11 /// contexts as used by `[begin/end] declare variant` and `metadirective`.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_FRONTEND_OPENMP_OMPCONTEXT_H
16 #define LLVM_FRONTEND_OPENMP_OMPCONTEXT_H
17 
18 #include "llvm/ADT/APInt.h"
19 #include "llvm/ADT/BitVector.h"
20 #include "llvm/ADT/DenseMap.h"
21 #include "llvm/ADT/DenseMapInfo.h"
22 #include "llvm/Frontend/OpenMP/OMPConstants.h"
23 
24 namespace llvm {
25 class Triple;
26 namespace omp {
27 
28 /// OpenMP Context related IDs and helpers
29 ///
30 ///{
31 
32 /// IDs for all OpenMP context selector trait sets (construct/device/...).
33 enum class TraitSet {
34 #define OMP_TRAIT_SET(Enum, ...) Enum,
35 #include "llvm/Frontend/OpenMP/OMPKinds.def"
36 };
37 
38 /// IDs for all OpenMP context selector trait (device={kind/isa...}/...).
39 enum class TraitSelector {
40 #define OMP_TRAIT_SELECTOR(Enum, ...) Enum,
41 #include "llvm/Frontend/OpenMP/OMPKinds.def"
42 };
43 
44 /// IDs for all OpenMP context trait properties (host/gpu/bsc/llvm/...)
45 enum class TraitProperty {
46 #define OMP_TRAIT_PROPERTY(Enum, ...) Enum,
47 #define OMP_LAST_TRAIT_PROPERTY(Enum) Last = Enum
48 #include "llvm/Frontend/OpenMP/OMPKinds.def"
49 };
50 
51 /// Parse \p Str and return the trait set it matches or TraitSet::invalid.
52 TraitSet getOpenMPContextTraitSetKind(StringRef Str);
53 
54 /// Return the trait set for which \p Selector is a selector.
55 TraitSet getOpenMPContextTraitSetForSelector(TraitSelector Selector);
56 
57 /// Return the trait set for which \p Property is a property.
58 TraitSet getOpenMPContextTraitSetForProperty(TraitProperty Property);
59 
60 /// Return a textual representation of the trait set \p Kind.
61 StringRef getOpenMPContextTraitSetName(TraitSet Kind);
62 
63 /// Parse \p Str and return the trait set it matches or
64 /// TraitSelector::invalid.
65 TraitSelector getOpenMPContextTraitSelectorKind(StringRef Str);
66 
67 /// Return the trait selector for which \p Property is a property.
68 TraitSelector getOpenMPContextTraitSelectorForProperty(TraitProperty Property);
69 
70 /// Return a textual representation of the trait selector \p Kind.
71 StringRef getOpenMPContextTraitSelectorName(TraitSelector Kind);
72 
73 /// Parse \p Str and return the trait property it matches in the set \p Set and
74 /// selector \p Selector or TraitProperty::invalid.
75 TraitProperty getOpenMPContextTraitPropertyKind(TraitSet Set,
76                                                 TraitSelector Selector,
77                                                 StringRef Str);
78 
79 /// Return the trait property for a singleton selector \p Selector.
80 TraitProperty getOpenMPContextTraitPropertyForSelector(TraitSelector Selector);
81 
82 /// Return a textual representation of the trait property \p Kind, which might
83 /// be the raw string we parsed (\p RawString) if we do not translate the
84 /// property into a (distinct) enum.
85 StringRef getOpenMPContextTraitPropertyName(TraitProperty Kind,
86                                             StringRef RawString);
87 
88 /// Return a textual representation of the trait property \p Kind with selector
89 /// and set name included.
90 StringRef getOpenMPContextTraitPropertyFullName(TraitProperty Kind);
91 
92 /// Return a string listing all trait sets.
93 std::string listOpenMPContextTraitSets();
94 
95 /// Return a string listing all trait selectors for \p Set.
96 std::string listOpenMPContextTraitSelectors(TraitSet Set);
97 
98 /// Return a string listing all trait properties for \p Set and \p Selector.
99 std::string listOpenMPContextTraitProperties(TraitSet Set,
100                                              TraitSelector Selector);
101 ///}
102 
103 /// Return true if \p Selector can be nested in \p Set. Also sets
104 /// \p AllowsTraitScore and \p RequiresProperty to true/false if the user can
105 /// specify a score for properties in \p Selector and if the \p Selector
106 /// requires at least one property.
107 bool isValidTraitSelectorForTraitSet(TraitSelector Selector, TraitSet Set,
108                                      bool &AllowsTraitScore,
109                                      bool &RequiresProperty);
110 
111 /// Return true if \p Property can be nested in \p Selector and \p Set.
112 bool isValidTraitPropertyForTraitSetAndSelector(TraitProperty Property,
113                                                 TraitSelector Selector,
114                                                 TraitSet Set);
115 
116 /// Variant match information describes the required traits and how they are
117 /// scored (via the ScoresMap). In addition, the required consturct nesting is
118 /// decribed as well.
119 struct VariantMatchInfo {
120   /// Add the trait \p Property to the required trait set. \p RawString is the
121   /// string we parsed and derived \p Property from. If \p Score is not null, it
122   /// recorded as well. If \p Property is in the `construct` set it is recorded
123   /// in-order in the ConstructTraits as well.
124   void addTrait(TraitProperty Property, StringRef RawString,
125                 APInt *Score = nullptr) {
126     addTrait(getOpenMPContextTraitSetForProperty(Property), Property, RawString,
127              Score);
128   }
129   /// Add the trait \p Property which is in set \p Set to the required trait
130   /// set. \p RawString is the string we parsed and derived \p Property from. If
131   /// \p Score is not null, it recorded as well. If \p Set is the `construct`
132   /// set it is recorded in-order in the ConstructTraits as well.
133   void addTrait(TraitSet Set, TraitProperty Property, StringRef RawString,
134                 APInt *Score = nullptr) {
135     if (Score)
136       ScoreMap[Property] = *Score;
137 
138     // Special handling for `device={isa(...)}` as we do not match the enum but
139     // the raw string.
140     if (Property == TraitProperty::device_isa___ANY)
141       ISATraits.push_back(RawString);
142 
143     RequiredTraits.set(unsigned(Property));
144     if (Set == TraitSet::construct)
145       ConstructTraits.push_back(Property);
146   }
147 
148   BitVector RequiredTraits = BitVector(unsigned(TraitProperty::Last) + 1);
149   SmallVector<StringRef, 8> ISATraits;
150   SmallVector<TraitProperty, 8> ConstructTraits;
151   SmallDenseMap<TraitProperty, APInt> ScoreMap;
152 };
153 
154 /// The context for a source location is made up of active property traits,
155 /// e.g., device={kind(host)}, and constructs traits which describe the nesting
156 /// in OpenMP constructs at the location.
157 struct OMPContext {
158   OMPContext(bool IsDeviceCompilation, Triple TargetTriple);
159   virtual ~OMPContext() = default;
160 
161   void addTrait(TraitProperty Property) {
162     addTrait(getOpenMPContextTraitSetForProperty(Property), Property);
163   }
164   void addTrait(TraitSet Set, TraitProperty Property) {
165     ActiveTraits.set(unsigned(Property));
166     if (Set == TraitSet::construct)
167       ConstructTraits.push_back(Property);
168   }
169 
170   /// Hook for users to check if an ISA trait matches. The trait is described as
171   /// the string that got parsed and it depends on the target and context if
172   /// this matches or not.
173   virtual bool matchesISATrait(StringRef) const { return false; }
174 
175   BitVector ActiveTraits = BitVector(unsigned(TraitProperty::Last) + 1);
176   SmallVector<TraitProperty, 8> ConstructTraits;
177 };
178 
179 /// Return true if \p VMI is applicable in \p Ctx, that is, all traits required
180 /// by \p VMI are available in the OpenMP context \p Ctx. If \p DeviceSetOnly is
181 /// true, only the device selector set, if present, are checked. Note that we
182 /// still honor extension traits provided by the user.
183 bool isVariantApplicableInContext(const VariantMatchInfo &VMI,
184                                   const OMPContext &Ctx,
185                                   bool DeviceSetOnly = false);
186 
187 /// Return the index (into \p VMIs) of the variant with the highest score
188 /// from the ones applicble in \p Ctx. See llvm::isVariantApplicableInContext.
189 int getBestVariantMatchForContext(const SmallVectorImpl<VariantMatchInfo> &VMIs,
190                                   const OMPContext &Ctx);
191 
192 } // namespace omp
193 
194 template <> struct DenseMapInfo<omp::TraitProperty> {
195   static inline omp::TraitProperty getEmptyKey() {
196     return omp::TraitProperty(-1);
197   }
198   static inline omp::TraitProperty getTombstoneKey() {
199     return omp::TraitProperty(-2);
200   }
201   static unsigned getHashValue(omp::TraitProperty val) {
202     return std::hash<unsigned>{}(unsigned(val));
203   }
204   static bool isEqual(omp::TraitProperty LHS, omp::TraitProperty RHS) {
205     return LHS == RHS;
206   }
207 };
208 
209 } // end namespace llvm
210 #endif // LLVM_FRONTEND_OPENMP_OMPCONTEXT_H
211