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