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