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(Bit)) 190 return false; 191 if (!isSubset<TraitProperty>(VMI0.ConstructTraits, 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 unsigned(TraitProperty::implementation_extension_match_any))) 211 MK = MK_ANY; 212 if (VMI.RequiredTraits.test( 213 unsigned(TraitProperty::implementation_extension_match_none))) 214 MK = MK_NONE; 215 216 // Helper to deal with a single property that was (not) found in the OpenMP 217 // context based on the match kind selected by the user via 218 // `implementation={extensions(match_[all,any,none])}' 219 auto HandleTrait = [MK](TraitProperty Property, 220 bool WasFound) -> std::optional<bool> /* Result */ { 221 // For kind "any" a single match is enough but we ignore non-matched 222 // properties. 223 if (MK == MK_ANY) { 224 if (WasFound) 225 return true; 226 return std::nullopt; 227 } 228 229 // In "all" or "none" mode we accept a matching or non-matching property 230 // respectively and move on. We are not done yet! 231 if ((WasFound && MK == MK_ALL) || (!WasFound && MK == MK_NONE)) 232 return std::nullopt; 233 234 // We missed a property, provide some debug output and indicate failure. 235 LLVM_DEBUG({ 236 if (MK == MK_ALL) 237 dbgs() << "[" << DEBUG_TYPE << "] Property " 238 << getOpenMPContextTraitPropertyName(Property, "") 239 << " was not in the OpenMP context but match kind is all.\n"; 240 if (MK == MK_NONE) 241 dbgs() << "[" << DEBUG_TYPE << "] Property " 242 << getOpenMPContextTraitPropertyName(Property, "") 243 << " was in the OpenMP context but match kind is none.\n"; 244 }); 245 return false; 246 }; 247 248 for (unsigned Bit : VMI.RequiredTraits.set_bits()) { 249 TraitProperty Property = TraitProperty(Bit); 250 if (DeviceOrImplementationSetOnly && 251 getOpenMPContextTraitSetForProperty(Property) != TraitSet::device && 252 getOpenMPContextTraitSetForProperty(Property) != 253 TraitSet::implementation) 254 continue; 255 256 // So far all extensions are handled elsewhere, we skip them here as they 257 // are not part of the OpenMP context. 258 if (getOpenMPContextTraitSelectorForProperty(Property) == 259 TraitSelector::implementation_extension) 260 continue; 261 262 bool IsActiveTrait = Ctx.ActiveTraits.test(unsigned(Property)); 263 264 // We overwrite the isa trait as it is actually up to the OMPContext hook to 265 // check the raw string(s). 266 if (Property == TraitProperty::device_isa___ANY) 267 IsActiveTrait = llvm::all_of(VMI.ISATraits, [&](StringRef RawString) { 268 return Ctx.matchesISATrait(RawString); 269 }); 270 if (Property == TraitProperty::target_device_isa___ANY) 271 IsActiveTrait = llvm::all_of(VMI.ISATraits, [&](StringRef RawString) { 272 return Ctx.matchesISATrait(RawString); 273 }); 274 275 if (std::optional<bool> Result = HandleTrait(Property, IsActiveTrait)) 276 return *Result; 277 } 278 279 if (!DeviceOrImplementationSetOnly) { 280 // We could use isSubset here but we also want to record the match 281 // locations. 282 unsigned ConstructIdx = 0, NoConstructTraits = Ctx.ConstructTraits.size(); 283 for (TraitProperty Property : VMI.ConstructTraits) { 284 assert(getOpenMPContextTraitSetForProperty(Property) == 285 TraitSet::construct && 286 "Variant context is ill-formed!"); 287 288 // Verify the nesting. 289 bool FoundInOrder = false; 290 while (!FoundInOrder && ConstructIdx != NoConstructTraits) 291 FoundInOrder = (Ctx.ConstructTraits[ConstructIdx++] == Property); 292 if (ConstructMatches) 293 ConstructMatches->push_back(ConstructIdx - 1); 294 295 if (std::optional<bool> Result = HandleTrait(Property, FoundInOrder)) 296 return *Result; 297 298 if (!FoundInOrder) { 299 LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Construct property " 300 << getOpenMPContextTraitPropertyName(Property, "") 301 << " was not nested properly.\n"); 302 return false; 303 } 304 305 // TODO: Verify SIMD 306 } 307 308 assert(isSubset<TraitProperty>(VMI.ConstructTraits, Ctx.ConstructTraits) && 309 "Broken invariant!"); 310 } 311 312 if (MK == MK_ANY) { 313 LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE 314 << "] None of the properties was in the OpenMP context " 315 "but match kind is any.\n"); 316 return false; 317 } 318 319 return true; 320 } 321 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(Property)) { 339 const APInt &UserScore = VMI.ScoreMap.lookup(Property); 340 assert(UserScore.uge(0) && "Expect non-negative user scores!"); 341 Score += UserScore.getZExtValue(); 342 continue; 343 } 344 345 switch (getOpenMPContextTraitSetForProperty(Property)) { 346 case TraitSet::construct: 347 // We handle the construct traits later via the VMI.ConstructTraits 348 // container. 349 continue; 350 case TraitSet::implementation: 351 // No effect on the score (implementation defined). 352 continue; 353 case TraitSet::user: 354 // No effect on the score. 355 continue; 356 case TraitSet::device: 357 // Handled separately below. 358 break; 359 case TraitSet::target_device: 360 // TODO: Handling separately. 361 break; 362 case TraitSet::invalid: 363 llvm_unreachable("Unknown trait set is not to be used!"); 364 } 365 366 // device={kind(any)} is "as if" no kind selector was specified. 367 if (Property == TraitProperty::device_kind_any) 368 continue; 369 if (Property == TraitProperty::target_device_kind_any) 370 continue; 371 372 switch (getOpenMPContextTraitSelectorForProperty(Property)) { 373 case TraitSelector::device_kind: 374 Score += (1ULL << (NoConstructTraits + 0)); 375 continue; 376 case TraitSelector::device_arch: 377 Score += (1ULL << (NoConstructTraits + 1)); 378 continue; 379 case TraitSelector::device_isa: 380 Score += (1ULL << (NoConstructTraits + 2)); 381 continue; 382 case TraitSelector::target_device_kind: 383 Score += (1ULL << (NoConstructTraits + 0)); 384 continue; 385 case TraitSelector::target_device_arch: 386 Score += (1ULL << (NoConstructTraits + 1)); 387 continue; 388 case TraitSelector::target_device_isa: 389 Score += (1ULL << (NoConstructTraits + 2)); 390 continue; 391 default: 392 continue; 393 } 394 } 395 396 unsigned ConstructIdx = 0; 397 assert(NoConstructTraits == ConstructMatches.size() && 398 "Mismatch in the construct traits!"); 399 for (TraitProperty Property : VMI.ConstructTraits) { 400 assert(getOpenMPContextTraitSetForProperty(Property) == 401 TraitSet::construct && 402 "Ill-formed variant match info!"); 403 (void)Property; 404 // ConstructMatches is the position p - 1 and we need 2^(p-1). 405 Score += (1ULL << ConstructMatches[ConstructIdx++]); 406 } 407 408 LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Variant has a score of " << Score 409 << "\n"); 410 return Score; 411 } 412 413 int llvm::omp::getBestVariantMatchForContext( 414 const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext &Ctx) { 415 416 APInt BestScore(64, 0); 417 int BestVMIIdx = -1; 418 const VariantMatchInfo *BestVMI = nullptr; 419 420 for (unsigned u = 0, e = VMIs.size(); u < e; ++u) { 421 const VariantMatchInfo &VMI = VMIs[u]; 422 423 SmallVector<unsigned, 8> ConstructMatches; 424 // If the variant is not applicable its not the best. 425 if (!isVariantApplicableInContextHelper( 426 VMI, Ctx, &ConstructMatches, 427 /* DeviceOrImplementationSetOnly */ false)) 428 continue; 429 // Check if its clearly not the best. 430 APInt Score = getVariantMatchScore(VMI, Ctx, ConstructMatches); 431 if (Score.ult(BestScore)) 432 continue; 433 // Equal score need subset checks. 434 if (Score.eq(BestScore)) { 435 // Strict subset are never best. 436 if (isStrictSubset(VMI, *BestVMI)) 437 continue; 438 // Same score and the current best is no strict subset so we keep it. 439 if (!isStrictSubset(*BestVMI, VMI)) 440 continue; 441 } 442 // New best found. 443 BestVMI = &VMI; 444 BestVMIIdx = u; 445 BestScore = Score; 446 } 447 448 return BestVMIIdx; 449 } 450 451 TraitSet llvm::omp::getOpenMPContextTraitSetKind(StringRef S) { 452 return StringSwitch<TraitSet>(S) 453 #define OMP_TRAIT_SET(Enum, Str) .Case(Str, TraitSet::Enum) 454 #include "llvm/Frontend/OpenMP/OMPKinds.def" 455 .Default(TraitSet::invalid); 456 } 457 458 TraitSet 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(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(Selector)) 541 #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \ 542 .Case(Str, Selector == TraitSelector::TraitSelectorEnum \ 543 ? TraitProperty::Enum \ 544 : TraitProperty::invalid) 545 #include "llvm/Frontend/OpenMP/OMPKinds.def" 546 .Default(TraitProperty::invalid); 547 } 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