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"
17d970a285SJohannes Doerfert #include "llvm/ADT/StringRef.h"
18c953409fSJohannes Doerfert #include "llvm/ADT/StringSwitch.h"
19d970a285SJohannes Doerfert #include "llvm/ADT/Triple.h"
20c953409fSJohannes Doerfert #include "llvm/Support/Debug.h"
21c953409fSJohannes Doerfert #include "llvm/Support/raw_ostream.h"
22c953409fSJohannes Doerfert 
23c953409fSJohannes Doerfert #define DEBUG_TYPE "openmp-ir-builder"
24c953409fSJohannes Doerfert 
25c953409fSJohannes Doerfert using namespace llvm;
26c953409fSJohannes Doerfert using namespace omp;
27c953409fSJohannes Doerfert 
28c953409fSJohannes Doerfert OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) {
29c953409fSJohannes Doerfert   // Add the appropriate device kind trait based on the triple and the
30c953409fSJohannes Doerfert   // IsDeviceCompilation flag.
316b57d7f5SJohannes Doerfert   ActiveTraits.set(unsigned(IsDeviceCompilation
326b57d7f5SJohannes Doerfert                                 ? TraitProperty::device_kind_nohost
336b57d7f5SJohannes Doerfert                                 : TraitProperty::device_kind_host));
34c953409fSJohannes Doerfert   switch (TargetTriple.getArch()) {
35c953409fSJohannes Doerfert   case Triple::arm:
36c953409fSJohannes Doerfert   case Triple::armeb:
37c953409fSJohannes Doerfert   case Triple::aarch64:
38c953409fSJohannes Doerfert   case Triple::aarch64_be:
39c953409fSJohannes Doerfert   case Triple::aarch64_32:
40c953409fSJohannes Doerfert   case Triple::mips:
41c953409fSJohannes Doerfert   case Triple::mipsel:
42c953409fSJohannes Doerfert   case Triple::mips64:
43c953409fSJohannes Doerfert   case Triple::mips64el:
44c953409fSJohannes Doerfert   case Triple::ppc:
4522883197SBrandon Bergren   case Triple::ppcle:
46c953409fSJohannes Doerfert   case Triple::ppc64:
47c953409fSJohannes Doerfert   case Triple::ppc64le:
48c953409fSJohannes Doerfert   case Triple::x86:
49c953409fSJohannes Doerfert   case Triple::x86_64:
506b57d7f5SJohannes Doerfert     ActiveTraits.set(unsigned(TraitProperty::device_kind_cpu));
51c953409fSJohannes Doerfert     break;
52c953409fSJohannes Doerfert   case Triple::amdgcn:
53c953409fSJohannes Doerfert   case Triple::nvptx:
54c953409fSJohannes Doerfert   case Triple::nvptx64:
556b57d7f5SJohannes Doerfert     ActiveTraits.set(unsigned(TraitProperty::device_kind_gpu));
56c953409fSJohannes Doerfert     break;
57c953409fSJohannes Doerfert   default:
58c953409fSJohannes Doerfert     break;
59c953409fSJohannes Doerfert   }
60c953409fSJohannes Doerfert 
61c953409fSJohannes Doerfert   // Add the appropriate device architecture trait based on the triple.
62c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
63d970a285SJohannes Doerfert   if (TraitSelector::TraitSelectorEnum == TraitSelector::device_arch) {        \
64c953409fSJohannes Doerfert     if (TargetTriple.getArch() == TargetTriple.getArchTypeForLLVMName(Str))    \
65d970a285SJohannes Doerfert       ActiveTraits.set(unsigned(TraitProperty::Enum));                         \
66*0b0f2e6eSJohannes Doerfert     if (StringRef(Str) == StringRef("x86_64") &&                               \
67*0b0f2e6eSJohannes Doerfert         TargetTriple.getArch() == Triple::x86_64)                              \
68d970a285SJohannes Doerfert       ActiveTraits.set(unsigned(TraitProperty::Enum));                         \
69d970a285SJohannes Doerfert   }
70c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
71c953409fSJohannes Doerfert 
72c953409fSJohannes Doerfert   // TODO: What exactly do we want to see as device ISA trait?
73c953409fSJohannes Doerfert   //       The discussion on the list did not seem to have come to an agreed
74c953409fSJohannes Doerfert   //       upon solution.
75c953409fSJohannes Doerfert 
76c953409fSJohannes Doerfert   // LLVM is the "OpenMP vendor" but we could also interpret vendor as the
77c953409fSJohannes Doerfert   // target vendor.
786b57d7f5SJohannes Doerfert   ActiveTraits.set(unsigned(TraitProperty::implementation_vendor_llvm));
79c953409fSJohannes Doerfert 
80c953409fSJohannes Doerfert   // The user condition true is accepted but not false.
816b57d7f5SJohannes Doerfert   ActiveTraits.set(unsigned(TraitProperty::user_condition_true));
82c953409fSJohannes Doerfert 
83c953409fSJohannes Doerfert   // This is for sure some device.
846b57d7f5SJohannes Doerfert   ActiveTraits.set(unsigned(TraitProperty::device_kind_any));
85c953409fSJohannes Doerfert 
86c953409fSJohannes Doerfert   LLVM_DEBUG({
87c953409fSJohannes Doerfert     dbgs() << "[" << DEBUG_TYPE
88c953409fSJohannes Doerfert            << "] New OpenMP context with the following properties:\n";
8999913ef3SFlorian Hahn     for (unsigned Bit : ActiveTraits.set_bits()) {
9099913ef3SFlorian Hahn       TraitProperty Property = TraitProperty(Bit);
91c953409fSJohannes Doerfert       dbgs() << "\t " << getOpenMPContextTraitPropertyFullName(Property)
92c953409fSJohannes Doerfert              << "\n";
936b57d7f5SJohannes Doerfert     }
94c953409fSJohannes Doerfert   });
95c953409fSJohannes Doerfert }
96c953409fSJohannes Doerfert 
97c953409fSJohannes Doerfert /// Return true if \p C0 is a subset of \p C1. Note that both arrays are
98c953409fSJohannes Doerfert /// expected to be sorted.
99c953409fSJohannes Doerfert template <typename T> static bool isSubset(ArrayRef<T> C0, ArrayRef<T> C1) {
100c953409fSJohannes Doerfert #ifdef EXPENSIVE_CHECKS
1011647ff6eSGeorgii Rymar   assert(llvm::is_sorted(C0) && llvm::is_sorted(C1) &&
1021647ff6eSGeorgii Rymar          "Expected sorted arrays!");
103c953409fSJohannes Doerfert #endif
104c953409fSJohannes Doerfert   if (C0.size() > C1.size())
105c953409fSJohannes Doerfert     return false;
106c953409fSJohannes Doerfert   auto It0 = C0.begin(), End0 = C0.end();
107c953409fSJohannes Doerfert   auto It1 = C1.begin(), End1 = C1.end();
108c953409fSJohannes Doerfert   while (It0 != End0) {
109c953409fSJohannes Doerfert     if (It1 == End1)
110c953409fSJohannes Doerfert       return false;
111c953409fSJohannes Doerfert     if (*It0 == *It1) {
112c953409fSJohannes Doerfert       ++It0;
113c953409fSJohannes Doerfert       ++It1;
114c953409fSJohannes Doerfert       continue;
115c953409fSJohannes Doerfert     }
116c953409fSJohannes Doerfert     ++It0;
117c953409fSJohannes Doerfert   }
118c953409fSJohannes Doerfert   return true;
119c953409fSJohannes Doerfert }
120c953409fSJohannes Doerfert 
121c953409fSJohannes Doerfert /// Return true if \p C0 is a strict subset of \p C1. Note that both arrays are
122c953409fSJohannes Doerfert /// expected to be sorted.
123c953409fSJohannes Doerfert template <typename T>
124c953409fSJohannes Doerfert static bool isStrictSubset(ArrayRef<T> C0, ArrayRef<T> C1) {
125c953409fSJohannes Doerfert   if (C0.size() >= C1.size())
126c953409fSJohannes Doerfert     return false;
127c953409fSJohannes Doerfert   return isSubset<T>(C0, C1);
128c953409fSJohannes Doerfert }
129c953409fSJohannes Doerfert 
130c953409fSJohannes Doerfert static bool isStrictSubset(const VariantMatchInfo &VMI0,
131c953409fSJohannes Doerfert                            const VariantMatchInfo &VMI1) {
132c953409fSJohannes Doerfert   // If all required traits are a strict subset and the ordered vectors storing
133c953409fSJohannes Doerfert   // the construct traits, we say it is a strict subset. Note that the latter
134c953409fSJohannes Doerfert   // relation is not required to be strict.
1356b57d7f5SJohannes Doerfert   if (VMI0.RequiredTraits.count() >= VMI1.RequiredTraits.count())
1366b57d7f5SJohannes Doerfert     return false;
13799913ef3SFlorian Hahn   for (unsigned Bit : VMI0.RequiredTraits.set_bits())
13899913ef3SFlorian Hahn     if (!VMI1.RequiredTraits.test(Bit))
1396b57d7f5SJohannes Doerfert       return false;
1406b57d7f5SJohannes Doerfert   if (!isSubset<TraitProperty>(VMI0.ConstructTraits, VMI1.ConstructTraits))
1416b57d7f5SJohannes Doerfert     return false;
1426b57d7f5SJohannes Doerfert   return true;
143c953409fSJohannes Doerfert }
144c953409fSJohannes Doerfert 
145c953409fSJohannes Doerfert static int isVariantApplicableInContextHelper(
146c953409fSJohannes Doerfert     const VariantMatchInfo &VMI, const OMPContext &Ctx,
147a19eb1deSJohannes Doerfert     SmallVectorImpl<unsigned> *ConstructMatches, bool DeviceSetOnly) {
148a19eb1deSJohannes Doerfert 
149a19eb1deSJohannes Doerfert   // The match kind determines if we need to match all traits, any of the
150a19eb1deSJohannes Doerfert   // traits, or none of the traits for it to be an applicable context.
151a19eb1deSJohannes Doerfert   enum MatchKind { MK_ALL, MK_ANY, MK_NONE };
152a19eb1deSJohannes Doerfert 
153a19eb1deSJohannes Doerfert   MatchKind MK = MK_ALL;
154a19eb1deSJohannes Doerfert   // Determine the match kind the user wants, "all" is the default and provided
155a19eb1deSJohannes Doerfert   // to the user only for completeness.
156a19eb1deSJohannes Doerfert   if (VMI.RequiredTraits.test(
157a19eb1deSJohannes Doerfert           unsigned(TraitProperty::implementation_extension_match_any)))
158a19eb1deSJohannes Doerfert     MK = MK_ANY;
159a19eb1deSJohannes Doerfert   if (VMI.RequiredTraits.test(
160a19eb1deSJohannes Doerfert           unsigned(TraitProperty::implementation_extension_match_none)))
161a19eb1deSJohannes Doerfert     MK = MK_NONE;
162a19eb1deSJohannes Doerfert 
163a19eb1deSJohannes Doerfert   // Helper to deal with a single property that was (not) found in the OpenMP
164a19eb1deSJohannes Doerfert   // context based on the match kind selected by the user via
165a19eb1deSJohannes Doerfert   // `implementation={extensions(match_[all,any,none])}'
166a19eb1deSJohannes Doerfert   auto HandleTrait = [MK](TraitProperty Property,
167a19eb1deSJohannes Doerfert                           bool WasFound) -> Optional<bool> /* Result */ {
168a19eb1deSJohannes Doerfert     // For kind "any" a single match is enough but we ignore non-matched
169a19eb1deSJohannes Doerfert     // properties.
170a19eb1deSJohannes Doerfert     if (MK == MK_ANY) {
171a19eb1deSJohannes Doerfert       if (WasFound)
172a19eb1deSJohannes Doerfert         return true;
173a19eb1deSJohannes Doerfert       return None;
174a19eb1deSJohannes Doerfert     }
175a19eb1deSJohannes Doerfert 
176a19eb1deSJohannes Doerfert     // In "all" or "none" mode we accept a matching or non-matching property
177a19eb1deSJohannes Doerfert     // respectively and move on. We are not done yet!
178a19eb1deSJohannes Doerfert     if ((WasFound && MK == MK_ALL) || (!WasFound && MK == MK_NONE))
179a19eb1deSJohannes Doerfert       return None;
180a19eb1deSJohannes Doerfert 
181a19eb1deSJohannes Doerfert     // We missed a property, provide some debug output and indicate failure.
182a19eb1deSJohannes Doerfert     LLVM_DEBUG({
183a19eb1deSJohannes Doerfert       if (MK == MK_ALL)
184a19eb1deSJohannes Doerfert         dbgs() << "[" << DEBUG_TYPE << "] Property "
185ee05167cSJohannes Doerfert                << getOpenMPContextTraitPropertyName(Property, "")
186a19eb1deSJohannes Doerfert                << " was not in the OpenMP context but match kind is all.\n";
187a19eb1deSJohannes Doerfert       if (MK == MK_NONE)
188a19eb1deSJohannes Doerfert         dbgs() << "[" << DEBUG_TYPE << "] Property "
189ee05167cSJohannes Doerfert                << getOpenMPContextTraitPropertyName(Property, "")
190a19eb1deSJohannes Doerfert                << " was in the OpenMP context but match kind is none.\n";
191a19eb1deSJohannes Doerfert     });
192a19eb1deSJohannes Doerfert     return false;
193a19eb1deSJohannes Doerfert   };
194c953409fSJohannes Doerfert 
19599913ef3SFlorian Hahn   for (unsigned Bit : VMI.RequiredTraits.set_bits()) {
19699913ef3SFlorian Hahn     TraitProperty Property = TraitProperty(Bit);
197a19eb1deSJohannes Doerfert     if (DeviceSetOnly &&
198a19eb1deSJohannes Doerfert         getOpenMPContextTraitSetForProperty(Property) != TraitSet::device)
199a19eb1deSJohannes Doerfert       continue;
200a19eb1deSJohannes Doerfert 
201a19eb1deSJohannes Doerfert     // So far all extensions are handled elsewhere, we skip them here as they
202a19eb1deSJohannes Doerfert     // are not part of the OpenMP context.
203a19eb1deSJohannes Doerfert     if (getOpenMPContextTraitSelectorForProperty(Property) ==
204a19eb1deSJohannes Doerfert         TraitSelector::implementation_extension)
205a19eb1deSJohannes Doerfert       continue;
206c953409fSJohannes Doerfert 
2076b57d7f5SJohannes Doerfert     bool IsActiveTrait = Ctx.ActiveTraits.test(unsigned(Property));
208ee05167cSJohannes Doerfert 
209ee05167cSJohannes Doerfert     // We overwrite the isa trait as it is actually up to the OMPContext hook to
210ee05167cSJohannes Doerfert     // check the raw string(s).
211ee05167cSJohannes Doerfert     if (Property == TraitProperty::device_isa___ANY)
212ee05167cSJohannes Doerfert       IsActiveTrait = llvm::all_of(VMI.ISATraits, [&](StringRef RawString) {
213ee05167cSJohannes Doerfert         return Ctx.matchesISATrait(RawString);
214ee05167cSJohannes Doerfert       });
215ee05167cSJohannes Doerfert 
216a19eb1deSJohannes Doerfert     Optional<bool> Result = HandleTrait(Property, IsActiveTrait);
217a19eb1deSJohannes Doerfert     if (Result.hasValue())
218a19eb1deSJohannes Doerfert       return Result.getValue();
219c953409fSJohannes Doerfert   }
220c953409fSJohannes Doerfert 
221a19eb1deSJohannes Doerfert   if (!DeviceSetOnly) {
222a19eb1deSJohannes Doerfert     // We could use isSubset here but we also want to record the match
223a19eb1deSJohannes Doerfert     // locations.
224c953409fSJohannes Doerfert     unsigned ConstructIdx = 0, NoConstructTraits = Ctx.ConstructTraits.size();
225c953409fSJohannes Doerfert     for (TraitProperty Property : VMI.ConstructTraits) {
226c953409fSJohannes Doerfert       assert(getOpenMPContextTraitSetForProperty(Property) ==
227c953409fSJohannes Doerfert                  TraitSet::construct &&
228c953409fSJohannes Doerfert              "Variant context is ill-formed!");
229c953409fSJohannes Doerfert 
230c953409fSJohannes Doerfert       // Verify the nesting.
231c953409fSJohannes Doerfert       bool FoundInOrder = false;
232c953409fSJohannes Doerfert       while (!FoundInOrder && ConstructIdx != NoConstructTraits)
233c953409fSJohannes Doerfert         FoundInOrder = (Ctx.ConstructTraits[ConstructIdx++] == Property);
234c953409fSJohannes Doerfert       if (ConstructMatches)
235c953409fSJohannes Doerfert         ConstructMatches->push_back(ConstructIdx - 1);
236c953409fSJohannes Doerfert 
237a19eb1deSJohannes Doerfert       Optional<bool> Result = HandleTrait(Property, FoundInOrder);
238a19eb1deSJohannes Doerfert       if (Result.hasValue())
239a19eb1deSJohannes Doerfert         return Result.getValue();
240a19eb1deSJohannes Doerfert 
241c953409fSJohannes Doerfert       if (!FoundInOrder) {
242c953409fSJohannes Doerfert         LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Construct property "
243ee05167cSJohannes Doerfert                           << getOpenMPContextTraitPropertyName(Property, "")
244c953409fSJohannes Doerfert                           << " was not nested properly.\n");
245c953409fSJohannes Doerfert         return false;
246c953409fSJohannes Doerfert       }
247c953409fSJohannes Doerfert 
248c953409fSJohannes Doerfert       // TODO: Verify SIMD
249c953409fSJohannes Doerfert     }
250c953409fSJohannes Doerfert 
251c953409fSJohannes Doerfert     assert(isSubset<TraitProperty>(VMI.ConstructTraits, Ctx.ConstructTraits) &&
252c953409fSJohannes Doerfert            "Broken invariant!");
253a19eb1deSJohannes Doerfert   }
254a19eb1deSJohannes Doerfert 
255a19eb1deSJohannes Doerfert   if (MK == MK_ANY) {
256a19eb1deSJohannes Doerfert     LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE
257a19eb1deSJohannes Doerfert                       << "] None of the properties was in the OpenMP context "
258a19eb1deSJohannes Doerfert                          "but match kind is any.\n");
259a19eb1deSJohannes Doerfert     return false;
260a19eb1deSJohannes Doerfert   }
261a19eb1deSJohannes Doerfert 
262c953409fSJohannes Doerfert   return true;
263c953409fSJohannes Doerfert }
264c953409fSJohannes Doerfert 
265c953409fSJohannes Doerfert bool llvm::omp::isVariantApplicableInContext(const VariantMatchInfo &VMI,
266a19eb1deSJohannes Doerfert                                              const OMPContext &Ctx,
267a19eb1deSJohannes Doerfert                                              bool DeviceSetOnly) {
268a19eb1deSJohannes Doerfert   return isVariantApplicableInContextHelper(
269a19eb1deSJohannes Doerfert       VMI, Ctx, /* ConstructMatches */ nullptr, DeviceSetOnly);
270c953409fSJohannes Doerfert }
271c953409fSJohannes Doerfert 
272c953409fSJohannes Doerfert static APInt getVariantMatchScore(const VariantMatchInfo &VMI,
273c953409fSJohannes Doerfert                                   const OMPContext &Ctx,
274c953409fSJohannes Doerfert                                   SmallVectorImpl<unsigned> &ConstructMatches) {
275c953409fSJohannes Doerfert   APInt Score(64, 1);
276c953409fSJohannes Doerfert 
277c953409fSJohannes Doerfert   unsigned NoConstructTraits = VMI.ConstructTraits.size();
27899913ef3SFlorian Hahn   for (unsigned Bit : VMI.RequiredTraits.set_bits()) {
27999913ef3SFlorian Hahn     TraitProperty Property = TraitProperty(Bit);
280c953409fSJohannes Doerfert     // If there is a user score attached, use it.
281c953409fSJohannes Doerfert     if (VMI.ScoreMap.count(Property)) {
282c953409fSJohannes Doerfert       const APInt &UserScore = VMI.ScoreMap.lookup(Property);
283c953409fSJohannes Doerfert       assert(UserScore.uge(0) && "Expect non-negative user scores!");
284c953409fSJohannes Doerfert       Score += UserScore.getZExtValue();
285c953409fSJohannes Doerfert       continue;
286c953409fSJohannes Doerfert     }
287c953409fSJohannes Doerfert 
288c953409fSJohannes Doerfert     switch (getOpenMPContextTraitSetForProperty(Property)) {
289c953409fSJohannes Doerfert     case TraitSet::construct:
290c953409fSJohannes Doerfert       // We handle the construct traits later via the VMI.ConstructTraits
291c953409fSJohannes Doerfert       // container.
292c953409fSJohannes Doerfert       continue;
293c953409fSJohannes Doerfert     case TraitSet::implementation:
294c953409fSJohannes Doerfert       // No effect on the score (implementation defined).
295c953409fSJohannes Doerfert       continue;
296c953409fSJohannes Doerfert     case TraitSet::user:
297c953409fSJohannes Doerfert       // No effect on the score.
298c953409fSJohannes Doerfert       continue;
299c953409fSJohannes Doerfert     case TraitSet::device:
300c953409fSJohannes Doerfert       // Handled separately below.
301c953409fSJohannes Doerfert       break;
302c953409fSJohannes Doerfert     case TraitSet::invalid:
303c953409fSJohannes Doerfert       llvm_unreachable("Unknown trait set is not to be used!");
304c953409fSJohannes Doerfert     }
305c953409fSJohannes Doerfert 
306c953409fSJohannes Doerfert     // device={kind(any)} is "as if" no kind selector was specified.
307c953409fSJohannes Doerfert     if (Property == TraitProperty::device_kind_any)
308c953409fSJohannes Doerfert       continue;
309c953409fSJohannes Doerfert 
310c953409fSJohannes Doerfert     switch (getOpenMPContextTraitSelectorForProperty(Property)) {
311c953409fSJohannes Doerfert     case TraitSelector::device_kind:
312ae5d3e8cSSimon Pilgrim       Score += (1ULL << (NoConstructTraits + 0));
313c953409fSJohannes Doerfert       continue;
314c953409fSJohannes Doerfert     case TraitSelector::device_arch:
315ae5d3e8cSSimon Pilgrim       Score += (1ULL << (NoConstructTraits + 1));
316c953409fSJohannes Doerfert       continue;
317c953409fSJohannes Doerfert     case TraitSelector::device_isa:
318ae5d3e8cSSimon Pilgrim       Score += (1ULL << (NoConstructTraits + 2));
319c953409fSJohannes Doerfert       continue;
320c953409fSJohannes Doerfert     default:
321c953409fSJohannes Doerfert       continue;
322c953409fSJohannes Doerfert     }
323c953409fSJohannes Doerfert   }
324c953409fSJohannes Doerfert 
325c953409fSJohannes Doerfert   unsigned ConstructIdx = 0;
326c953409fSJohannes Doerfert   assert(NoConstructTraits == ConstructMatches.size() &&
327c953409fSJohannes Doerfert          "Mismatch in the construct traits!");
328c953409fSJohannes Doerfert   for (TraitProperty Property : VMI.ConstructTraits) {
329c953409fSJohannes Doerfert     assert(getOpenMPContextTraitSetForProperty(Property) ==
330c953409fSJohannes Doerfert                TraitSet::construct &&
331c953409fSJohannes Doerfert            "Ill-formed variant match info!");
3327b6e49a2SDmitri Gribenko     (void)Property;
333c953409fSJohannes Doerfert     // ConstructMatches is the position p - 1 and we need 2^(p-1).
334ae5d3e8cSSimon Pilgrim     Score += (1ULL << ConstructMatches[ConstructIdx++]);
335c953409fSJohannes Doerfert   }
336c953409fSJohannes Doerfert 
337c953409fSJohannes Doerfert   LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Variant has a score of " << Score
338c953409fSJohannes Doerfert                     << "\n");
339c953409fSJohannes Doerfert   return Score;
3402dc45bf3SMartin Storsjö }
341c953409fSJohannes Doerfert 
342c953409fSJohannes Doerfert int llvm::omp::getBestVariantMatchForContext(
343c953409fSJohannes Doerfert     const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext &Ctx) {
344c953409fSJohannes Doerfert 
345c953409fSJohannes Doerfert   APInt BestScore(64, 0);
346c953409fSJohannes Doerfert   int BestVMIIdx = -1;
347c953409fSJohannes Doerfert   const VariantMatchInfo *BestVMI = nullptr;
348c953409fSJohannes Doerfert 
349c953409fSJohannes Doerfert   for (unsigned u = 0, e = VMIs.size(); u < e; ++u) {
350c953409fSJohannes Doerfert     const VariantMatchInfo &VMI = VMIs[u];
351c953409fSJohannes Doerfert 
352c953409fSJohannes Doerfert     SmallVector<unsigned, 8> ConstructMatches;
353c953409fSJohannes Doerfert     // If the variant is not applicable its not the best.
354a19eb1deSJohannes Doerfert     if (!isVariantApplicableInContextHelper(VMI, Ctx, &ConstructMatches,
355a19eb1deSJohannes Doerfert                                             /* DeviceSetOnly */ false))
356c953409fSJohannes Doerfert       continue;
357c953409fSJohannes Doerfert     // Check if its clearly not the best.
358c953409fSJohannes Doerfert     APInt Score = getVariantMatchScore(VMI, Ctx, ConstructMatches);
359c953409fSJohannes Doerfert     if (Score.ult(BestScore))
360c953409fSJohannes Doerfert       continue;
361c953409fSJohannes Doerfert     // Equal score need subset checks.
362c953409fSJohannes Doerfert     if (Score.eq(BestScore)) {
363c953409fSJohannes Doerfert       // Strict subset are never best.
364c953409fSJohannes Doerfert       if (isStrictSubset(VMI, *BestVMI))
365c953409fSJohannes Doerfert         continue;
366c953409fSJohannes Doerfert       // Same score and the current best is no strict subset so we keep it.
367c953409fSJohannes Doerfert       if (!isStrictSubset(*BestVMI, VMI))
368c953409fSJohannes Doerfert         continue;
369c953409fSJohannes Doerfert     }
370c953409fSJohannes Doerfert     // New best found.
371c953409fSJohannes Doerfert     BestVMI = &VMI;
372c953409fSJohannes Doerfert     BestVMIIdx = u;
373c953409fSJohannes Doerfert     BestScore = Score;
374c953409fSJohannes Doerfert   }
375c953409fSJohannes Doerfert 
376c953409fSJohannes Doerfert   return BestVMIIdx;
377c953409fSJohannes Doerfert }
378c953409fSJohannes Doerfert 
379c953409fSJohannes Doerfert TraitSet llvm::omp::getOpenMPContextTraitSetKind(StringRef S) {
380c953409fSJohannes Doerfert   return StringSwitch<TraitSet>(S)
381c953409fSJohannes Doerfert #define OMP_TRAIT_SET(Enum, Str) .Case(Str, TraitSet::Enum)
382c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
383c953409fSJohannes Doerfert       .Default(TraitSet::invalid);
384c953409fSJohannes Doerfert }
3851228d42dSJohannes Doerfert 
3861228d42dSJohannes Doerfert TraitSet
3871228d42dSJohannes Doerfert llvm::omp::getOpenMPContextTraitSetForSelector(TraitSelector Selector) {
3881228d42dSJohannes Doerfert   switch (Selector) {
3891228d42dSJohannes Doerfert #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
3901228d42dSJohannes Doerfert   case TraitSelector::Enum:                                                    \
3911228d42dSJohannes Doerfert     return TraitSet::TraitSetEnum;
3921228d42dSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
3931228d42dSJohannes Doerfert   }
394b91c2673SJohannes Doerfert   llvm_unreachable("Unknown trait selector!");
3951228d42dSJohannes Doerfert }
396c953409fSJohannes Doerfert TraitSet
397c953409fSJohannes Doerfert llvm::omp::getOpenMPContextTraitSetForProperty(TraitProperty Property) {
398c953409fSJohannes Doerfert   switch (Property) {
399c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
400c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
401c953409fSJohannes Doerfert     return TraitSet::TraitSetEnum;
402c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
403c953409fSJohannes Doerfert   }
4042dc45bf3SMartin Storsjö   llvm_unreachable("Unknown trait set!");
405c953409fSJohannes Doerfert }
406c953409fSJohannes Doerfert StringRef llvm::omp::getOpenMPContextTraitSetName(TraitSet Kind) {
407c953409fSJohannes Doerfert   switch (Kind) {
408c953409fSJohannes Doerfert #define OMP_TRAIT_SET(Enum, Str)                                               \
409c953409fSJohannes Doerfert   case TraitSet::Enum:                                                         \
410c953409fSJohannes Doerfert     return Str;
411c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
412c953409fSJohannes Doerfert   }
413c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait set!");
414c953409fSJohannes Doerfert }
415c953409fSJohannes Doerfert 
416c953409fSJohannes Doerfert TraitSelector llvm::omp::getOpenMPContextTraitSelectorKind(StringRef S) {
417c953409fSJohannes Doerfert   return StringSwitch<TraitSelector>(S)
418c953409fSJohannes Doerfert #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
419c953409fSJohannes Doerfert   .Case(Str, TraitSelector::Enum)
420c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
421c953409fSJohannes Doerfert       .Default(TraitSelector::invalid);
422c953409fSJohannes Doerfert }
423c953409fSJohannes Doerfert TraitSelector
424c953409fSJohannes Doerfert llvm::omp::getOpenMPContextTraitSelectorForProperty(TraitProperty Property) {
425c953409fSJohannes Doerfert   switch (Property) {
426c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
427c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
428c953409fSJohannes Doerfert     return TraitSelector::TraitSelectorEnum;
429c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
430c953409fSJohannes Doerfert   }
4312dc45bf3SMartin Storsjö   llvm_unreachable("Unknown trait set!");
432c953409fSJohannes Doerfert }
433c953409fSJohannes Doerfert StringRef llvm::omp::getOpenMPContextTraitSelectorName(TraitSelector Kind) {
434c953409fSJohannes Doerfert   switch (Kind) {
435c953409fSJohannes Doerfert #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
436c953409fSJohannes Doerfert   case TraitSelector::Enum:                                                    \
437c953409fSJohannes Doerfert     return Str;
438c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
439c953409fSJohannes Doerfert   }
440c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait selector!");
441c953409fSJohannes Doerfert }
442c953409fSJohannes Doerfert 
443ee05167cSJohannes Doerfert TraitProperty llvm::omp::getOpenMPContextTraitPropertyKind(
444ee05167cSJohannes Doerfert     TraitSet Set, TraitSelector Selector, StringRef S) {
445ee05167cSJohannes Doerfert   // Special handling for `device={isa(...)}` as we accept anything here. It is
446ee05167cSJohannes Doerfert   // up to the target to decide if the feature is available.
447ee05167cSJohannes Doerfert   if (Set == TraitSet::device && Selector == TraitSelector::device_isa)
448ee05167cSJohannes Doerfert     return TraitProperty::device_isa___ANY;
449c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
4501228d42dSJohannes Doerfert   if (Set == TraitSet::TraitSetEnum && Str == S)                               \
451c953409fSJohannes Doerfert     return TraitProperty::Enum;
452c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
453c953409fSJohannes Doerfert   return TraitProperty::invalid;
454c953409fSJohannes Doerfert }
455c953409fSJohannes Doerfert TraitProperty
456c953409fSJohannes Doerfert llvm::omp::getOpenMPContextTraitPropertyForSelector(TraitSelector Selector) {
457c953409fSJohannes Doerfert   return StringSwitch<TraitProperty>(
458c953409fSJohannes Doerfert              getOpenMPContextTraitSelectorName(Selector))
459c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
460c953409fSJohannes Doerfert   .Case(Str, Selector == TraitSelector::TraitSelectorEnum                      \
461c953409fSJohannes Doerfert                  ? TraitProperty::Enum                                         \
462c953409fSJohannes Doerfert                  : TraitProperty::invalid)
463c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
464c953409fSJohannes Doerfert       .Default(TraitProperty::invalid);
465c953409fSJohannes Doerfert }
466ee05167cSJohannes Doerfert StringRef llvm::omp::getOpenMPContextTraitPropertyName(TraitProperty Kind,
467ee05167cSJohannes Doerfert                                                        StringRef RawString) {
468ee05167cSJohannes Doerfert   if (Kind == TraitProperty::device_isa___ANY)
469ee05167cSJohannes Doerfert     return RawString;
470c953409fSJohannes Doerfert   switch (Kind) {
471c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
472c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
473c953409fSJohannes Doerfert     return Str;
474c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
475c953409fSJohannes Doerfert   }
476c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait property!");
477c953409fSJohannes Doerfert }
478c953409fSJohannes Doerfert StringRef llvm::omp::getOpenMPContextTraitPropertyFullName(TraitProperty Kind) {
479c953409fSJohannes Doerfert   switch (Kind) {
480c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
481c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
482c953409fSJohannes Doerfert     return "(" #TraitSetEnum "," #TraitSelectorEnum "," Str ")";
483c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
484c953409fSJohannes Doerfert   }
485c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait property!");
486c953409fSJohannes Doerfert }
487c953409fSJohannes Doerfert 
488c953409fSJohannes Doerfert bool llvm::omp::isValidTraitSelectorForTraitSet(TraitSelector Selector,
489c953409fSJohannes Doerfert                                                 TraitSet Set,
490c953409fSJohannes Doerfert                                                 bool &AllowsTraitScore,
491c953409fSJohannes Doerfert                                                 bool &RequiresProperty) {
492c953409fSJohannes Doerfert   AllowsTraitScore = Set != TraitSet::construct && Set != TraitSet::device;
493c953409fSJohannes Doerfert   switch (Selector) {
494c953409fSJohannes Doerfert #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
495c953409fSJohannes Doerfert   case TraitSelector::Enum:                                                    \
496c953409fSJohannes Doerfert     RequiresProperty = ReqProp;                                                \
497c953409fSJohannes Doerfert     return Set == TraitSet::TraitSetEnum;
498c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
499c953409fSJohannes Doerfert   }
500c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait selector!");
501c953409fSJohannes Doerfert }
502c953409fSJohannes Doerfert 
503c953409fSJohannes Doerfert bool llvm::omp::isValidTraitPropertyForTraitSetAndSelector(
504c953409fSJohannes Doerfert     TraitProperty Property, TraitSelector Selector, TraitSet Set) {
505c953409fSJohannes Doerfert   switch (Property) {
506c953409fSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
507c953409fSJohannes Doerfert   case TraitProperty::Enum:                                                    \
508c953409fSJohannes Doerfert     return Set == TraitSet::TraitSetEnum &&                                    \
509c953409fSJohannes Doerfert            Selector == TraitSelector::TraitSelectorEnum;
510c953409fSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
511c953409fSJohannes Doerfert   }
512c953409fSJohannes Doerfert   llvm_unreachable("Unknown trait property!");
513c953409fSJohannes Doerfert }
5141228d42dSJohannes Doerfert 
5151228d42dSJohannes Doerfert std::string llvm::omp::listOpenMPContextTraitSets() {
5161228d42dSJohannes Doerfert   std::string S;
5171228d42dSJohannes Doerfert #define OMP_TRAIT_SET(Enum, Str)                                               \
518a8f03963SJohannes Doerfert   if (StringRef(Str) != "invalid")                                             \
5191228d42dSJohannes Doerfert     S.append("'").append(Str).append("'").append(" ");
5201228d42dSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
5211228d42dSJohannes Doerfert   S.pop_back();
5221228d42dSJohannes Doerfert   return S;
5231228d42dSJohannes Doerfert }
5241228d42dSJohannes Doerfert 
5251228d42dSJohannes Doerfert std::string llvm::omp::listOpenMPContextTraitSelectors(TraitSet Set) {
5261228d42dSJohannes Doerfert   std::string S;
5271228d42dSJohannes Doerfert #define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp)                   \
528a8f03963SJohannes Doerfert   if (TraitSet::TraitSetEnum == Set && StringRef(Str) != "Invalid")            \
5291228d42dSJohannes Doerfert     S.append("'").append(Str).append("'").append(" ");
5301228d42dSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
5311228d42dSJohannes Doerfert   S.pop_back();
5321228d42dSJohannes Doerfert   return S;
5331228d42dSJohannes Doerfert }
5341228d42dSJohannes Doerfert 
5351228d42dSJohannes Doerfert std::string
5361228d42dSJohannes Doerfert llvm::omp::listOpenMPContextTraitProperties(TraitSet Set,
5371228d42dSJohannes Doerfert                                             TraitSelector Selector) {
5381228d42dSJohannes Doerfert   std::string S;
5391228d42dSJohannes Doerfert #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str)         \
5401228d42dSJohannes Doerfert   if (TraitSet::TraitSetEnum == Set &&                                         \
5411a93285cSReid Kleckner       TraitSelector::TraitSelectorEnum == Selector &&                          \
542a8f03963SJohannes Doerfert       StringRef(Str) != "invalid")                                             \
5431228d42dSJohannes Doerfert     S.append("'").append(Str).append("'").append(" ");
5441228d42dSJohannes Doerfert #include "llvm/Frontend/OpenMP/OMPKinds.def"
545095cecbeSJohannes Doerfert   if (S.empty())
546095cecbeSJohannes Doerfert     return "<none>";
5471228d42dSJohannes Doerfert   S.pop_back();
5481228d42dSJohannes Doerfert   return S;
5491228d42dSJohannes Doerfert }
550