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