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

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 3 06:35:09 PST 2020


Fixed by 7b6e49a2f02. Thanks Dmitri!


On 02/03, Mikael Holmén wrote:
> 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

-- 

Johannes Doerfert
Researcher

Argonne National Laboratory
Lemont, IL 60439, USA

jdoerfert at anl.gov
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200203/5deed8fc/attachment-0001.sig>


More information about the llvm-commits mailing list