[llvm] c953409 - [OpenMP][Part 1] Reusable OpenMP context/traits handling

Mikael Holmén via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 3 01:42:39 PST 2020


Hi Johannes,

This code in getVariantMatchScore in OMPContext.cpp causes a compiler
warning when asserts are disabled since Property is then unused:

+  unsigned ConstructIdx = 0;
+  assert(NoConstructTraits == ConstructMatches.size() &&
+         "Mismatch in the construct traits!");
+  for (TraitProperty Property : VMI.ConstructTraits) {
+    assert(getOpenMPContextTraitSetForProperty(Property) ==
+               TraitSet::construct &&
+           "Ill-formed variant match info!");
+    // ConstructMatches is the position p - 1 and we need 2^(p-1).
+    Score += (1 << ConstructMatches[ConstructIdx++]);
+  }

lib/Frontend/OpenMP/CMakeFiles/LLVMFrontendOpenMP.dir/OMPContext.cpp.o
-c ../lib/Frontend/OpenMP/OMPContext.cpp
../lib/Frontend/OpenMP/OMPContext.cpp:233:22: error: unused variable
'Property' [-Werror,-Wunused-variable]
  for (TraitProperty Property : VMI.ConstructTraits) {
                     ^
1 error generated.

/Mikael

On Sun, 2020-02-02 at 21:19 -0800, Johannes Doerfert via llvm-commits
wrote:
> Author: Johannes Doerfert
> Date: 2020-02-02T23:18:25-06:00
> New Revision: c953409ff89e38f5aa5927f5adae3078db45d81c
> 
> URL: 
> https://github.com/llvm/llvm-project/commit/c953409ff89e38f5aa5927f5adae3078db45d81c
> DIFF: 
> https://github.com/llvm/llvm-project/commit/c953409ff89e38f5aa5927f5adae3078db45d81c.diff
> 
> LOG: [OpenMP][Part 1] Reusable OpenMP context/traits handling
> 
> This is the first of multiple parts to make OpenMP context/trait
> handling reusable and generic. This patch was originally part of
> D71830
> but with the unit tests it can be tested independently.
> 
> This patch implements an almost complete handling of OpenMP
> contexts/traits such that we can reuse most of the logic in Flang
> through the OMPContext.{h,cpp} in llvm/Frontend/OpenMP.
> 
> All but construct SIMD specifiers, e.g., inbranch, and the device ISA
> selector are define in llvm/lib/Frontend/OpenMP/OMPKinds.def. From
> these definitions we generate the enum classes TraitSet,
> TraitSelector, and TraitProperty as well as conversion and helper
> functions in llvm/lib/Frontend/OpenMP/OMPContext.{h,cpp}.
> 
> The OpenMP context is now an explicit object (see `struct
> OMPContext`).
> This is in anticipation of construct traits that need to be tracked.
> The
> OpenMP context, as well as the VariantMatchInfo, are basically made
> up
> of a set of active or respectively required traits, e.g., 'host', and
> an
> ordered container of constructs which allows duplication. Matching
> and
> scoring is kept as generic as possible to allow easy extension in the
> future.
> 
> Reviewed By: JonChesterfield
> 
> Differential Revision: https://reviews.llvm.org/D71847
> 
> Added: 
>     llvm/include/llvm/Frontend/OpenMP/OMPContext.h
>     llvm/lib/Frontend/OpenMP/OMPContext.cpp
>     llvm/unittests/Frontend/OpenMPContextTest.cpp
> 
> Modified: 
>     llvm/include/llvm/ADT/SetOperations.h
>     llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
>     llvm/lib/Frontend/OpenMP/CMakeLists.txt
>     llvm/unittests/Frontend/CMakeLists.txt
> 
> Removed: 
>     
> 
> 
> #####################################################################
> ###########
> diff  --git a/llvm/include/llvm/ADT/SetOperations.h
> b/llvm/include/llvm/ADT/SetOperations.h
> index 037256a860b2..6087f479fe37 100644
> --- a/llvm/include/llvm/ADT/SetOperations.h
> +++ b/llvm/include/llvm/ADT/SetOperations.h
> @@ -65,6 +65,27 @@ void set_subtract(S1Ty &S1, const S2Ty &S2) {
>      S1.erase(*SI);
>  }
>  
> +/// set_is_subset(A, B) - Return true iff A in B
> +///
> +template <class S1Ty, class S2Ty>
> +bool set_is_subset(const S1Ty &S1, const S2Ty &S2) {
> +  if (S1.size() > S2.size())
> +    return false;
> +  for (auto &It : S1)
> +    if (!S2.count(It))
> +      return false;
> +  return true;
> +}
> +
> +/// set_is_strict_subset(A, B) - Return true iff A in B and and A !=
> B
> +///
> +template <class S1Ty, class S2Ty>
> +bool set_is_strict_subset(const S1Ty &S1, const S2Ty &S2) {
> +  if (S1.size() >= S2.size())
> +    return false;
> +  return set_is_subset(S1, S2);
> +}
> +
>  } // End llvm namespace
>  
>  #endif
> 
> diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
> b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
> new file mode 100644
> index 000000000000..3b401b72a7d8
> --- /dev/null
> +++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
> @@ -0,0 +1,171 @@
> +//===- OpenMP/OMPContext.h ----- OpenMP context helper functions  -
> C++ -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------
> -------===//
> +/// \file
> +///
> +/// This file provides helper functions and classes to deal with
> OpenMP
> +/// contexts as used by `[begin/end] declare variant` and
> `metadirective`.
> +///
> +//===---------------------------------------------------------------
> -------===//
> +
> +#ifndef LLVM_OPENMP_CONTEXT_H
> +#define LLVM_OPENMP_CONTEXT_H
> +
> +#include "llvm/ADT/APSInt.h"
> +#include "llvm/ADT/SetVector.h"
> +#include "llvm/ADT/SmallSet.h"
> +#include "llvm/ADT/Triple.h"
> +#include "llvm/Frontend/OpenMP/OMPConstants.h"
> +
> +namespace llvm {
> +namespace omp {
> +
> +/// OpenMP Context related IDs and helpers
> +///
> +///{
> +
> +/// IDs for all OpenMP context selector trait sets
> (construct/device/...).
> +enum class TraitSet {
> +#define OMP_TRAIT_SET(Enum, ...) Enum,
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +};
> +
> +/// IDs for all OpenMP context selector trait
> (device={kind/isa...}/...).
> +enum class TraitSelector {
> +#define OMP_TRAIT_SELECTOR(Enum, ...) Enum,
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +};
> +
> +/// IDs for all OpenMP context trait properties
> (host/gpu/bsc/llvm/...)
> +enum class TraitProperty {
> +#define OMP_TRAIT_PROPERTY(Enum, ...) Enum,
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +};
> +
> +/// Parse \p Str and return the trait set it matches or
> TraitSet::invalid.
> +TraitSet getOpenMPContextTraitSetKind(StringRef Str);
> +
> +/// Return the trait set for which \p Property is a property.
> +TraitSet getOpenMPContextTraitSetForProperty(TraitProperty
> Property);
> +
> +/// Return a textual representation of the trait set \p Kind.
> +StringRef getOpenMPContextTraitSetName(TraitSet Kind);
> +
> +/// Parse \p Str and return the trait set it matches or
> +/// TraitSelector::invalid.
> +TraitSelector getOpenMPContextTraitSelectorKind(StringRef Str);
> +
> +/// Return the trait selector for which \p Property is a property.
> +TraitSelector getOpenMPContextTraitSelectorForProperty(TraitProperty
> Property);
> +
> +/// Return a textual representation of the trait selector \p Kind.
> +StringRef getOpenMPContextTraitSelectorName(TraitSelector Kind);
> +
> +/// Parse \p Str and return the trait set it matches or
> +/// TraitProperty::invalid.
> +TraitProperty getOpenMPContextTraitPropertyKind(TraitSet Set,
> +                                                TraitSelector
> Selector,
> +                                                StringRef Str);
> +
> +/// Return the trait property for a singleton selector \p Selector.
> +TraitProperty getOpenMPContextTraitPropertyForSelector(TraitSelector
> Selector);
> +
> +/// Return a textual representation of the trait property \p Kind.
> +StringRef getOpenMPContextTraitPropertyName(TraitProperty Kind);
> +
> +/// Return a textual representation of the trait property \p Kind
> with selector
> +/// and set name included.
> +StringRef getOpenMPContextTraitPropertyFullName(TraitProperty Kind);
> +///}
> +
> +/// Return true if \p Selector can be nested in \p Set. Also sets
> +/// \p AllowsTraitScore and \p RequiresProperty to true/false if the
> user can
> +/// specify a score for properties in \p Selector and if the \p
> Selector
> +/// requires at least one property.
> +bool isValidTraitSelectorForTraitSet(TraitSelector Selector,
> TraitSet Set,
> +                                     bool &AllowsTraitScore,
> +                                     bool &RequiresProperty);
> +
> +/// Return true if \p Property can be nested in \p Selector and \p
> Set.
> +bool isValidTraitPropertyForTraitSetAndSelector(TraitProperty
> Property,
> +                                                TraitSelector
> Selector,
> +                                                TraitSet Set);
> +
> +/// Variant match information describes the required traits and how
> they are
> +/// scored (via the ScoresMap). In addition, the required consturct
> nesting is
> +/// decribed as well.
> +struct VariantMatchInfo {
> +  /// Add the trait \p Property to the required trait set. If \p
> Score is not
> +  /// null, it recorded as well. If \p Property is in the
> `construct` set it
> +  /// is recorded in-order in the ConstructTraits as well.
> +  void addTrait(TraitProperty Property, APInt *Score = nullptr) {
> +    addTrait(getOpenMPContextTraitSetForProperty(Property),
> Property, Score);
> +  }
> +  /// Add the trait \p Property which is in set \p Set to the
> required trait
> +  /// set. If \p Score is not null, it recorded as well. If \p Set
> is the
> +  /// `construct` set it is recorded in-order in the ConstructTraits
> as well.
> +  void addTrait(TraitSet Set, TraitProperty Property, APInt *Score =
> nullptr) {
> +    if (Score)
> +      ScoreMap[Property] = *Score;
> +    RequiredTraits.insert(Property);
> +    if (Set == TraitSet::construct)
> +      ConstructTraits.push_back(Property);
> +  }
> +
> +  SmallSet<TraitProperty, 8> RequiredTraits;
> +  SmallVector<TraitProperty, 8> ConstructTraits;
> +  SmallDenseMap<TraitProperty, APInt> ScoreMap;
> +};
> +
> +/// The context for a source location is made up of active property
> traits,
> +/// e.g., device={kind(host)}, and constructs traits which describe
> the nesting
> +/// in OpenMP constructs at the location.
> +struct OMPContext {
> +  OMPContext(bool IsDeviceCompilation, Triple TargetTriple);
> +
> +  void addTrait(TraitProperty Property) {
> +    addTrait(getOpenMPContextTraitSetForProperty(Property),
> Property);
> +  }
> +  void addTrait(TraitSet Set, TraitProperty Property) {
> +    ActiveTraits.insert(Property);
> +    if (Set == TraitSet::construct)
> +      ConstructTraits.push_back(Property);
> +  }
> +
> +  SmallSet<TraitProperty, 8> ActiveTraits;
> +  SmallVector<TraitProperty, 8> ConstructTraits;
> +};
> +
> +/// Return true if \p VMI is applicable in \p Ctx, that is, all
> traits required
> +/// by \p VMI are available in the OpenMP context \p Ctx.
> +bool isVariantApplicableInContext(const VariantMatchInfo &VMI,
> +                                  const OMPContext &Ctx);
> +
> +/// Return the index (into \p VMIs) of the variant with the highest
> score
> +/// from the ones applicble in \p Ctx. See
> llvm::isVariantApplicableInContext.
> +int getBestVariantMatchForContext(const
> SmallVectorImpl<VariantMatchInfo> &VMIs,
> +                                  const OMPContext &Ctx);
> +
> +} // namespace omp
> +
> +template <> struct DenseMapInfo<omp::TraitProperty> {
> +  static inline omp::TraitProperty getEmptyKey() {
> +    return omp::TraitProperty(-1);
> +  }
> +  static inline omp::TraitProperty getTombstoneKey() {
> +    return omp::TraitProperty(-2);
> +  }
> +  static unsigned getHashValue(omp::TraitProperty val) {
> +    return std::hash<unsigned>{}(unsigned(val));
> +  }
> +  static bool isEqual(omp::TraitProperty LHS, omp::TraitProperty
> RHS) {
> +    return LHS == RHS;
> +  }
> +};
> +
> +} // end namespace llvm
> +#endif // LLVM_OPENMP_CONTEXT_H
> 
> diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
> b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
> index 3ec27e5c08a8..04fc2684729f 100644
> --- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
> +++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
> @@ -287,3 +287,135 @@ __OMP_PROC_BIND_KIND(unknown, 7)
>  #undef OMP_PROC_BIND_KIND
>  
>  ///}
> +
> +/// OpenMP context related definitions:
> +///  - trait set selector
> +///  - trait selector
> +///  - trait property
> +///
> +///{
> +
> +#ifndef OMP_TRAIT_SET
> +#define OMP_TRAIT_SET(Enum, Str)
> +#endif
> +#ifndef OMP_TRAIT_SELECTOR
> +#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str,
> RequiresProperty)
> +#endif
> +#ifndef OMP_TRAIT_PROPERTY
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)
> +#endif
> +
> +#define __OMP_TRAIT_SET(Name) OMP_TRAIT_SET(Name, #Name)
> +#define __OMP_TRAIT_SELECTOR(TraitSet, Name,
> RequiresProperty)                 \
> +  OMP_TRAIT_SELECTOR(TraitSet##_##Name, TraitSet, #Name,
> RequiresProperty)
> +#define __OMP_TRAIT_SELECTOR_AND_PROPERTY(TraitSet,
> Name)                      \
> +  OMP_TRAIT_SELECTOR(TraitSet##_##Name, TraitSet, #Name,
> false)                \
> +  OMP_TRAIT_PROPERTY(TraitSet##_##Name##_##Name, TraitSet,
> TraitSet##_##Name,  \
> +                     #Name)
> +#define __OMP_TRAIT_PROPERTY(TraitSet, TraitSelector,
> Name)                    \
> +  OMP_TRAIT_PROPERTY(TraitSet##_##TraitSelector##_##Name,
> TraitSet,            \
> +                     TraitSet##_##TraitSelector, #Name)
> +
> +// "invalid" must go first.
> +OMP_TRAIT_SET(invalid, "invalid")
> +OMP_TRAIT_SELECTOR(invalid, invalid, "invalid", false)
> +OMP_TRAIT_PROPERTY(invalid, invalid, invalid, "invalid")
> +
> +__OMP_TRAIT_SET(construct)
> +__OMP_TRAIT_SELECTOR_AND_PROPERTY(construct, target)
> +__OMP_TRAIT_SELECTOR_AND_PROPERTY(construct, teams)
> +__OMP_TRAIT_SELECTOR_AND_PROPERTY(construct, parallel)
> +__OMP_TRAIT_SELECTOR_AND_PROPERTY(construct, for)
> +__OMP_TRAIT_SELECTOR_AND_PROPERTY(construct, simd)
> +
> +__OMP_TRAIT_SET(device)
> +
> +__OMP_TRAIT_SELECTOR(device, kind, true)
> +
> +__OMP_TRAIT_PROPERTY(device, kind, host)
> +__OMP_TRAIT_PROPERTY(device, kind, nohost)
> +__OMP_TRAIT_PROPERTY(device, kind, cpu)
> +__OMP_TRAIT_PROPERTY(device, kind, gpu)
> +__OMP_TRAIT_PROPERTY(device, kind, fpga)
> +__OMP_TRAIT_PROPERTY(device, kind, any)
> +
> +__OMP_TRAIT_SELECTOR(device, isa, true)
> +
> +// TODO: What do we want for ISA?
> +
> +__OMP_TRAIT_SELECTOR(device, arch, true)
> +
> +__OMP_TRAIT_PROPERTY(device, arch, arm)
> +__OMP_TRAIT_PROPERTY(device, arch, armeb)
> +__OMP_TRAIT_PROPERTY(device, arch, aarch64)
> +__OMP_TRAIT_PROPERTY(device, arch, aarch64_be)
> +__OMP_TRAIT_PROPERTY(device, arch, aarch64_32)
> +__OMP_TRAIT_PROPERTY(device, arch, ppc)
> +__OMP_TRAIT_PROPERTY(device, arch, ppc64)
> +__OMP_TRAIT_PROPERTY(device, arch, ppc64le)
> +__OMP_TRAIT_PROPERTY(device, arch, x86)
> +__OMP_TRAIT_PROPERTY(device, arch, x86_64)
> +__OMP_TRAIT_PROPERTY(device, arch, amdgcn)
> +__OMP_TRAIT_PROPERTY(device, arch, nvptx)
> +__OMP_TRAIT_PROPERTY(device, arch, nvptx64)
> +
> +__OMP_TRAIT_SET(implementation)
> +
> +__OMP_TRAIT_SELECTOR(implementation, vendor, true)
> +
> +__OMP_TRAIT_PROPERTY(implementation, vendor, amd)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, arm)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, bsc)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, cray)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, fujitsu)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, gnu)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, ibm)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, intel)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, llvm)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, pgi)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, ti)
> +__OMP_TRAIT_PROPERTY(implementation, vendor, unknown)
> +
> +__OMP_TRAIT_SELECTOR(implementation, extension, true)
> +
> +__OMP_TRAIT_SET(user)
> +
> +__OMP_TRAIT_SELECTOR(user, condition, true)
> +
> +__OMP_TRAIT_PROPERTY(user, condition, true)
> +__OMP_TRAIT_PROPERTY(user, condition, false)
> +__OMP_TRAIT_PROPERTY(user, condition, unknown)
> +
> +#undef OMP_TRAIT_SET
> +#undef __OMP_TRAIT_SET
> +///}
> +
> +/// Traits for the requires directive
> +///
> +/// These will (potentially) become trait selectors for the OpenMP
> context if
> +/// the OMP_REQUIRES_TRAIT macro is not defined.
> +///
> +///{
> +
> +#ifdef OMP_REQUIRES_TRAIT
> +#define
> __OMP_REQUIRES_TRAIT(Name)                                           
>   \
> +  OMP_REQUIRES_TRAIT(OMP_REQUIRES_TRAIT_##Name, #Name)
> +#else
> +#define
> __OMP_REQUIRES_TRAIT(Name)                                           
>   \
> +  __OMP_TRAIT_SELECTOR_AND_PROPERTY(implementation, Name)
> +#endif
> +
> +__OMP_REQUIRES_TRAIT(unified_address)
> +__OMP_REQUIRES_TRAIT(unified_shared_memory)
> +__OMP_REQUIRES_TRAIT(reverse_offload)
> +__OMP_REQUIRES_TRAIT(dynamic_allocators)
> +__OMP_REQUIRES_TRAIT(atomic_default_mem_order)
> +
> +#undef __OMP_TRAIT_SELECTOR_AND_PROPERTY
> +#undef OMP_TRAIT_SELECTOR
> +#undef __OMP_TRAIT_SELECTOR
> +#undef OMP_TRAIT_PROPERTY
> +#undef __OMP_TRAIT_PROPERTY
> +#undef __OMP_REQUIRES_TRAIT
> +#undef OMP_REQUIRES_TRAIT
> +///}
> 
> diff  --git a/llvm/lib/Frontend/OpenMP/CMakeLists.txt
> b/llvm/lib/Frontend/OpenMP/CMakeLists.txt
> index e7d1f8e57f62..609b8ad0756b 100644
> --- a/llvm/lib/Frontend/OpenMP/CMakeLists.txt
> +++ b/llvm/lib/Frontend/OpenMP/CMakeLists.txt
> @@ -1,5 +1,6 @@
>  add_llvm_component_library(LLVMFrontendOpenMP
>    OMPConstants.cpp
> +  OMPContext.cpp
>    OMPIRBuilder.cpp
>  
>    ADDITIONAL_HEADER_DIRS
> 
> diff  --git a/llvm/lib/Frontend/OpenMP/OMPContext.cpp
> b/llvm/lib/Frontend/OpenMP/OMPContext.cpp
> new file mode 100644
> index 000000000000..ad0f1ab3d932
> --- /dev/null
> +++ b/llvm/lib/Frontend/OpenMP/OMPContext.cpp
> @@ -0,0 +1,397 @@
> +//===- OMPContext.cpp ------ Collection of helpers for OpenMP
> contexts ----===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------
> -------===//
> +/// \file
> +///
> +/// This file implements helper functions and classes to deal with
> OpenMP
> +/// contexts as used by `[begin/end] declare variant` and
> `metadirective`.
> +///
> +//===---------------------------------------------------------------
> -------===//
> +
> +#include "llvm/Frontend/OpenMP/OMPContext.h"
> +#include "llvm/ADT/SetOperations.h"
> +#include "llvm/ADT/StringSwitch.h"
> +#include "llvm/Support/Debug.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +#define DEBUG_TYPE "openmp-ir-builder"
> +
> +using namespace llvm;
> +using namespace omp;
> +
> +OMPContext::OMPContext(bool IsDeviceCompilation, Triple
> TargetTriple) {
> +  // Add the appropriate device kind trait based on the triple and
> the
> +  // IsDeviceCompilation flag.
> +  ActiveTraits.insert(IsDeviceCompilation ?
> TraitProperty::device_kind_nohost
> +                                          :
> TraitProperty::device_kind_host);
> +  switch (TargetTriple.getArch()) {
> +  case Triple::arm:
> +  case Triple::armeb:
> +  case Triple::aarch64:
> +  case Triple::aarch64_be:
> +  case Triple::aarch64_32:
> +  case Triple::mips:
> +  case Triple::mipsel:
> +  case Triple::mips64:
> +  case Triple::mips64el:
> +  case Triple::ppc:
> +  case Triple::ppc64:
> +  case Triple::ppc64le:
> +  case Triple::x86:
> +  case Triple::x86_64:
> +    ActiveTraits.insert(TraitProperty::device_kind_cpu);
> +    break;
> +  case Triple::amdgcn:
> +  case Triple::nvptx:
> +  case Triple::nvptx64:
> +    ActiveTraits.insert(TraitProperty::device_kind_gpu);
> +    break;
> +  default:
> +    break;
> +  }
> +
> +  // Add the appropriate device architecture trait based on the
> triple.
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  if (TraitSelector::TraitSelectorEnum ==
> TraitSelector::device_arch)          \
> +    if (TargetTriple.getArch() ==
> TargetTriple.getArchTypeForLLVMName(Str))    \
> +      ActiveTraits.insert(TraitProperty::Enum);
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +
> +  // TODO: What exactly do we want to see as device ISA trait?
> +  //       The discussion on the list did not seem to have come to
> an agreed
> +  //       upon solution.
> +
> +  // LLVM is the "OpenMP vendor" but we could also interpret vendor
> as the
> +  // target vendor.
> +  ActiveTraits.insert(TraitProperty::implementation_vendor_llvm);
> +
> +  // The user condition true is accepted but not false.
> +  ActiveTraits.insert(TraitProperty::user_condition_true);
> +
> +  // This is for sure some device.
> +  ActiveTraits.insert(TraitProperty::device_kind_any);
> +
> +  LLVM_DEBUG({
> +    dbgs() << "[" << DEBUG_TYPE
> +           << "] New OpenMP context with the following
> properties:\n";
> +    for (auto &Property : ActiveTraits)
> +      dbgs() << "\t " <<
> getOpenMPContextTraitPropertyFullName(Property)
> +             << "\n";
> +  });
> +}
> +
> +/// Return true if \p C0 is a subset of \p C1. Note that both arrays
> are
> +/// expected to be sorted.
> +template <typename T> static bool isSubset(ArrayRef<T> C0,
> ArrayRef<T> C1) {
> +#ifdef EXPENSIVE_CHECKS
> +  assert(std::is_sorted(C0.begin(), C0.end()) &&
> +         std::is_sorted(C1.begin(), C1.end()) && "Expected sorted
> arrays!");
> +#endif
> +  if (C0.size() > C1.size())
> +    return false;
> +  auto It0 = C0.begin(), End0 = C0.end();
> +  auto It1 = C1.begin(), End1 = C1.end();
> +  while (It0 != End0) {
> +    if (It1 == End1)
> +      return false;
> +    if (*It0 == *It1) {
> +      ++It0;
> +      ++It1;
> +      continue;
> +    }
> +    ++It0;
> +  }
> +  return true;
> +}
> +
> +/// Return true if \p C0 is a strict subset of \p C1. Note that both
> arrays are
> +/// expected to be sorted.
> +template <typename T>
> +static bool isStrictSubset(ArrayRef<T> C0, ArrayRef<T> C1) {
> +  if (C0.size() >= C1.size())
> +    return false;
> +  return isSubset<T>(C0, C1);
> +}
> +
> +static bool isStrictSubset(const VariantMatchInfo &VMI0,
> +                           const VariantMatchInfo &VMI1) {
> +  // If all required traits are a strict subset and the ordered
> vectors storing
> +  // the construct traits, we say it is a strict subset. Note that
> the latter
> +  // relation is not required to be strict.
> +  return set_is_strict_subset(VMI0.RequiredTraits,
> VMI1.RequiredTraits) &&
> +         isSubset<TraitProperty>(VMI0.ConstructTraits,
> VMI1.ConstructTraits);
> +}
> +
> +static int isVariantApplicableInContextHelper(
> +    const VariantMatchInfo &VMI, const OMPContext &Ctx,
> +    SmallVectorImpl<unsigned> *ConstructMatches) {
> +
> +  for (TraitProperty Property : VMI.RequiredTraits) {
> +
> +    bool IsActiveTrait = Ctx.ActiveTraits.count(Property);
> +    if (!IsActiveTrait) {
> +      LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Property "
> +                        <<
> getOpenMPContextTraitPropertyName(Property)
> +                        << " was not in the OpenMP context.\n");
> +      return false;
> +    }
> +  }
> +
> +  // We could use isSubset here but we also want to record the match
> locations.
> +  unsigned ConstructIdx = 0, NoConstructTraits =
> Ctx.ConstructTraits.size();
> +  for (TraitProperty Property : VMI.ConstructTraits) {
> +    assert(getOpenMPContextTraitSetForProperty(Property) ==
> +               TraitSet::construct &&
> +           "Variant context is ill-formed!");
> +
> +    // Verify the nesting.
> +    bool FoundInOrder = false;
> +    while (!FoundInOrder && ConstructIdx != NoConstructTraits)
> +      FoundInOrder = (Ctx.ConstructTraits[ConstructIdx++] ==
> Property);
> +    if (ConstructMatches)
> +      ConstructMatches->push_back(ConstructIdx - 1);
> +
> +    if (!FoundInOrder) {
> +      LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Construct
> property "
> +                        <<
> getOpenMPContextTraitPropertyName(Property)
> +                        << " was not nested properly.\n");
> +      return false;
> +    }
> +
> +    // TODO: Verify SIMD
> +  }
> +
> +  assert(isSubset<TraitProperty>(VMI.ConstructTraits,
> Ctx.ConstructTraits) &&
> +         "Broken invariant!");
> +  return true;
> +}
> +
> +bool llvm::omp::isVariantApplicableInContext(const VariantMatchInfo
> &VMI,
> +                                             const OMPContext &Ctx)
> {
> +  return isVariantApplicableInContextHelper(VMI, Ctx, nullptr);
> +}
> +
> +static APInt getVariantMatchScore(const VariantMatchInfo &VMI,
> +                                  const OMPContext &Ctx,
> +                                  SmallVectorImpl<unsigned>
> &ConstructMatches) {
> +  APInt Score(64, 1);
> +
> +  unsigned NoConstructTraits = VMI.ConstructTraits.size();
> +  for (TraitProperty Property : VMI.RequiredTraits) {
> +    // If there is a user score attached, use it.
> +    if (VMI.ScoreMap.count(Property)) {
> +      const APInt &UserScore = VMI.ScoreMap.lookup(Property);
> +      assert(UserScore.uge(0) && "Expect non-negative user
> scores!");
> +      Score += UserScore.getZExtValue();
> +      continue;
> +    }
> +
> +    switch (getOpenMPContextTraitSetForProperty(Property)) {
> +    case TraitSet::construct:
> +      // We handle the construct traits later via the
> VMI.ConstructTraits
> +      // container.
> +      continue;
> +    case TraitSet::implementation:
> +      // No effect on the score (implementation defined).
> +      continue;
> +    case TraitSet::user:
> +      // No effect on the score.
> +      continue;
> +    case TraitSet::device:
> +      // Handled separately below.
> +      break;
> +    case TraitSet::invalid:
> +      llvm_unreachable("Unknown trait set is not to be used!");
> +    }
> +
> +    // device={kind(any)} is "as if" no kind selector was specified.
> +    if (Property == TraitProperty::device_kind_any)
> +      continue;
> +
> +    switch (getOpenMPContextTraitSelectorForProperty(Property)) {
> +    case TraitSelector::device_kind:
> +      Score += (1 << (NoConstructTraits + 0));
> +      continue;
> +    case TraitSelector::device_arch:
> +      Score += (1 << (NoConstructTraits + 1));
> +      continue;
> +    case TraitSelector::device_isa:
> +      Score += (1 << (NoConstructTraits + 2));
> +      continue;
> +    default:
> +      continue;
> +    }
> +  }
> +
> +  unsigned ConstructIdx = 0;
> +  assert(NoConstructTraits == ConstructMatches.size() &&
> +         "Mismatch in the construct traits!");
> +  for (TraitProperty Property : VMI.ConstructTraits) {
> +    assert(getOpenMPContextTraitSetForProperty(Property) ==
> +               TraitSet::construct &&
> +           "Ill-formed variant match info!");
> +    // ConstructMatches is the position p - 1 and we need 2^(p-1).
> +    Score += (1 << ConstructMatches[ConstructIdx++]);
> +  }
> +
> +  LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Variant has a score
> of " << Score
> +                    << "\n");
> +  return Score;
> +};
> +
> +int llvm::omp::getBestVariantMatchForContext(
> +    const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext
> &Ctx) {
> +
> +  APInt BestScore(64, 0);
> +  int BestVMIIdx = -1;
> +  const VariantMatchInfo *BestVMI = nullptr;
> +
> +  for (unsigned u = 0, e = VMIs.size(); u < e; ++u) {
> +    const VariantMatchInfo &VMI = VMIs[u];
> +
> +    SmallVector<unsigned, 8> ConstructMatches;
> +    // If the variant is not applicable its not the best.
> +    if (!isVariantApplicableInContextHelper(VMI, Ctx,
> &ConstructMatches))
> +      continue;
> +    // Check if its clearly not the best.
> +    APInt Score = getVariantMatchScore(VMI, Ctx, ConstructMatches);
> +    if (Score.ult(BestScore))
> +      continue;
> +    // Equal score need subset checks.
> +    if (Score.eq(BestScore)) {
> +      // Strict subset are never best.
> +      if (isStrictSubset(VMI, *BestVMI))
> +        continue;
> +      // Same score and the current best is no strict subset so we
> keep it.
> +      if (!isStrictSubset(*BestVMI, VMI))
> +        continue;
> +    }
> +    // New best found.
> +    BestVMI = &VMI;
> +    BestVMIIdx = u;
> +    BestScore = Score;
> +  }
> +
> +  return BestVMIIdx;
> +}
> +
> +TraitSet llvm::omp::getOpenMPContextTraitSetKind(StringRef S) {
> +  return StringSwitch<TraitSet>(S)
> +#define OMP_TRAIT_SET(Enum, Str) .Case(Str, TraitSet::Enum)
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +      .Default(TraitSet::invalid);
> +}
> +TraitSet
> +llvm::omp::getOpenMPContextTraitSetForProperty(TraitProperty
> Property) {
> +  switch (Property) {
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  case
> TraitProperty::Enum:                                                 
>    \
> +    return TraitSet::TraitSetEnum;
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  }
> +}
> +StringRef llvm::omp::getOpenMPContextTraitSetName(TraitSet Kind) {
> +  switch (Kind) {
> +#define OMP_TRAIT_SET(Enum,
> Str)                                               \
> +  case
> TraitSet::Enum:                                                      
>    \
> +    return Str;
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  }
> +  llvm_unreachable("Unknown trait set!");
> +}
> +
> +TraitSelector llvm::omp::getOpenMPContextTraitSelectorKind(StringRef
> S) {
> +  return StringSwitch<TraitSelector>(S)
> +#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str,
> ReqProp)                   \
> +  .Case(Str, TraitSelector::Enum)
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +      .Default(TraitSelector::invalid);
> +}
> +TraitSelector
> +llvm::omp::getOpenMPContextTraitSelectorForProperty(TraitProperty
> Property) {
> +  switch (Property) {
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  case
> TraitProperty::Enum:                                                 
>    \
> +    return TraitSelector::TraitSelectorEnum;
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  }
> +}
> +StringRef llvm::omp::getOpenMPContextTraitSelectorName(TraitSelector
> Kind) {
> +  switch (Kind) {
> +#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str,
> ReqProp)                   \
> +  case
> TraitSelector::Enum:                                                 
>    \
> +    return Str;
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  }
> +  llvm_unreachable("Unknown trait selector!");
> +}
> +
> +TraitProperty llvm::omp::getOpenMPContextTraitPropertyKind(
> +    TraitSet Set, TraitSelector Selector, StringRef S) {
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  if (Set == TraitSet::TraitSetEnum
> &&                                         \
> +      Selector == TraitSelector::TraitSelectorEnum && Str ==
> S)                \
> +    return TraitProperty::Enum;
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  return TraitProperty::invalid;
> +}
> +TraitProperty
> +llvm::omp::getOpenMPContextTraitPropertyForSelector(TraitSelector
> Selector) {
> +  return StringSwitch<TraitProperty>(
> +             getOpenMPContextTraitSelectorName(Selector))
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  .Case(Str, Selector ==
> TraitSelector::TraitSelectorEnum                      \
> +                 ?
> TraitProperty::Enum                                         \
> +                 : TraitProperty::invalid)
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +      .Default(TraitProperty::invalid);
> +}
> +StringRef llvm::omp::getOpenMPContextTraitPropertyName(TraitProperty
> Kind) {
> +  switch (Kind) {
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  case
> TraitProperty::Enum:                                                 
>    \
> +    return Str;
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  }
> +  llvm_unreachable("Unknown trait property!");
> +}
> +StringRef
> llvm::omp::getOpenMPContextTraitPropertyFullName(TraitProperty Kind)
> {
> +  switch (Kind) {
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  case
> TraitProperty::Enum:                                                 
>    \
> +    return "(" #TraitSetEnum "," #TraitSelectorEnum "," Str ")";
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  }
> +  llvm_unreachable("Unknown trait property!");
> +}
> +
> +bool llvm::omp::isValidTraitSelectorForTraitSet(TraitSelector
> Selector,
> +                                                TraitSet Set,
> +                                                bool
> &AllowsTraitScore,
> +                                                bool
> &RequiresProperty) {
> +  AllowsTraitScore = Set != TraitSet::construct && Set !=
> TraitSet::device;
> +  switch (Selector) {
> +#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str,
> ReqProp)                   \
> +  case
> TraitSelector::Enum:                                                 
>    \
> +    RequiresProperty =
> ReqProp;                                                \
> +    return Set == TraitSet::TraitSetEnum;
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  }
> +  llvm_unreachable("Unknown trait selector!");
> +}
> +
> +bool llvm::omp::isValidTraitPropertyForTraitSetAndSelector(
> +    TraitProperty Property, TraitSelector Selector, TraitSet Set) {
> +  switch (Property) {
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  case
> TraitProperty::Enum:                                                 
>    \
> +    return Set == TraitSet::TraitSetEnum
> &&                                    \
> +           Selector == TraitSelector::TraitSelectorEnum;
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +  }
> +  llvm_unreachable("Unknown trait property!");
> +}
> 
> diff  --git a/llvm/unittests/Frontend/CMakeLists.txt
> b/llvm/unittests/Frontend/CMakeLists.txt
> index 530c188ca8e5..b3ffaf90c47e 100644
> --- a/llvm/unittests/Frontend/CMakeLists.txt
> +++ b/llvm/unittests/Frontend/CMakeLists.txt
> @@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS
>    )
>  
>  add_llvm_unittest(LLVMFrontendTests
> +  OpenMPContextTest.cpp
>    OpenMPIRBuilderTest.cpp
>    )
>  
> 
> diff  --git a/llvm/unittests/Frontend/OpenMPContextTest.cpp
> b/llvm/unittests/Frontend/OpenMPContextTest.cpp
> new file mode 100644
> index 000000000000..8741b825cb61
> --- /dev/null
> +++ b/llvm/unittests/Frontend/OpenMPContextTest.cpp
> @@ -0,0 +1,310 @@
> +//===- unittest/IR/OpenMPContextTest.cpp - OpenMP Context handling
> tests --===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------
> -------===//
> +
> +#include "llvm/Frontend/OpenMP/OMPConstants.h"
> +#include "llvm/Frontend/OpenMP/OMPContext.h"
> +#include "gtest/gtest.h"
> +
> +using namespace llvm;
> +using namespace omp;
> +
> +namespace {
> +
> +class OpenMPContextTest : public testing::Test {
> +protected:
> +  void SetUp() override {}
> +
> +  void TearDown() override {}
> +};
> +
> +TEST_F(OpenMPContextTest, RoundTripAndAssociation) {
> +#define OMP_TRAIT_SET(Enum,
> Str)                                               \
> +  EXPECT_EQ(TraitSet::Enum,                                         
>            \
> +            getOpenMPContextTraitSetKind(                           
>            \
> +                getOpenMPContextTraitSetName(TraitSet::Enum)));     
>            \
> +  EXPECT_EQ(Str,                                                    
>            \
> +            getOpenMPContextTraitSetName(getOpenMPContextTraitSetKin
> d(Str)));
> +#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str,
> RequiresProperty)          \
> +  EXPECT_EQ(TraitSelector::Enum,                                    
>            \
> +            getOpenMPContextTraitSelectorKind(                      
>            \
> +                getOpenMPContextTraitSelectorName(TraitSelector::Enu
> m)));      \
> +  EXPECT_EQ(Str,
> getOpenMPContextTraitSelectorName(                            \
> +                     getOpenMPContextTraitSelectorKind(Str)));
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  EXPECT_EQ(TraitProperty::Enum,                                    
>            \
> +            getOpenMPContextTraitPropertyKind(                      
>            \
> +                TraitSet::TraitSetEnum,
> TraitSelector::TraitSelectorEnum,      \
> +                getOpenMPContextTraitPropertyName(TraitProperty::Enu
> m)));      \
> +  EXPECT_EQ(                                                        
>            \
> +      Str,                                                          
>            \
> +      getOpenMPContextTraitPropertyName(getOpenMPContextTraitPropert
> yKind(     \
> +          TraitSet::TraitSetEnum, TraitSelector::TraitSelectorEnum,
> Str)));    \
> +  EXPECT_EQ(TraitSet::TraitSetEnum,                                 
>            \
> +            getOpenMPContextTraitSetForProperty(TraitProperty::Enum)
> );         \
> +  EXPECT_EQ(TraitSelector::TraitSelectorEnum,                       
>            \
> +            getOpenMPContextTraitSelectorForProperty(TraitProperty::
> Enum));
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +}
> +
> +TEST_F(OpenMPContextTest, ValidNesting) {
> +  bool AllowsTraitScore, ReqProperty;
> +#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str,
> RequiresProperty)          \
> +  EXPECT_TRUE(isValidTraitSelectorForTraitSet(TraitSelector::Enum,  
>            \
> +                                              TraitSet::TraitSetEnum
> ,          \
> +                                              AllowsTraitScore,
> ReqProperty)); \
> +  EXPECT_EQ(RequiresProperty, ReqProperty);
> +#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum,
> Str)         \
> +  EXPECT_TRUE(isValidTraitPropertyForTraitSetAndSelector(           
>            \
> +      TraitProperty::Enum,
> TraitSelector::TraitSelectorEnum,                   \
> +      TraitSet::TraitSetEnum));
> +#include "llvm/Frontend/OpenMP/OMPKinds.def"
> +}
> +
> +TEST_F(OpenMPContextTest, ApplicabilityNonConstruct) {
> +  OMPContext HostLinux(false, Triple("x86_64-unknown-linux"));
> +  OMPContext DeviceLinux(true, Triple("x86_64-unknown-linux"));
> +  OMPContext HostNVPTX(false, Triple("nvptx64-nvidia-cuda"));
> +  OMPContext DeviceNVPTX(true, Triple("nvptx64-nvidia-cuda"));
> +
> +  VariantMatchInfo Empty;
> +  EXPECT_TRUE(isVariantApplicableInContext(Empty, HostLinux));
> +  EXPECT_TRUE(isVariantApplicableInContext(Empty, DeviceLinux));
> +  EXPECT_TRUE(isVariantApplicableInContext(Empty, HostNVPTX));
> +  EXPECT_TRUE(isVariantApplicableInContext(Empty, DeviceNVPTX));
> +
> +  VariantMatchInfo UserCondFalse;
> +  UserCondFalse.addTrait(TraitProperty::user_condition_false);
> +  EXPECT_FALSE(isVariantApplicableInContext(UserCondFalse,
> HostLinux));
> +  EXPECT_FALSE(isVariantApplicableInContext(UserCondFalse,
> DeviceLinux));
> +  EXPECT_FALSE(isVariantApplicableInContext(UserCondFalse,
> HostNVPTX));
> +  EXPECT_FALSE(isVariantApplicableInContext(UserCondFalse,
> DeviceNVPTX));
> +
> +  VariantMatchInfo DeviceArchArm;
> +  DeviceArchArm.addTrait(TraitProperty::device_arch_arm);
> +  EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArm,
> HostLinux));
> +  EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArm,
> DeviceLinux));
> +  EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArm,
> HostNVPTX));
> +  EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArm,
> DeviceNVPTX));
> +
> +  VariantMatchInfo LLVMHostUserCondTrue;
> +  LLVMHostUserCondTrue.addTrait(TraitProperty::implementation_vendor
> _llvm);
> +  LLVMHostUserCondTrue.addTrait(TraitProperty::device_kind_host);
> +  LLVMHostUserCondTrue.addTrait(TraitProperty::device_kind_any);
> +  LLVMHostUserCondTrue.addTrait(TraitProperty::user_condition_true);
> +  EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTrue,
> HostLinux));
> +  EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrue,
> DeviceLinux));
> +  EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTrue,
> HostNVPTX));
> +  EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrue,
> DeviceNVPTX));
> +
> +  VariantMatchInfo LLVMHostUserCondTrueCPU = LLVMHostUserCondTrue;
> +  LLVMHostUserCondTrueCPU.addTrait(TraitProperty::device_kind_cpu);
> +  EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTrueCPU,
> HostLinux));
> +  EXPECT_FALSE(
> +      isVariantApplicableInContext(LLVMHostUserCondTrueCPU,
> DeviceLinux));
> +  EXPECT_FALSE(
> +      isVariantApplicableInContext(LLVMHostUserCondTrueCPU,
> HostNVPTX));
> +  EXPECT_FALSE(
> +      isVariantApplicableInContext(LLVMHostUserCondTrueCPU,
> DeviceNVPTX));
> +
> +  VariantMatchInfo GPU;
> +  GPU.addTrait(TraitProperty::device_kind_gpu);
> +  EXPECT_FALSE(isVariantApplicableInContext(GPU, HostLinux));
> +  EXPECT_FALSE(isVariantApplicableInContext(GPU, DeviceLinux));
> +  EXPECT_TRUE(isVariantApplicableInContext(GPU, HostNVPTX));
> +  EXPECT_TRUE(isVariantApplicableInContext(GPU, DeviceNVPTX));
> +
> +  VariantMatchInfo NoHost;
> +  NoHost.addTrait(TraitProperty::device_kind_nohost);
> +  EXPECT_FALSE(isVariantApplicableInContext(NoHost, HostLinux));
> +  EXPECT_TRUE(isVariantApplicableInContext(NoHost, DeviceLinux));
> +  EXPECT_FALSE(isVariantApplicableInContext(NoHost, HostNVPTX));
> +  EXPECT_TRUE(isVariantApplicableInContext(NoHost, DeviceNVPTX));
> +}
> +
> +TEST_F(OpenMPContextTest, ApplicabilityAllTraits) {
> +  OMPContext HostLinuxParallelParallel(false, Triple("x86_64-
> unknown-linux"));
> +  HostLinuxParallelParallel.addTrait(
> +      TraitProperty::construct_parallel_parallel);
> +  HostLinuxParallelParallel.addTrait(
> +      TraitProperty::construct_parallel_parallel);
> +  OMPContext DeviceLinuxTargetParallel(true, Triple("x86_64-unknown-
> linux"));
> +  DeviceLinuxTargetParallel.addTrait(TraitProperty::construct_target
> _target);
> +  DeviceLinuxTargetParallel.addTrait(
> +      TraitProperty::construct_parallel_parallel);
> +  OMPContext HostNVPTXFor(false, Triple("nvptx64-nvidia-cuda"));
> +  HostNVPTXFor.addTrait(TraitProperty::construct_for_for);
> +  OMPContext DeviceNVPTXTargetTeamsParallel(true,
> +                                            Triple("nvptx64-nvidia-
> cuda"));
> +  DeviceNVPTXTargetTeamsParallel.addTrait(
> +      TraitProperty::construct_target_target);
> +  DeviceNVPTXTargetTeamsParallel.addTrait(TraitProperty::construct_t
> eams_teams);
> +  DeviceNVPTXTargetTeamsParallel.addTrait(
> +      TraitProperty::construct_parallel_parallel);
> +
> +  { // non-construct variants
> +    VariantMatchInfo Empty;
> +    EXPECT_TRUE(isVariantApplicableInContext(Empty,
> HostLinuxParallelParallel));
> +    EXPECT_TRUE(isVariantApplicableInContext(Empty,
> DeviceLinuxTargetParallel));
> +    EXPECT_TRUE(isVariantApplicableInContext(Empty, HostNVPTXFor));
> +    EXPECT_TRUE(
> +        isVariantApplicableInContext(Empty,
> DeviceNVPTXTargetTeamsParallel));
> +
> +    VariantMatchInfo UserCondFalse;
> +    UserCondFalse.addTrait(TraitProperty::user_condition_false);
> +    EXPECT_FALSE(
> +        isVariantApplicableInContext(UserCondFalse,
> HostLinuxParallelParallel));
> +    EXPECT_FALSE(
> +        isVariantApplicableInContext(UserCondFalse,
> DeviceLinuxTargetParallel));
> +    EXPECT_FALSE(isVariantApplicableInContext(UserCondFalse,
> HostNVPTXFor));
> +    EXPECT_FALSE(isVariantApplicableInContext(UserCondFalse,
> +                                              DeviceNVPTXTargetTeams
> Parallel));
> +
> +    VariantMatchInfo DeviceArchArm;
> +    DeviceArchArm.addTrait(TraitProperty::device_arch_arm);
> +    EXPECT_FALSE(
> +        isVariantApplicableInContext(DeviceArchArm,
> HostLinuxParallelParallel));
> +    EXPECT_FALSE(
> +        isVariantApplicableInContext(DeviceArchArm,
> DeviceLinuxTargetParallel));
> +    EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArm,
> HostNVPTXFor));
> +    EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArm,
> +                                              DeviceNVPTXTargetTeams
> Parallel));
> +
> +    APInt Score(32, 1000);
> +    VariantMatchInfo LLVMHostUserCondTrue;
> +    LLVMHostUserCondTrue.addTrait(TraitProperty::implementation_vend
> or_llvm);
> +    LLVMHostUserCondTrue.addTrait(TraitProperty::device_kind_host);
> +    LLVMHostUserCondTrue.addTrait(TraitProperty::device_kind_any);
> +    LLVMHostUserCondTrue.addTrait(TraitProperty::user_condition_true
> , &Score);
> +    EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTrue,
> +                                             HostLinuxParallelParall
> el));
> +    EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrue,
> +                                              DeviceLinuxTargetParal
> lel));
> +    EXPECT_TRUE(
> +        isVariantApplicableInContext(LLVMHostUserCondTrue,
> HostNVPTXFor));
> +    EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrue,
> +                                              DeviceNVPTXTargetTeams
> Parallel));
> +
> +    VariantMatchInfo LLVMHostUserCondTrueCPU = LLVMHostUserCondTrue;
> +    LLVMHostUserCondTrueCPU.addTrait(TraitProperty::device_kind_cpu)
> ;
> +    EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTrueCPU
> ,
> +                                             HostLinuxParallelParall
> el));
> +    EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrueCP
> U,
> +                                              DeviceLinuxTargetParal
> lel));
> +    EXPECT_FALSE(
> +        isVariantApplicableInContext(LLVMHostUserCondTrueCPU,
> HostNVPTXFor));
> +    EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrueCP
> U,
> +                                              DeviceNVPTXTargetTeams
> Parallel));
> +
> +    VariantMatchInfo GPU;
> +    GPU.addTrait(TraitProperty::device_kind_gpu);
> +    EXPECT_FALSE(isVariantApplicableInContext(GPU,
> HostLinuxParallelParallel));
> +    EXPECT_FALSE(isVariantApplicableInContext(GPU,
> DeviceLinuxTargetParallel));
> +    EXPECT_TRUE(isVariantApplicableInContext(GPU, HostNVPTXFor));
> +    EXPECT_TRUE(
> +        isVariantApplicableInContext(GPU,
> DeviceNVPTXTargetTeamsParallel));
> +
> +    VariantMatchInfo NoHost;
> +    NoHost.addTrait(TraitProperty::device_kind_nohost);
> +    EXPECT_FALSE(
> +        isVariantApplicableInContext(NoHost,
> HostLinuxParallelParallel));
> +    EXPECT_TRUE(
> +        isVariantApplicableInContext(NoHost,
> DeviceLinuxTargetParallel));
> +    EXPECT_FALSE(isVariantApplicableInContext(NoHost,
> HostNVPTXFor));
> +    EXPECT_TRUE(
> +        isVariantApplicableInContext(NoHost,
> DeviceNVPTXTargetTeamsParallel));
> +  }
> +  { // variants with all sets
> +    VariantMatchInfo DeviceArchArmParallel;
> +    DeviceArchArmParallel.addTrait(TraitProperty::construct_parallel
> _parallel);
> +    DeviceArchArmParallel.addTrait(TraitProperty::device_arch_arm);
> +    EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArmParallel,
> +                                              HostLinuxParallelParal
> lel));
> +    EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArmParallel,
> +                                              DeviceLinuxTargetParal
> lel));
> +    EXPECT_FALSE(
> +        isVariantApplicableInContext(DeviceArchArmParallel,
> HostNVPTXFor));
> +    EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArmParallel,
> +                                              DeviceNVPTXTargetTeams
> Parallel));
> +
> +    VariantMatchInfo LLVMHostUserCondTrueParallel;
> +    LLVMHostUserCondTrueParallel.addTrait(
> +        TraitProperty::implementation_vendor_llvm);
> +    LLVMHostUserCondTrueParallel.addTrait(TraitProperty::device_kind
> _host);
> +    LLVMHostUserCondTrueParallel.addTrait(TraitProperty::device_kind
> _any);
> +    LLVMHostUserCondTrueParallel.addTrait(TraitProperty::user_condit
> ion_true);
> +    LLVMHostUserCondTrueParallel.addTrait(
> +        TraitProperty::construct_parallel_parallel);
> +    EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTruePar
> allel,
> +                                             HostLinuxParallelParall
> el));
> +    EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTruePa
> rallel,
> +                                              DeviceLinuxTargetParal
> lel));
> +    EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTruePa
> rallel,
> +                                              HostNVPTXFor));
> +    EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTruePa
> rallel,
> +                                              DeviceNVPTXTargetTeams
> Parallel));
> +
> +    VariantMatchInfo LLVMHostUserCondTrueParallelParallel =
> +        LLVMHostUserCondTrueParallel;
> +    LLVMHostUserCondTrueParallelParallel.addTrait(
> +        TraitProperty::construct_parallel_parallel);
> +    EXPECT_TRUE(isVariantApplicableInContext(
> +        LLVMHostUserCondTrueParallelParallel,
> HostLinuxParallelParallel));
> +    EXPECT_FALSE(isVariantApplicableInContext(
> +        LLVMHostUserCondTrueParallelParallel,
> DeviceLinuxTargetParallel));
> +    EXPECT_FALSE(isVariantApplicableInContext(
> +        LLVMHostUserCondTrueParallelParallel, HostNVPTXFor));
> +    EXPECT_FALSE(isVariantApplicableInContext(
> +        LLVMHostUserCondTrueParallelParallel,
> DeviceNVPTXTargetTeamsParallel));
> +
> +    VariantMatchInfo LLVMHostUserCondTrueParallelParallelParallel =
> +        LLVMHostUserCondTrueParallelParallel;
> +    LLVMHostUserCondTrueParallelParallelParallel.addTrait(
> +        TraitProperty::construct_parallel_parallel);
> +    EXPECT_FALSE(isVariantApplicableInContext(
> +        LLVMHostUserCondTrueParallelParallelParallel,
> +        HostLinuxParallelParallel));
> +    EXPECT_FALSE(isVariantApplicableInContext(
> +        LLVMHostUserCondTrueParallelParallelParallel,
> +        DeviceLinuxTargetParallel));
> +    EXPECT_FALSE(isVariantApplicableInContext(
> +        LLVMHostUserCondTrueParallelParallelParallel,
> HostNVPTXFor));
> +    EXPECT_FALSE(isVariantApplicableInContext(
> +        LLVMHostUserCondTrueParallelParallelParallel,
> +        DeviceNVPTXTargetTeamsParallel));
> +
> +    VariantMatchInfo GPUTargetTeams;
> +    GPUTargetTeams.addTrait(TraitProperty::construct_target_target);
> +    GPUTargetTeams.addTrait(TraitProperty::construct_teams_teams);
> +    GPUTargetTeams.addTrait(TraitProperty::device_kind_gpu);
> +    EXPECT_FALSE(isVariantApplicableInContext(GPUTargetTeams,
> +                                              HostLinuxParallelParal
> lel));
> +    EXPECT_FALSE(isVariantApplicableInContext(GPUTargetTeams,
> +                                              DeviceLinuxTargetParal
> lel));
> +    EXPECT_FALSE(isVariantApplicableInContext(GPUTargetTeams,
> HostNVPTXFor));
> +    EXPECT_TRUE(isVariantApplicableInContext(GPUTargetTeams,
> +                                             DeviceNVPTXTargetTeamsP
> arallel));
> +
> +    VariantMatchInfo GPUTargetParallel;
> +    GPUTargetParallel.addTrait(TraitProperty::construct_target_targe
> t);
> +    GPUTargetParallel.addTrait(TraitProperty::construct_parallel_par
> allel);
> +    GPUTargetParallel.addTrait(TraitProperty::device_kind_gpu);
> +    EXPECT_FALSE(isVariantApplicableInContext(GPUTargetParallel,
> +                                              HostLinuxParallelParal
> lel));
> +    EXPECT_FALSE(isVariantApplicableInContext(GPUTargetParallel,
> +                                              DeviceLinuxTargetParal
> lel));
> +    EXPECT_FALSE(isVariantApplicableInContext(GPUTargetParallel,
> HostNVPTXFor));
> +    EXPECT_TRUE(isVariantApplicableInContext(GPUTargetParallel,
> +                                             DeviceNVPTXTargetTeamsP
> arallel));
> +  }
> +}
> +
> +TEST_F(OpenMPContextTest, ScoringSimple) {
> +  // TODO: Add scoring tests (via getBestVariantMatchForContext).
> +}
> +
> +} // namespace
> 
> 
>         
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list