1*c953409fSJohannes Doerfert //===- OMPContext.cpp ------ Collection of helpers for OpenMP contexts ----===//
2*c953409fSJohannes Doerfert //
3*c953409fSJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c953409fSJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
5*c953409fSJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c953409fSJohannes Doerfert //
7*c953409fSJohannes Doerfert //===----------------------------------------------------------------------===//
8*c953409fSJohannes Doerfert /// \file
9*c953409fSJohannes Doerfert ///
10*c953409fSJohannes Doerfert /// This file implements helper functions and classes to deal with OpenMP
11*c953409fSJohannes Doerfert /// contexts as used by `[begin/end] declare variant` and `metadirective`.
12*c953409fSJohannes Doerfert ///
13*c953409fSJohannes Doerfert //===----------------------------------------------------------------------===//
14*c953409fSJohannes Doerfert 
15*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPContext.h"
16*c953409fSJohannes Doerfert #include "llvm/ADT/SetOperations.h"
17*c953409fSJohannes Doerfert #include "llvm/ADT/StringSwitch.h"
18*c953409fSJohannes Doerfert #include "llvm/Support/Debug.h"
19*c953409fSJohannes Doerfert #include "llvm/Support/raw_ostream.h"
20*c953409fSJohannes Doerfert 
21*c953409fSJohannes Doerfert #define DEBUG_TYPE "openmp-ir-builder"
22*c953409fSJohannes Doerfert 
23*c953409fSJohannes Doerfert using namespace llvm;
24*c953409fSJohannes Doerfert using namespace omp;
25*c953409fSJohannes Doerfert 
26*c953409fSJohannes Doerfert OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) {
27*c953409fSJohannes Doerfert   // Add the appropriate device kind trait based on the triple and the
28*c953409fSJohannes Doerfert   // IsDeviceCompilation flag.
29*c953409fSJohannes Doerfert   ActiveTraits.insert(IsDeviceCompilation ? TraitProperty::device_kind_nohost
30*c953409fSJohannes Doerfert                                           : TraitProperty::device_kind_host);
31*c953409fSJohannes Doerfert   switch (TargetTriple.getArch()) {
32*c953409fSJohannes Doerfert   case Triple::arm:
33*c953409fSJohannes Doerfert   case Triple::armeb:
34*c953409fSJohannes Doerfert   case Triple::aarch64:
35*c953409fSJohannes Doerfert   case Triple::aarch64_be:
36*c953409fSJohannes Doerfert   case Triple::aarch64_32:
37*c953409fSJohannes Doerfert   case Triple::mips:
38*c953409fSJohannes Doerfert   case Triple::mipsel:
39*c953409fSJohannes Doerfert   case Triple::mips64:
40*c953409fSJohannes Doerfert   case Triple::mips64el:
41*c953409fSJohannes Doerfert   case Triple::ppc:
42*c953409fSJohannes Doerfert   case Triple::ppc64:
43*c953409fSJohannes Doerfert   case Triple::ppc64le:
44*c953409fSJohannes Doerfert   case Triple::x86:
45*c953409fSJohannes Doerfert   case Triple::x86_64:
46*c953409fSJohannes Doerfert     ActiveTraits.insert(TraitProperty::device_kind_cpu);
47*c953409fSJohannes Doerfert     break;
48*c953409fSJohannes Doerfert   case Triple::amdgcn:
49*c953409fSJohannes Doerfert   case Triple::nvptx:
50*c953409fSJohannes Doerfert   case Triple::nvptx64:
51*c953409fSJohannes Doerfert     ActiveTraits.insert(TraitProperty::device_kind_gpu);
52*c953409fSJohannes Doerfert     break;
53*c953409fSJohannes Doerfert   default:
54*c953409fSJohannes Doerfert     break;
55*c953409fSJohannes Doerfert   }
56*c953409fSJohannes Doerfert 
57*c953409fSJohannes Doerfert   // Add the appropriate device architecture trait based on the triple.
58*c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
59*c953409fSJohannes Doerfert   if (TraitSelector::TraitSelectorEnum == TraitSelector::device_arch)          \
60*c953409fSJohannes Doerfert     if (TargetTriple.getArch() == TargetTriple.getArchTypeForLLVMName(Str))    \
61*c953409fSJohannes Doerfert       ActiveTraits.insert(TraitProperty::Enum);
62*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
63*c953409fSJohannes Doerfert 
64*c953409fSJohannes Doerfert   // TODO: What exactly do we want to see as device ISA trait?
65*c953409fSJohannes Doerfert   //       The discussion on the list did not seem to have come to an agreed
66*c953409fSJohannes Doerfert   //       upon solution.
67*c953409fSJohannes Doerfert 
68*c953409fSJohannes Doerfert   // LLVM is the "OpenMP vendor" but we could also interpret vendor as the
69*c953409fSJohannes Doerfert   // target vendor.
70*c953409fSJohannes Doerfert   ActiveTraits.insert(TraitProperty::implementation_vendor_llvm);
71*c953409fSJohannes Doerfert 
72*c953409fSJohannes Doerfert   // The user condition true is accepted but not false.
73*c953409fSJohannes Doerfert   ActiveTraits.insert(TraitProperty::user_condition_true);
74*c953409fSJohannes Doerfert 
75*c953409fSJohannes Doerfert   // This is for sure some device.
76*c953409fSJohannes Doerfert   ActiveTraits.insert(TraitProperty::device_kind_any);
77*c953409fSJohannes Doerfert 
78*c953409fSJohannes Doerfert   LLVM_DEBUG({
79*c953409fSJohannes Doerfert     dbgs() << "[" << DEBUG_TYPE
80*c953409fSJohannes Doerfert            << "] New OpenMP context with the following properties:\n";
81*c953409fSJohannes Doerfert     for (auto &Property : ActiveTraits)
82*c953409fSJohannes Doerfert       dbgs() << "\t " << getOpenMPContextTraitPropertyFullName(Property)
83*c953409fSJohannes Doerfert              << "\n";
84*c953409fSJohannes Doerfert   });
85*c953409fSJohannes Doerfert }
86*c953409fSJohannes Doerfert 
87*c953409fSJohannes Doerfert /// Return true if \p C0 is a subset of \p C1. Note that both arrays are
88*c953409fSJohannes Doerfert /// expected to be sorted.
89*c953409fSJohannes Doerfert template <typename T> static bool isSubset(ArrayRef<T> C0, ArrayRef<T> C1) {
90*c953409fSJohannes Doerfert #ifdef EXPENSIVE_CHECKS
91*c953409fSJohannes Doerfert   assert(std::is_sorted(C0.begin(), C0.end()) &&
92*c953409fSJohannes Doerfert          std::is_sorted(C1.begin(), C1.end()) && "Expected sorted arrays!");
93*c953409fSJohannes Doerfert #endif
94*c953409fSJohannes Doerfert   if (C0.size() > C1.size())
95*c953409fSJohannes Doerfert     return false;
96*c953409fSJohannes Doerfert   auto It0 = C0.begin(), End0 = C0.end();
97*c953409fSJohannes Doerfert   auto It1 = C1.begin(), End1 = C1.end();
98*c953409fSJohannes Doerfert   while (It0 != End0) {
99*c953409fSJohannes Doerfert     if (It1 == End1)
100*c953409fSJohannes Doerfert       return false;
101*c953409fSJohannes Doerfert     if (*It0 == *It1) {
102*c953409fSJohannes Doerfert       ++It0;
103*c953409fSJohannes Doerfert       ++It1;
104*c953409fSJohannes Doerfert       continue;
105*c953409fSJohannes Doerfert     }
106*c953409fSJohannes Doerfert     ++It0;
107*c953409fSJohannes Doerfert   }
108*c953409fSJohannes Doerfert   return true;
109*c953409fSJohannes Doerfert }
110*c953409fSJohannes Doerfert 
111*c953409fSJohannes Doerfert /// Return true if \p C0 is a strict subset of \p C1. Note that both arrays are
112*c953409fSJohannes Doerfert /// expected to be sorted.
113*c953409fSJohannes Doerfert template <typename T>
114*c953409fSJohannes Doerfert static bool isStrictSubset(ArrayRef<T> C0, ArrayRef<T> C1) {
115*c953409fSJohannes Doerfert   if (C0.size() >= C1.size())
116*c953409fSJohannes Doerfert     return false;
117*c953409fSJohannes Doerfert   return isSubset<T>(C0, C1);
118*c953409fSJohannes Doerfert }
119*c953409fSJohannes Doerfert 
120*c953409fSJohannes Doerfert static bool isStrictSubset(const VariantMatchInfo &VMI0,
121*c953409fSJohannes Doerfert                            const VariantMatchInfo &VMI1) {
122*c953409fSJohannes Doerfert   // If all required traits are a strict subset and the ordered vectors storing
123*c953409fSJohannes Doerfert   // the construct traits, we say it is a strict subset. Note that the latter
124*c953409fSJohannes Doerfert   // relation is not required to be strict.
125*c953409fSJohannes Doerfert   return set_is_strict_subset(VMI0.RequiredTraits, VMI1.RequiredTraits) &&
126*c953409fSJohannes Doerfert          isSubset<TraitProperty>(VMI0.ConstructTraits, VMI1.ConstructTraits);
127*c953409fSJohannes Doerfert }
128*c953409fSJohannes Doerfert 
129*c953409fSJohannes Doerfert static int isVariantApplicableInContextHelper(
130*c953409fSJohannes Doerfert     const VariantMatchInfo &VMI, const OMPContext &Ctx,
131*c953409fSJohannes Doerfert     SmallVectorImpl<unsigned> *ConstructMatches) {
132*c953409fSJohannes Doerfert 
133*c953409fSJohannes Doerfert   for (TraitProperty Property : VMI.RequiredTraits) {
134*c953409fSJohannes Doerfert 
135*c953409fSJohannes Doerfert     bool IsActiveTrait = Ctx.ActiveTraits.count(Property);
136*c953409fSJohannes Doerfert     if (!IsActiveTrait) {
137*c953409fSJohannes Doerfert       LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Property "
138*c953409fSJohannes Doerfert                         << getOpenMPContextTraitPropertyName(Property)
139*c953409fSJohannes Doerfert                         << " was not in the OpenMP context.\n");
140*c953409fSJohannes Doerfert       return false;
141*c953409fSJohannes Doerfert     }
142*c953409fSJohannes Doerfert   }
143*c953409fSJohannes Doerfert 
144*c953409fSJohannes Doerfert   // We could use isSubset here but we also want to record the match locations.
145*c953409fSJohannes Doerfert   unsigned ConstructIdx = 0, NoConstructTraits = Ctx.ConstructTraits.size();
146*c953409fSJohannes Doerfert   for (TraitProperty Property : VMI.ConstructTraits) {
147*c953409fSJohannes Doerfert     assert(getOpenMPContextTraitSetForProperty(Property) ==
148*c953409fSJohannes Doerfert                TraitSet::construct &&
149*c953409fSJohannes Doerfert            "Variant context is ill-formed!");
150*c953409fSJohannes Doerfert 
151*c953409fSJohannes Doerfert     // Verify the nesting.
152*c953409fSJohannes Doerfert     bool FoundInOrder = false;
153*c953409fSJohannes Doerfert     while (!FoundInOrder && ConstructIdx != NoConstructTraits)
154*c953409fSJohannes Doerfert       FoundInOrder = (Ctx.ConstructTraits[ConstructIdx++] == Property);
155*c953409fSJohannes Doerfert     if (ConstructMatches)
156*c953409fSJohannes Doerfert       ConstructMatches->push_back(ConstructIdx - 1);
157*c953409fSJohannes Doerfert 
158*c953409fSJohannes Doerfert     if (!FoundInOrder) {
159*c953409fSJohannes Doerfert       LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Construct property "
160*c953409fSJohannes Doerfert                         << getOpenMPContextTraitPropertyName(Property)
161*c953409fSJohannes Doerfert                         << " was not nested properly.\n");
162*c953409fSJohannes Doerfert       return false;
163*c953409fSJohannes Doerfert     }
164*c953409fSJohannes Doerfert 
165*c953409fSJohannes Doerfert     // TODO: Verify SIMD
166*c953409fSJohannes Doerfert   }
167*c953409fSJohannes Doerfert 
168*c953409fSJohannes Doerfert   assert(isSubset<TraitProperty>(VMI.ConstructTraits, Ctx.ConstructTraits) &&
169*c953409fSJohannes Doerfert          "Broken invariant!");
170*c953409fSJohannes Doerfert   return true;
171*c953409fSJohannes Doerfert }
172*c953409fSJohannes Doerfert 
173*c953409fSJohannes Doerfert bool llvm::omp::isVariantApplicableInContext(const VariantMatchInfo &VMI,
174*c953409fSJohannes Doerfert                                              const OMPContext &Ctx) {
175*c953409fSJohannes Doerfert   return isVariantApplicableInContextHelper(VMI, Ctx, nullptr);
176*c953409fSJohannes Doerfert }
177*c953409fSJohannes Doerfert 
178*c953409fSJohannes Doerfert static APInt getVariantMatchScore(const VariantMatchInfo &VMI,
179*c953409fSJohannes Doerfert                                   const OMPContext &Ctx,
180*c953409fSJohannes Doerfert                                   SmallVectorImpl<unsigned> &ConstructMatches) {
181*c953409fSJohannes Doerfert   APInt Score(64, 1);
182*c953409fSJohannes Doerfert 
183*c953409fSJohannes Doerfert   unsigned NoConstructTraits = VMI.ConstructTraits.size();
184*c953409fSJohannes Doerfert   for (TraitProperty Property : VMI.RequiredTraits) {
185*c953409fSJohannes Doerfert     // If there is a user score attached, use it.
186*c953409fSJohannes Doerfert     if (VMI.ScoreMap.count(Property)) {
187*c953409fSJohannes Doerfert       const APInt &UserScore = VMI.ScoreMap.lookup(Property);
188*c953409fSJohannes Doerfert       assert(UserScore.uge(0) && "Expect non-negative user scores!");
189*c953409fSJohannes Doerfert       Score += UserScore.getZExtValue();
190*c953409fSJohannes Doerfert       continue;
191*c953409fSJohannes Doerfert     }
192*c953409fSJohannes Doerfert 
193*c953409fSJohannes Doerfert     switch (getOpenMPContextTraitSetForProperty(Property)) {
194*c953409fSJohannes Doerfert     case TraitSet::construct:
195*c953409fSJohannes Doerfert       // We handle the construct traits later via the VMI.ConstructTraits
196*c953409fSJohannes Doerfert       // container.
197*c953409fSJohannes Doerfert       continue;
198*c953409fSJohannes Doerfert     case TraitSet::implementation:
199*c953409fSJohannes Doerfert       // No effect on the score (implementation defined).
200*c953409fSJohannes Doerfert       continue;
201*c953409fSJohannes Doerfert     case TraitSet::user:
202*c953409fSJohannes Doerfert       // No effect on the score.
203*c953409fSJohannes Doerfert       continue;
204*c953409fSJohannes Doerfert     case TraitSet::device:
205*c953409fSJohannes Doerfert       // Handled separately below.
206*c953409fSJohannes Doerfert       break;
207*c953409fSJohannes Doerfert     case TraitSet::invalid:
208*c953409fSJohannes Doerfert       llvm_unreachable("Unknown trait set is not to be used!");
209*c953409fSJohannes Doerfert     }
210*c953409fSJohannes Doerfert 
211*c953409fSJohannes Doerfert     // device={kind(any)} is "as if" no kind selector was specified.
212*c953409fSJohannes Doerfert     if (Property == TraitProperty::device_kind_any)
213*c953409fSJohannes Doerfert       continue;
214*c953409fSJohannes Doerfert 
215*c953409fSJohannes Doerfert     switch (getOpenMPContextTraitSelectorForProperty(Property)) {
216*c953409fSJohannes Doerfert     case TraitSelector::device_kind:
217*c953409fSJohannes Doerfert       Score += (1 << (NoConstructTraits + 0));
218*c953409fSJohannes Doerfert       continue;
219*c953409fSJohannes Doerfert     case TraitSelector::device_arch:
220*c953409fSJohannes Doerfert       Score += (1 << (NoConstructTraits + 1));
221*c953409fSJohannes Doerfert       continue;
222*c953409fSJohannes Doerfert     case TraitSelector::device_isa:
223*c953409fSJohannes Doerfert       Score += (1 << (NoConstructTraits + 2));
224*c953409fSJohannes Doerfert       continue;
225*c953409fSJohannes Doerfert     default:
226*c953409fSJohannes Doerfert       continue;
227*c953409fSJohannes Doerfert     }
228*c953409fSJohannes Doerfert   }
229*c953409fSJohannes Doerfert 
230*c953409fSJohannes Doerfert   unsigned ConstructIdx = 0;
231*c953409fSJohannes Doerfert   assert(NoConstructTraits == ConstructMatches.size() &&
232*c953409fSJohannes Doerfert          "Mismatch in the construct traits!");
233*c953409fSJohannes Doerfert   for (TraitProperty Property : VMI.ConstructTraits) {
234*c953409fSJohannes Doerfert     assert(getOpenMPContextTraitSetForProperty(Property) ==
235*c953409fSJohannes Doerfert                TraitSet::construct &&
236*c953409fSJohannes Doerfert            "Ill-formed variant match info!");
237*c953409fSJohannes Doerfert     // ConstructMatches is the position p - 1 and we need 2^(p-1).
238*c953409fSJohannes Doerfert     Score += (1 << ConstructMatches[ConstructIdx++]);
239*c953409fSJohannes Doerfert   }
240*c953409fSJohannes Doerfert 
241*c953409fSJohannes Doerfert   LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Variant has a score of " << Score
242*c953409fSJohannes Doerfert                     << "\n");
243*c953409fSJohannes Doerfert   return Score;
244*c953409fSJohannes Doerfert };
245*c953409fSJohannes Doerfert 
246*c953409fSJohannes Doerfert int llvm::omp::getBestVariantMatchForContext(
247*c953409fSJohannes Doerfert     const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext &Ctx) {
248*c953409fSJohannes Doerfert 
249*c953409fSJohannes Doerfert   APInt BestScore(64, 0);
250*c953409fSJohannes Doerfert   int BestVMIIdx = -1;
251*c953409fSJohannes Doerfert   const VariantMatchInfo *BestVMI = nullptr;
252*c953409fSJohannes Doerfert 
253*c953409fSJohannes Doerfert   for (unsigned u = 0, e = VMIs.size(); u < e; ++u) {
254*c953409fSJohannes Doerfert     const VariantMatchInfo &VMI = VMIs[u];
255*c953409fSJohannes Doerfert 
256*c953409fSJohannes Doerfert     SmallVector<unsigned, 8> ConstructMatches;
257*c953409fSJohannes Doerfert     // If the variant is not applicable its not the best.
258*c953409fSJohannes Doerfert     if (!isVariantApplicableInContextHelper(VMI, Ctx, &ConstructMatches))
259*c953409fSJohannes Doerfert       continue;
260*c953409fSJohannes Doerfert     // Check if its clearly not the best.
261*c953409fSJohannes Doerfert     APInt Score = getVariantMatchScore(VMI, Ctx, ConstructMatches);
262*c953409fSJohannes Doerfert     if (Score.ult(BestScore))
263*c953409fSJohannes Doerfert       continue;
264*c953409fSJohannes Doerfert     // Equal score need subset checks.
265*c953409fSJohannes Doerfert     if (Score.eq(BestScore)) {
266*c953409fSJohannes Doerfert       // Strict subset are never best.
267*c953409fSJohannes Doerfert       if (isStrictSubset(VMI, *BestVMI))
268*c953409fSJohannes Doerfert         continue;
269*c953409fSJohannes Doerfert       // Same score and the current best is no strict subset so we keep it.
270*c953409fSJohannes Doerfert       if (!isStrictSubset(*BestVMI, VMI))
271*c953409fSJohannes Doerfert         continue;
272*c953409fSJohannes Doerfert     }
273*c953409fSJohannes Doerfert     // New best found.
274*c953409fSJohannes Doerfert     BestVMI = &VMI;
275*c953409fSJohannes Doerfert     BestVMIIdx = u;
276*c953409fSJohannes Doerfert     BestScore = Score;
277*c953409fSJohannes Doerfert   }
278*c953409fSJohannes Doerfert 
279*c953409fSJohannes Doerfert   return BestVMIIdx;
280*c953409fSJohannes Doerfert }
281*c953409fSJohannes Doerfert 
282*c953409fSJohannes Doerfert TraitSet llvm::omp::getOpenMPContextTraitSetKind(StringRef S) {
283*c953409fSJohannes Doerfert   return StringSwitch<TraitSet>(S)
284*c953409fSJohannes Doerfert #define OMP_TRAIT_SET(Enum, Str) .Case(Str, TraitSet::Enum)
285*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
286*c953409fSJohannes Doerfert       .Default(TraitSet::invalid);
287*c953409fSJohannes Doerfert }
288*c953409fSJohannes Doerfert TraitSet
289*c953409fSJohannes Doerfert llvm::omp::getOpenMPContextTraitSetForProperty(TraitProperty Property) {
290*c953409fSJohannes Doerfert   switch (Property) {
291*c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
292*c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
293*c953409fSJohannes Doerfert     return TraitSet::TraitSetEnum;
294*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
295*c953409fSJohannes Doerfert   }
296*c953409fSJohannes Doerfert }
297*c953409fSJohannes Doerfert StringRef llvm::omp::getOpenMPContextTraitSetName(TraitSet Kind) {
298*c953409fSJohannes Doerfert   switch (Kind) {
299*c953409fSJohannes Doerfert #define OMP_TRAIT_SET(Enum, Str)                                               \
300*c953409fSJohannes Doerfert   case TraitSet::Enum:                                                         \
301*c953409fSJohannes Doerfert     return Str;
302*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
303*c953409fSJohannes Doerfert   }
304*c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait set!");
305*c953409fSJohannes Doerfert }
306*c953409fSJohannes Doerfert 
307*c953409fSJohannes Doerfert TraitSelector llvm::omp::getOpenMPContextTraitSelectorKind(StringRef S) {
308*c953409fSJohannes Doerfert   return StringSwitch<TraitSelector>(S)
309*c953409fSJohannes Doerfert #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
310*c953409fSJohannes Doerfert   .Case(Str, TraitSelector::Enum)
311*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
312*c953409fSJohannes Doerfert       .Default(TraitSelector::invalid);
313*c953409fSJohannes Doerfert }
314*c953409fSJohannes Doerfert TraitSelector
315*c953409fSJohannes Doerfert llvm::omp::getOpenMPContextTraitSelectorForProperty(TraitProperty Property) {
316*c953409fSJohannes Doerfert   switch (Property) {
317*c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
318*c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
319*c953409fSJohannes Doerfert     return TraitSelector::TraitSelectorEnum;
320*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
321*c953409fSJohannes Doerfert   }
322*c953409fSJohannes Doerfert }
323*c953409fSJohannes Doerfert StringRef llvm::omp::getOpenMPContextTraitSelectorName(TraitSelector Kind) {
324*c953409fSJohannes Doerfert   switch (Kind) {
325*c953409fSJohannes Doerfert #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
326*c953409fSJohannes Doerfert   case TraitSelector::Enum:                                                    \
327*c953409fSJohannes Doerfert     return Str;
328*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
329*c953409fSJohannes Doerfert   }
330*c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait selector!");
331*c953409fSJohannes Doerfert }
332*c953409fSJohannes Doerfert 
333*c953409fSJohannes Doerfert TraitProperty llvm::omp::getOpenMPContextTraitPropertyKind(
334*c953409fSJohannes Doerfert     TraitSet Set, TraitSelector Selector, StringRef S) {
335*c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
336*c953409fSJohannes Doerfert   if (Set == TraitSet::TraitSetEnum &&                                         \
337*c953409fSJohannes Doerfert       Selector == TraitSelector::TraitSelectorEnum && Str == S)                \
338*c953409fSJohannes Doerfert     return TraitProperty::Enum;
339*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
340*c953409fSJohannes Doerfert   return TraitProperty::invalid;
341*c953409fSJohannes Doerfert }
342*c953409fSJohannes Doerfert TraitProperty
343*c953409fSJohannes Doerfert llvm::omp::getOpenMPContextTraitPropertyForSelector(TraitSelector Selector) {
344*c953409fSJohannes Doerfert   return StringSwitch<TraitProperty>(
345*c953409fSJohannes Doerfert              getOpenMPContextTraitSelectorName(Selector))
346*c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
347*c953409fSJohannes Doerfert   .Case(Str, Selector == TraitSelector::TraitSelectorEnum                      \
348*c953409fSJohannes Doerfert                  ? TraitProperty::Enum                                         \
349*c953409fSJohannes Doerfert                  : TraitProperty::invalid)
350*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
351*c953409fSJohannes Doerfert       .Default(TraitProperty::invalid);
352*c953409fSJohannes Doerfert }
353*c953409fSJohannes Doerfert StringRef llvm::omp::getOpenMPContextTraitPropertyName(TraitProperty Kind) {
354*c953409fSJohannes Doerfert   switch (Kind) {
355*c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
356*c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
357*c953409fSJohannes Doerfert     return Str;
358*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
359*c953409fSJohannes Doerfert   }
360*c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait property!");
361*c953409fSJohannes Doerfert }
362*c953409fSJohannes Doerfert StringRef llvm::omp::getOpenMPContextTraitPropertyFullName(TraitProperty Kind) {
363*c953409fSJohannes Doerfert   switch (Kind) {
364*c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
365*c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
366*c953409fSJohannes Doerfert     return "(" #TraitSetEnum "," #TraitSelectorEnum "," Str ")";
367*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
368*c953409fSJohannes Doerfert   }
369*c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait property!");
370*c953409fSJohannes Doerfert }
371*c953409fSJohannes Doerfert 
372*c953409fSJohannes Doerfert bool llvm::omp::isValidTraitSelectorForTraitSet(TraitSelector Selector,
373*c953409fSJohannes Doerfert                                                 TraitSet Set,
374*c953409fSJohannes Doerfert                                                 bool &AllowsTraitScore,
375*c953409fSJohannes Doerfert                                                 bool &RequiresProperty) {
376*c953409fSJohannes Doerfert   AllowsTraitScore = Set != TraitSet::construct && Set != TraitSet::device;
377*c953409fSJohannes Doerfert   switch (Selector) {
378*c953409fSJohannes Doerfert #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
379*c953409fSJohannes Doerfert   case TraitSelector::Enum:                                                    \
380*c953409fSJohannes Doerfert     RequiresProperty = ReqProp;                                                \
381*c953409fSJohannes Doerfert     return Set == TraitSet::TraitSetEnum;
382*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
383*c953409fSJohannes Doerfert   }
384*c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait selector!");
385*c953409fSJohannes Doerfert }
386*c953409fSJohannes Doerfert 
387*c953409fSJohannes Doerfert bool llvm::omp::isValidTraitPropertyForTraitSetAndSelector(
388*c953409fSJohannes Doerfert     TraitProperty Property, TraitSelector Selector, TraitSet Set) {
389*c953409fSJohannes Doerfert   switch (Property) {
390*c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
391*c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
392*c953409fSJohannes Doerfert     return Set == TraitSet::TraitSetEnum &&                                    \
393*c953409fSJohannes Doerfert            Selector == TraitSelector::TraitSelectorEnum;
394*c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
395*c953409fSJohannes Doerfert   }
396*c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait property!");
397*c953409fSJohannes Doerfert }
398