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