xref: /freebsd/contrib/llvm-project/llvm/lib/Frontend/OpenMP/OMPContext.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- OMPContext.cpp ------ Collection of helpers for OpenMP contexts ----===//
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 implements helper functions and classes to deal with OpenMP
11 /// contexts as used by `[begin/end] declare variant` and `metadirective`.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/Frontend/OpenMP/OMPContext.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ADT/StringSwitch.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/TargetParser/Triple.h"
21 
22 #define DEBUG_TYPE "openmp-ir-builder"
23 
24 using namespace llvm;
25 using namespace omp;
26 
OMPContext(bool IsDeviceCompilation,Triple TargetTriple,Triple TargetOffloadTriple,int DeviceNum)27 OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple,
28                        Triple TargetOffloadTriple, int DeviceNum) {
29   // Add the appropriate target device kind trait based on the target triple
30   if (!TargetOffloadTriple.getTriple().empty() && DeviceNum > -1) {
31     // If target triple is present, then target device is not a host
32     ActiveTraits.set(unsigned(TraitProperty::target_device_kind_nohost));
33     switch (TargetOffloadTriple.getArch()) {
34     case Triple::arm:
35     case Triple::armeb:
36     case Triple::aarch64:
37     case Triple::aarch64_be:
38     case Triple::aarch64_32:
39     case Triple::mips:
40     case Triple::mipsel:
41     case Triple::mips64:
42     case Triple::mips64el:
43     case Triple::ppc:
44     case Triple::ppcle:
45     case Triple::ppc64:
46     case Triple::ppc64le:
47     case Triple::systemz:
48     case Triple::x86:
49     case Triple::x86_64:
50       ActiveTraits.set(unsigned(TraitProperty::target_device_kind_cpu));
51       break;
52     case Triple::amdgcn:
53     case Triple::nvptx:
54     case Triple::nvptx64:
55     case Triple::spirv64:
56       ActiveTraits.set(unsigned(TraitProperty::target_device_kind_gpu));
57       break;
58     default:
59       break;
60     }
61     // Add the appropriate device architecture trait based on the triple.
62 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
63   if (TraitSelector::TraitSelectorEnum == TraitSelector::target_device_arch) { \
64     if (TargetOffloadTriple.getArch() ==                                       \
65         TargetOffloadTriple.getArchTypeForLLVMName(Str))                       \
66       ActiveTraits.set(unsigned(TraitProperty::Enum));                         \
67     if (StringRef(Str) == "x86_64" &&                                          \
68         TargetOffloadTriple.getArch() == Triple::x86_64)                       \
69       ActiveTraits.set(unsigned(TraitProperty::Enum));                         \
70   }
71 #include "llvm/Frontend/OpenMP/OMPKinds.def"
72   } else {
73     // Add the appropriate device kind trait based on the triple and the
74     // IsDeviceCompilation flag.
75     ActiveTraits.set(unsigned(IsDeviceCompilation
76                                   ? TraitProperty::device_kind_nohost
77                                   : TraitProperty::device_kind_host));
78     ActiveTraits.set(unsigned(TraitProperty::target_device_kind_host));
79     switch (TargetTriple.getArch()) {
80     case Triple::arm:
81     case Triple::armeb:
82     case Triple::aarch64:
83     case Triple::aarch64_be:
84     case Triple::aarch64_32:
85     case Triple::mips:
86     case Triple::mipsel:
87     case Triple::mips64:
88     case Triple::mips64el:
89     case Triple::ppc:
90     case Triple::ppcle:
91     case Triple::ppc64:
92     case Triple::ppc64le:
93     case Triple::systemz:
94     case Triple::x86:
95     case Triple::x86_64:
96       ActiveTraits.set(unsigned(TraitProperty::device_kind_cpu));
97       ActiveTraits.set(unsigned(TraitProperty::target_device_kind_cpu));
98       break;
99     case Triple::amdgcn:
100     case Triple::nvptx:
101     case Triple::nvptx64:
102     case Triple::spirv64:
103       ActiveTraits.set(unsigned(TraitProperty::device_kind_gpu));
104       ActiveTraits.set(unsigned(TraitProperty::target_device_kind_gpu));
105       break;
106     default:
107       break;
108     }
109 
110     // Add the appropriate device architecture trait based on the triple.
111 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
112   if (TraitSelector::TraitSelectorEnum == TraitSelector::device_arch ||        \
113       TraitSelector::TraitSelectorEnum == TraitSelector::target_device_arch) { \
114     if (TargetTriple.getArch() == TargetTriple.getArchTypeForLLVMName(Str))    \
115       ActiveTraits.set(unsigned(TraitProperty::Enum));                         \
116     if (StringRef(Str) == "x86_64" &&                                          \
117         TargetTriple.getArch() == Triple::x86_64)                              \
118       ActiveTraits.set(unsigned(TraitProperty::Enum));                         \
119   }
120 #include "llvm/Frontend/OpenMP/OMPKinds.def"
121 
122     // TODO: What exactly do we want to see as device ISA trait?
123     //       The discussion on the list did not seem to have come to an agreed
124     //       upon solution.
125 
126     // LLVM is the "OpenMP vendor" but we could also interpret vendor as the
127     // target vendor.
128     ActiveTraits.set(unsigned(TraitProperty::implementation_vendor_llvm));
129 
130     // The user condition true is accepted but not false.
131     ActiveTraits.set(unsigned(TraitProperty::user_condition_true));
132 
133     // This is for sure some device.
134     ActiveTraits.set(unsigned(TraitProperty::device_kind_any));
135 
136     LLVM_DEBUG({
137       dbgs() << "[" << DEBUG_TYPE
138              << "] New OpenMP context with the following properties:\n";
139       for (unsigned Bit : ActiveTraits.set_bits()) {
140         TraitProperty Property = TraitProperty(Bit);
141         dbgs() << "\t " << getOpenMPContextTraitPropertyFullName(Property)
142                << "\n";
143       }
144     });
145   }
146 }
147 
148 /// Return true if \p C0 is a subset of \p C1. Note that both arrays are
149 /// expected to be sorted.
isSubset(ArrayRef<T> C0,ArrayRef<T> C1)150 template <typename T> static bool isSubset(ArrayRef<T> C0, ArrayRef<T> C1) {
151 #ifdef EXPENSIVE_CHECKS
152   assert(llvm::is_sorted(C0) && llvm::is_sorted(C1) &&
153          "Expected sorted arrays!");
154 #endif
155   if (C0.size() > C1.size())
156     return false;
157   auto It0 = C0.begin(), End0 = C0.end();
158   auto It1 = C1.begin(), End1 = C1.end();
159   while (It0 != End0) {
160     if (It1 == End1)
161       return false;
162     if (*It0 == *It1) {
163       ++It0;
164       ++It1;
165       continue;
166     }
167     ++It0;
168   }
169   return true;
170 }
171 
172 /// Return true if \p C0 is a strict subset of \p C1. Note that both arrays are
173 /// expected to be sorted.
174 template <typename T>
isStrictSubset(ArrayRef<T> C0,ArrayRef<T> C1)175 static bool isStrictSubset(ArrayRef<T> C0, ArrayRef<T> C1) {
176   if (C0.size() >= C1.size())
177     return false;
178   return isSubset<T>(C0, C1);
179 }
180 
isStrictSubset(const VariantMatchInfo & VMI0,const VariantMatchInfo & VMI1)181 static bool isStrictSubset(const VariantMatchInfo &VMI0,
182                            const VariantMatchInfo &VMI1) {
183   // If all required traits are a strict subset and the ordered vectors storing
184   // the construct traits, we say it is a strict subset. Note that the latter
185   // relation is not required to be strict.
186   if (VMI0.RequiredTraits.count() >= VMI1.RequiredTraits.count())
187     return false;
188   for (unsigned Bit : VMI0.RequiredTraits.set_bits())
189     if (!VMI1.RequiredTraits.test(Bit))
190       return false;
191   if (!isSubset<TraitProperty>(VMI0.ConstructTraits, VMI1.ConstructTraits))
192     return false;
193   return true;
194 }
195 
196 static int
isVariantApplicableInContextHelper(const VariantMatchInfo & VMI,const OMPContext & Ctx,SmallVectorImpl<unsigned> * ConstructMatches,bool DeviceOrImplementationSetOnly)197 isVariantApplicableInContextHelper(const VariantMatchInfo &VMI,
198                                    const OMPContext &Ctx,
199                                    SmallVectorImpl<unsigned> *ConstructMatches,
200                                    bool DeviceOrImplementationSetOnly) {
201 
202   // The match kind determines if we need to match all traits, any of the
203   // traits, or none of the traits for it to be an applicable context.
204   enum MatchKind { MK_ALL, MK_ANY, MK_NONE };
205 
206   MatchKind MK = MK_ALL;
207   // Determine the match kind the user wants, "all" is the default and provided
208   // to the user only for completeness.
209   if (VMI.RequiredTraits.test(
210           unsigned(TraitProperty::implementation_extension_match_any)))
211     MK = MK_ANY;
212   if (VMI.RequiredTraits.test(
213           unsigned(TraitProperty::implementation_extension_match_none)))
214     MK = MK_NONE;
215 
216   // Helper to deal with a single property that was (not) found in the OpenMP
217   // context based on the match kind selected by the user via
218   // `implementation={extensions(match_[all,any,none])}'
219   auto HandleTrait = [MK](TraitProperty Property,
220                           bool WasFound) -> std::optional<bool> /* Result */ {
221     // For kind "any" a single match is enough but we ignore non-matched
222     // properties.
223     if (MK == MK_ANY) {
224       if (WasFound)
225         return true;
226       return std::nullopt;
227     }
228 
229     // In "all" or "none" mode we accept a matching or non-matching property
230     // respectively and move on. We are not done yet!
231     if ((WasFound && MK == MK_ALL) || (!WasFound && MK == MK_NONE))
232       return std::nullopt;
233 
234     // We missed a property, provide some debug output and indicate failure.
235     LLVM_DEBUG({
236       if (MK == MK_ALL)
237         dbgs() << "[" << DEBUG_TYPE << "] Property "
238                << getOpenMPContextTraitPropertyName(Property, "")
239                << " was not in the OpenMP context but match kind is all.\n";
240       if (MK == MK_NONE)
241         dbgs() << "[" << DEBUG_TYPE << "] Property "
242                << getOpenMPContextTraitPropertyName(Property, "")
243                << " was in the OpenMP context but match kind is none.\n";
244     });
245     return false;
246   };
247 
248   for (unsigned Bit : VMI.RequiredTraits.set_bits()) {
249     TraitProperty Property = TraitProperty(Bit);
250     if (DeviceOrImplementationSetOnly &&
251         getOpenMPContextTraitSetForProperty(Property) != TraitSet::device &&
252         getOpenMPContextTraitSetForProperty(Property) !=
253             TraitSet::implementation)
254       continue;
255 
256     // So far all extensions are handled elsewhere, we skip them here as they
257     // are not part of the OpenMP context.
258     if (getOpenMPContextTraitSelectorForProperty(Property) ==
259         TraitSelector::implementation_extension)
260       continue;
261 
262     bool IsActiveTrait = Ctx.ActiveTraits.test(unsigned(Property));
263 
264     // We overwrite the isa trait as it is actually up to the OMPContext hook to
265     // check the raw string(s).
266     if (Property == TraitProperty::device_isa___ANY)
267       IsActiveTrait = llvm::all_of(VMI.ISATraits, [&](StringRef RawString) {
268         return Ctx.matchesISATrait(RawString);
269       });
270     if (Property == TraitProperty::target_device_isa___ANY)
271       IsActiveTrait = llvm::all_of(VMI.ISATraits, [&](StringRef RawString) {
272         return Ctx.matchesISATrait(RawString);
273       });
274 
275     if (std::optional<bool> Result = HandleTrait(Property, IsActiveTrait))
276       return *Result;
277   }
278 
279   if (!DeviceOrImplementationSetOnly) {
280     // We could use isSubset here but we also want to record the match
281     // locations.
282     unsigned ConstructIdx = 0, NoConstructTraits = Ctx.ConstructTraits.size();
283     for (TraitProperty Property : VMI.ConstructTraits) {
284       assert(getOpenMPContextTraitSetForProperty(Property) ==
285                  TraitSet::construct &&
286              "Variant context is ill-formed!");
287 
288       // Verify the nesting.
289       bool FoundInOrder = false;
290       while (!FoundInOrder && ConstructIdx != NoConstructTraits)
291         FoundInOrder = (Ctx.ConstructTraits[ConstructIdx++] == Property);
292       if (ConstructMatches)
293         ConstructMatches->push_back(ConstructIdx - 1);
294 
295       if (std::optional<bool> Result = HandleTrait(Property, FoundInOrder))
296         return *Result;
297 
298       if (!FoundInOrder) {
299         LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Construct property "
300                           << getOpenMPContextTraitPropertyName(Property, "")
301                           << " was not nested properly.\n");
302         return false;
303       }
304 
305       // TODO: Verify SIMD
306     }
307 
308     assert(isSubset<TraitProperty>(VMI.ConstructTraits, Ctx.ConstructTraits) &&
309            "Broken invariant!");
310   }
311 
312   if (MK == MK_ANY) {
313     LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE
314                       << "] None of the properties was in the OpenMP context "
315                          "but match kind is any.\n");
316     return false;
317   }
318 
319   return true;
320 }
321 
isVariantApplicableInContext(const VariantMatchInfo & VMI,const OMPContext & Ctx,bool DeviceOrImplementationSetOnly)322 bool llvm::omp::isVariantApplicableInContext(
323     const VariantMatchInfo &VMI, const OMPContext &Ctx,
324     bool DeviceOrImplementationSetOnly) {
325   return isVariantApplicableInContextHelper(
326       VMI, Ctx, /* ConstructMatches */ nullptr, DeviceOrImplementationSetOnly);
327 }
328 
getVariantMatchScore(const VariantMatchInfo & VMI,const OMPContext & Ctx,SmallVectorImpl<unsigned> & ConstructMatches)329 static APInt getVariantMatchScore(const VariantMatchInfo &VMI,
330                                   const OMPContext &Ctx,
331                                   SmallVectorImpl<unsigned> &ConstructMatches) {
332   APInt Score(64, 1);
333 
334   unsigned NoConstructTraits = VMI.ConstructTraits.size();
335   for (unsigned Bit : VMI.RequiredTraits.set_bits()) {
336     TraitProperty Property = TraitProperty(Bit);
337     // If there is a user score attached, use it.
338     if (VMI.ScoreMap.count(Property)) {
339       const APInt &UserScore = VMI.ScoreMap.lookup(Property);
340       assert(UserScore.uge(0) && "Expect non-negative user scores!");
341       Score += UserScore.getZExtValue();
342       continue;
343     }
344 
345     switch (getOpenMPContextTraitSetForProperty(Property)) {
346     case TraitSet::construct:
347       // We handle the construct traits later via the VMI.ConstructTraits
348       // container.
349       continue;
350     case TraitSet::implementation:
351       // No effect on the score (implementation defined).
352       continue;
353     case TraitSet::user:
354       // No effect on the score.
355       continue;
356     case TraitSet::device:
357       // Handled separately below.
358       break;
359     case TraitSet::target_device:
360       // TODO: Handling separately.
361       break;
362     case TraitSet::invalid:
363       llvm_unreachable("Unknown trait set is not to be used!");
364     }
365 
366     // device={kind(any)} is "as if" no kind selector was specified.
367     if (Property == TraitProperty::device_kind_any)
368       continue;
369     if (Property == TraitProperty::target_device_kind_any)
370       continue;
371 
372     switch (getOpenMPContextTraitSelectorForProperty(Property)) {
373     case TraitSelector::device_kind:
374       Score += (1ULL << (NoConstructTraits + 0));
375       continue;
376     case TraitSelector::device_arch:
377       Score += (1ULL << (NoConstructTraits + 1));
378       continue;
379     case TraitSelector::device_isa:
380       Score += (1ULL << (NoConstructTraits + 2));
381       continue;
382     case TraitSelector::target_device_kind:
383       Score += (1ULL << (NoConstructTraits + 0));
384       continue;
385     case TraitSelector::target_device_arch:
386       Score += (1ULL << (NoConstructTraits + 1));
387       continue;
388     case TraitSelector::target_device_isa:
389       Score += (1ULL << (NoConstructTraits + 2));
390       continue;
391     default:
392       continue;
393     }
394   }
395 
396   unsigned ConstructIdx = 0;
397   assert(NoConstructTraits == ConstructMatches.size() &&
398          "Mismatch in the construct traits!");
399   for (TraitProperty Property : VMI.ConstructTraits) {
400     assert(getOpenMPContextTraitSetForProperty(Property) ==
401                TraitSet::construct &&
402            "Ill-formed variant match info!");
403     (void)Property;
404     // ConstructMatches is the position p - 1 and we need 2^(p-1).
405     Score += (1ULL << ConstructMatches[ConstructIdx++]);
406   }
407 
408   LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Variant has a score of " << Score
409                     << "\n");
410   return Score;
411 }
412 
getBestVariantMatchForContext(const SmallVectorImpl<VariantMatchInfo> & VMIs,const OMPContext & Ctx)413 int llvm::omp::getBestVariantMatchForContext(
414     const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext &Ctx) {
415 
416   APInt BestScore(64, 0);
417   int BestVMIIdx = -1;
418   const VariantMatchInfo *BestVMI = nullptr;
419 
420   for (unsigned u = 0, e = VMIs.size(); u < e; ++u) {
421     const VariantMatchInfo &VMI = VMIs[u];
422 
423     SmallVector<unsigned, 8> ConstructMatches;
424     // If the variant is not applicable its not the best.
425     if (!isVariantApplicableInContextHelper(
426             VMI, Ctx, &ConstructMatches,
427             /* DeviceOrImplementationSetOnly */ false))
428       continue;
429     // Check if its clearly not the best.
430     APInt Score = getVariantMatchScore(VMI, Ctx, ConstructMatches);
431     if (Score.ult(BestScore))
432       continue;
433     // Equal score need subset checks.
434     if (Score.eq(BestScore)) {
435       // Strict subset are never best.
436       if (isStrictSubset(VMI, *BestVMI))
437         continue;
438       // Same score and the current best is no strict subset so we keep it.
439       if (!isStrictSubset(*BestVMI, VMI))
440         continue;
441     }
442     // New best found.
443     BestVMI = &VMI;
444     BestVMIIdx = u;
445     BestScore = Score;
446   }
447 
448   return BestVMIIdx;
449 }
450 
getOpenMPContextTraitSetKind(StringRef S)451 TraitSet llvm::omp::getOpenMPContextTraitSetKind(StringRef S) {
452   return StringSwitch<TraitSet>(S)
453 #define OMP_TRAIT_SET(Enum, Str) .Case(Str, TraitSet::Enum)
454 #include "llvm/Frontend/OpenMP/OMPKinds.def"
455       .Default(TraitSet::invalid);
456 }
457 
458 TraitSet
getOpenMPContextTraitSetForSelector(TraitSelector Selector)459 llvm::omp::getOpenMPContextTraitSetForSelector(TraitSelector Selector) {
460   switch (Selector) {
461 #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
462   case TraitSelector::Enum:                                                    \
463     return TraitSet::TraitSetEnum;
464 #include "llvm/Frontend/OpenMP/OMPKinds.def"
465   }
466   llvm_unreachable("Unknown trait selector!");
467 }
468 TraitSet
getOpenMPContextTraitSetForProperty(TraitProperty Property)469 llvm::omp::getOpenMPContextTraitSetForProperty(TraitProperty Property) {
470   switch (Property) {
471 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
472   case TraitProperty::Enum:                                                    \
473     return TraitSet::TraitSetEnum;
474 #include "llvm/Frontend/OpenMP/OMPKinds.def"
475   }
476   llvm_unreachable("Unknown trait set!");
477 }
getOpenMPContextTraitSetName(TraitSet Kind)478 StringRef llvm::omp::getOpenMPContextTraitSetName(TraitSet Kind) {
479   switch (Kind) {
480 #define OMP_TRAIT_SET(Enum, Str)                                               \
481   case TraitSet::Enum:                                                         \
482     return Str;
483 #include "llvm/Frontend/OpenMP/OMPKinds.def"
484   }
485   llvm_unreachable("Unknown trait set!");
486 }
487 
getOpenMPContextTraitSelectorKind(StringRef S,TraitSet Set)488 TraitSelector llvm::omp::getOpenMPContextTraitSelectorKind(StringRef S,
489                                                            TraitSet Set) {
490   if (Set == TraitSet::target_device && S == "kind")
491     return TraitSelector::target_device_kind;
492   if (Set == TraitSet::target_device && S == "arch")
493     return TraitSelector::target_device_arch;
494   if (Set == TraitSet::target_device && S == "isa")
495     return TraitSelector::target_device_isa;
496   return StringSwitch<TraitSelector>(S)
497 #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
498   .Case(Str, TraitSelector::Enum)
499 #include "llvm/Frontend/OpenMP/OMPKinds.def"
500       .Default(TraitSelector::invalid);
501 }
502 TraitSelector
getOpenMPContextTraitSelectorForProperty(TraitProperty Property)503 llvm::omp::getOpenMPContextTraitSelectorForProperty(TraitProperty Property) {
504   switch (Property) {
505 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
506   case TraitProperty::Enum:                                                    \
507     return TraitSelector::TraitSelectorEnum;
508 #include "llvm/Frontend/OpenMP/OMPKinds.def"
509   }
510   llvm_unreachable("Unknown trait set!");
511 }
getOpenMPContextTraitSelectorName(TraitSelector Kind)512 StringRef llvm::omp::getOpenMPContextTraitSelectorName(TraitSelector Kind) {
513   switch (Kind) {
514 #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
515   case TraitSelector::Enum:                                                    \
516     return Str;
517 #include "llvm/Frontend/OpenMP/OMPKinds.def"
518   }
519   llvm_unreachable("Unknown trait selector!");
520 }
521 
getOpenMPContextTraitPropertyKind(TraitSet Set,TraitSelector Selector,StringRef S)522 TraitProperty llvm::omp::getOpenMPContextTraitPropertyKind(
523     TraitSet Set, TraitSelector Selector, StringRef S) {
524   // Special handling for `device={isa(...)}` as we accept anything here. It is
525   // up to the target to decide if the feature is available.
526   if (Set == TraitSet::device && Selector == TraitSelector::device_isa)
527     return TraitProperty::device_isa___ANY;
528   if (Set == TraitSet::target_device &&
529       Selector == TraitSelector::target_device_isa)
530     return TraitProperty::target_device_isa___ANY;
531 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
532   if (Set == TraitSet::TraitSetEnum && Str == S)                               \
533     return TraitProperty::Enum;
534 #include "llvm/Frontend/OpenMP/OMPKinds.def"
535   return TraitProperty::invalid;
536 }
537 TraitProperty
getOpenMPContextTraitPropertyForSelector(TraitSelector Selector)538 llvm::omp::getOpenMPContextTraitPropertyForSelector(TraitSelector Selector) {
539   return StringSwitch<TraitProperty>(
540              getOpenMPContextTraitSelectorName(Selector))
541 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
542   .Case(Str, Selector == TraitSelector::TraitSelectorEnum                      \
543                  ? TraitProperty::Enum                                         \
544                  : TraitProperty::invalid)
545 #include "llvm/Frontend/OpenMP/OMPKinds.def"
546       .Default(TraitProperty::invalid);
547 }
getOpenMPContextTraitPropertyName(TraitProperty Kind,StringRef RawString)548 StringRef llvm::omp::getOpenMPContextTraitPropertyName(TraitProperty Kind,
549                                                        StringRef RawString) {
550   if (Kind == TraitProperty::device_isa___ANY)
551     return RawString;
552   if (Kind == TraitProperty::target_device_isa___ANY)
553     return RawString;
554   switch (Kind) {
555 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
556   case TraitProperty::Enum:                                                    \
557     return Str;
558 #include "llvm/Frontend/OpenMP/OMPKinds.def"
559   }
560   llvm_unreachable("Unknown trait property!");
561 }
getOpenMPContextTraitPropertyFullName(TraitProperty Kind)562 StringRef llvm::omp::getOpenMPContextTraitPropertyFullName(TraitProperty Kind) {
563   switch (Kind) {
564 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
565   case TraitProperty::Enum:                                                    \
566     return "(" #TraitSetEnum "," #TraitSelectorEnum "," Str ")";
567 #include "llvm/Frontend/OpenMP/OMPKinds.def"
568   }
569   llvm_unreachable("Unknown trait property!");
570 }
571 
isValidTraitSelectorForTraitSet(TraitSelector Selector,TraitSet Set,bool & AllowsTraitScore,bool & RequiresProperty)572 bool llvm::omp::isValidTraitSelectorForTraitSet(TraitSelector Selector,
573                                                 TraitSet Set,
574                                                 bool &AllowsTraitScore,
575                                                 bool &RequiresProperty) {
576   AllowsTraitScore = Set != TraitSet::construct && Set != TraitSet::device &&
577                      Set != TraitSet::target_device;
578   switch (Selector) {
579 #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
580   case TraitSelector::Enum:                                                    \
581     RequiresProperty = ReqProp;                                                \
582     return Set == TraitSet::TraitSetEnum;
583 #include "llvm/Frontend/OpenMP/OMPKinds.def"
584   }
585   llvm_unreachable("Unknown trait selector!");
586 }
587 
isValidTraitPropertyForTraitSetAndSelector(TraitProperty Property,TraitSelector Selector,TraitSet Set)588 bool llvm::omp::isValidTraitPropertyForTraitSetAndSelector(
589     TraitProperty Property, TraitSelector Selector, TraitSet Set) {
590   switch (Property) {
591 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
592   case TraitProperty::Enum:                                                    \
593     return Set == TraitSet::TraitSetEnum &&                                    \
594            Selector == TraitSelector::TraitSelectorEnum;
595 #include "llvm/Frontend/OpenMP/OMPKinds.def"
596   }
597   llvm_unreachable("Unknown trait property!");
598 }
599 
listOpenMPContextTraitSets()600 std::string llvm::omp::listOpenMPContextTraitSets() {
601   std::string S;
602 #define OMP_TRAIT_SET(Enum, Str)                                               \
603   if (StringRef(Str) != "invalid")                                             \
604     S.append("'").append(Str).append("'").append(" ");
605 #include "llvm/Frontend/OpenMP/OMPKinds.def"
606   S.pop_back();
607   return S;
608 }
609 
listOpenMPContextTraitSelectors(TraitSet Set)610 std::string llvm::omp::listOpenMPContextTraitSelectors(TraitSet Set) {
611   std::string S;
612 #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
613   if (TraitSet::TraitSetEnum == Set && StringRef(Str) != "Invalid")            \
614     S.append("'").append(Str).append("'").append(" ");
615 #include "llvm/Frontend/OpenMP/OMPKinds.def"
616   S.pop_back();
617   return S;
618 }
619 
620 std::string
listOpenMPContextTraitProperties(TraitSet Set,TraitSelector Selector)621 llvm::omp::listOpenMPContextTraitProperties(TraitSet Set,
622                                             TraitSelector Selector) {
623   std::string S;
624 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
625   if (TraitSet::TraitSetEnum == Set &&                                         \
626       TraitSelector::TraitSelectorEnum == Selector &&                          \
627       StringRef(Str) != "invalid")                                             \
628     S.append("'").append(Str).append("'").append(" ");
629 #include "llvm/Frontend/OpenMP/OMPKinds.def"
630   if (S.empty())
631     return "<none>";
632   S.pop_back();
633   return S;
634 }
635