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