blob: aac6cfbdedfb5c434b74ce97e21f09244dd09e95 [file] [edit]
//===- 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/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include <algorithm>
#define DEBUG_TYPE "openmp-ir-builder"
using namespace llvm;
using namespace omp;
OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple,
Triple TargetOffloadTriple, int DeviceNum) {
// Add the appropriate target device kind trait based on the target triple
if (!TargetOffloadTriple.getTriple().empty() && DeviceNum > -1) {
// If target triple is present, then target device is not a host
ActiveTraits.set(unsigned(TraitProperty::target_device_kind_nohost));
switch (TargetOffloadTriple.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::ppcle:
case Triple::ppc64:
case Triple::ppc64le:
case Triple::systemz:
case Triple::x86:
case Triple::x86_64:
ActiveTraits.set(unsigned(TraitProperty::target_device_kind_cpu));
break;
case Triple::amdgpu:
case Triple::nvptx:
case Triple::nvptx64:
case Triple::spirv64:
ActiveTraits.set(unsigned(TraitProperty::target_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::target_device_arch) { \
if (TargetOffloadTriple.getArch() == Triple::parseArch(Str)) \
ActiveTraits.set(unsigned(TraitProperty::Enum)); \
}
#include "llvm/Frontend/OpenMP/OMPKinds.def"
} else {
// Add the appropriate device kind trait based on the triple and the
// IsDeviceCompilation flag.
ActiveTraits.set(unsigned(IsDeviceCompilation
? TraitProperty::device_kind_nohost
: TraitProperty::device_kind_host));
ActiveTraits.set(unsigned(TraitProperty::target_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::ppcle:
case Triple::ppc64:
case Triple::ppc64le:
case Triple::systemz:
case Triple::x86:
case Triple::x86_64:
ActiveTraits.set(unsigned(TraitProperty::device_kind_cpu));
ActiveTraits.set(unsigned(TraitProperty::target_device_kind_cpu));
break;
case Triple::amdgpu:
case Triple::nvptx:
case Triple::nvptx64:
case Triple::spirv64:
ActiveTraits.set(unsigned(TraitProperty::device_kind_gpu));
ActiveTraits.set(unsigned(TraitProperty::target_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 || \
TraitSelector::TraitSelectorEnum == TraitSelector::target_device_arch) { \
if (TargetTriple.getArch() == Triple::parseArch(Str)) \
ActiveTraits.set(unsigned(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.set(unsigned(TraitProperty::implementation_vendor_llvm));
// The user condition true is accepted but not false.
ActiveTraits.set(unsigned(TraitProperty::user_condition_true));
// This is for sure some device.
ActiveTraits.set(unsigned(TraitProperty::device_kind_any));
LLVM_DEBUG({
dbgs() << "[" << DEBUG_TYPE
<< "] New OpenMP context with the following properties:\n";
for (unsigned Bit : ActiveTraits.set_bits()) {
TraitProperty Property = TraitProperty(Bit);
dbgs() << "\t " << getOpenMPContextTraitPropertyFullName(Property)
<< "\n";
}
});
}
}
/// Return true if \p C0 is an ordered subsequence of \p C1.
template <typename T>
static bool isOrderedSubset(ArrayRef<T> C0, ArrayRef<T> C1) {
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;
}
++It1;
}
return true;
}
static bool isUserConditionTrait(TraitProperty Property) {
return Property == TraitProperty::user_condition_true ||
Property == TraitProperty::user_condition_false ||
Property == TraitProperty::user_condition_unknown;
}
static bool hasUserConditionTrait(const VariantMatchInfo &VMI) {
for (TraitProperty Property :
{TraitProperty::user_condition_true, TraitProperty::user_condition_false,
TraitProperty::user_condition_unknown})
if (VMI.RequiredTraits.test(unsigned(Property)))
return true;
return false;
}
// A runtime condition can be left out of the traits but keep its key, so count
// it as a trait.
static unsigned countTraits(const VariantMatchInfo &VMI) {
return VMI.RequiredTraits.count() +
(!VMI.UserCondition.empty() && !hasUserConditionTrait(VMI));
}
static bool isStrictSubset(const VariantMatchInfo &VMI0,
const VariantMatchInfo &VMI1) {
// VMI0 is a strict subset if its required traits are a subset of VMI1's, its
// construct traits are an ordered subsequence of VMI1's, and either relation
// is strict.
if (countTraits(VMI0) > countTraits(VMI1))
return false;
// Different runtime conditions share a trait, so compare them as well.
bool HasRuntimeCondition = !VMI0.UserCondition.empty();
if ((HasRuntimeCondition || hasUserConditionTrait(VMI0)) &&
VMI0.UserCondition != VMI1.UserCondition)
return false;
// The same key also stands for a condition left out of VMI1's traits.
bool IsConditionLeftOut = HasRuntimeCondition && !hasUserConditionTrait(VMI1);
for (unsigned Bit : VMI0.RequiredTraits.set_bits())
if (!VMI1.RequiredTraits.test(Bit) &&
!(IsConditionLeftOut && isUserConditionTrait(TraitProperty(Bit))))
return false;
// Different ISA names share a trait, so compare them as well.
if (!llvm::all_of(VMI0.ISATraits,
[&](const VariantMatchInfo::ISATrait &Trait) {
return llvm::is_contained(VMI1.ISATraits, Trait);
}))
return false;
if (!isOrderedSubset<TraitProperty>(VMI0.ConstructTraits,
VMI1.ConstructTraits))
return false;
if (countTraits(VMI0) < countTraits(VMI1))
return true;
// With the same traits, only a repeated construct makes VMI0 strict.
if (VMI0.ConstructTraits.size() == VMI1.ConstructTraits.size())
return false;
// Different conditions share a trait, so they can't be compared.
return !hasUserConditionTrait(VMI0);
}
static int
isVariantApplicableInContextHelper(const VariantMatchInfo &VMI,
const OMPContext &Ctx,
SmallVectorImpl<unsigned> *ConstructMatches,
bool DeviceOrImplementationSetOnly) {
// The match kind determines if we need to match all traits, any of the
// traits, or none of the traits for it to be an applicable context.
enum MatchKind { MK_ALL, MK_ANY, MK_NONE };
MatchKind MK = MK_ALL;
// Determine the match kind the user wants, "all" is the default and provided
// to the user only for completeness.
if (VMI.RequiredTraits.test(
unsigned(TraitProperty::implementation_extension_match_any)))
MK = MK_ANY;
if (VMI.RequiredTraits.test(
unsigned(TraitProperty::implementation_extension_match_none)))
MK = MK_NONE;
bool AnyTraitMatched = false;
// Apply the match kind selected by implementation={extension(...)} to
// each property. Continue after match_any succeeds to record all construct
// match positions needed for scoring.
auto HandleTrait = [MK, &AnyTraitMatched](TraitProperty Property,
bool WasFound) -> bool {
AnyTraitMatched |= WasFound;
if (MK == MK_ANY)
return true;
// In "all" or "none" mode we accept a matching or non-matching property
// respectively and move on. We are not done yet!
if ((WasFound && MK == MK_ALL) || (!WasFound && MK == MK_NONE))
return true;
// We missed a property, provide some debug output and indicate failure.
LLVM_DEBUG({
if (MK == MK_ALL)
dbgs() << "[" << DEBUG_TYPE << "] Property "
<< getOpenMPContextTraitPropertyName(Property, "")
<< " was not in the OpenMP context but match kind is all.\n";
if (MK == MK_NONE)
dbgs() << "[" << DEBUG_TYPE << "] Property "
<< getOpenMPContextTraitPropertyName(Property, "")
<< " was in the OpenMP context but match kind is none.\n";
});
return false;
};
for (unsigned Bit : VMI.RequiredTraits.set_bits()) {
TraitProperty Property = TraitProperty(Bit);
if (DeviceOrImplementationSetOnly &&
getOpenMPContextTraitSetForProperty(Property) != TraitSet::device &&
getOpenMPContextTraitSetForProperty(Property) !=
TraitSet::implementation)
continue;
// So far all extensions are handled elsewhere, we skip them here as they
// are not part of the OpenMP context.
if (getOpenMPContextTraitSelectorForProperty(Property) ==
TraitSelector::implementation_extension)
continue;
bool IsActiveTrait = Ctx.ActiveTraits.test(unsigned(Property));
// We overwrite the isa trait as it is actually up to the OMPContext hook to
// check the raw string(s).
if (Property == TraitProperty::device_isa___ANY ||
Property == TraitProperty::target_device_isa___ANY)
IsActiveTrait = llvm::all_of(VMI.ISATraits, [&](const auto &Trait) {
return Trait.Property != Property || Ctx.matchesISATrait(Trait.Name);
});
if (!HandleTrait(Property, IsActiveTrait))
return false;
// The match_any result is known; skip ISA lookups, which can warn.
if (MK == MK_ANY && AnyTraitMatched)
break;
}
if (!DeviceOrImplementationSetOnly) {
// Scan the construct sequence in order, recording matching context
// positions for scoring.
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. A failed match in match_any or match_none must not
// consume the remaining context, since a later selector property can
// still match.
unsigned SearchStart = ConstructIdx;
bool FoundInOrder = false;
while (!FoundInOrder && ConstructIdx != NoConstructTraits)
FoundInOrder = (Ctx.ConstructTraits[ConstructIdx++] == Property);
if (!FoundInOrder && MK != MK_ALL)
ConstructIdx = SearchStart;
if (ConstructMatches && FoundInOrder)
ConstructMatches->push_back(ConstructIdx - 1);
if (!HandleTrait(Property, FoundInOrder)) {
LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Construct property "
<< getOpenMPContextTraitPropertyName(Property, "")
<< " was not nested properly.\n");
return false;
}
// TODO: Verify SIMD
}
// A complete ordered match can have several embeddings in the context.
// Match backwards to choose the highest-valued one for scoring. Keep the
// forward scan's partial matches for the match_any extension.
if (ConstructMatches &&
ConstructMatches->size() == VMI.ConstructTraits.size()) {
ConstructIdx = NoConstructTraits;
for (unsigned I = VMI.ConstructTraits.size(); I > 0; --I) {
TraitProperty Property = VMI.ConstructTraits[I - 1];
while (ConstructIdx > 0 &&
Ctx.ConstructTraits[ConstructIdx - 1] != Property)
--ConstructIdx;
assert(ConstructIdx > 0 && "Previously matched construct not found!");
(*ConstructMatches)[I - 1] = --ConstructIdx;
}
}
if (MK == MK_ALL)
assert(isOrderedSubset<TraitProperty>(VMI.ConstructTraits,
Ctx.ConstructTraits) &&
"Broken invariant!");
}
if (MK == MK_ANY && !AnyTraitMatched) {
LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE
<< "] None of the properties was in the OpenMP context "
"but match kind is any.\n");
return false;
}
return true;
}
bool llvm::omp::isVariantApplicableInContext(
const VariantMatchInfo &VMI, const OMPContext &Ctx,
bool DeviceOrImplementationSetOnly) {
return isVariantApplicableInContextHelper(
VMI, Ctx, /* ConstructMatches */ nullptr, DeviceOrImplementationSetOnly);
}
static APInt getVariantMatchScore(const VariantMatchInfo &VMI,
const OMPContext &Ctx,
SmallVectorImpl<unsigned> &ConstructMatches) {
APInt Score(1, 1);
// A sum of valid scores can exceed the width of any individual score.
// Retain all active bits and allow one more bit for each addition's carry.
auto AddScore = [&](const APInt &Value) {
unsigned Width = std::max(Score.getActiveBits(), Value.getActiveBits()) + 1;
Score = Score.zextOrTrunc(Width);
Score += Value.zextOrTrunc(Width);
};
auto AddPowerOfTwo = [&](unsigned Exponent) {
AddScore(APInt::getOneBitSet(Exponent + 1, Exponent));
};
unsigned NoConstructTraits = Ctx.ConstructTraits.size();
SmallDenseSet<TraitSelector, 8> ScoredSelectors;
auto AddSelectorScore = [&](TraitSelector Selector, const APInt *UserScore) {
// Scores belong to selectors, not to individual properties.
if (!ScoredSelectors.insert(Selector).second)
return;
if (UserScore) {
AddScore(*UserScore);
return;
}
switch (Selector) {
case TraitSelector::device_kind:
case TraitSelector::target_device_kind:
AddPowerOfTwo(NoConstructTraits);
break;
case TraitSelector::device_arch:
case TraitSelector::target_device_arch:
AddPowerOfTwo(NoConstructTraits + 1);
break;
case TraitSelector::device_isa:
case TraitSelector::target_device_isa:
AddPowerOfTwo(NoConstructTraits + 2);
break;
default:
break;
}
};
for (unsigned Bit : VMI.RequiredTraits.set_bits()) {
TraitProperty Property = TraitProperty(Bit);
// Construct scores use ordered positions below. kind(any) is treated as
// if no kind selector were specified.
if (getOpenMPContextTraitSetForProperty(Property) == TraitSet::construct ||
Property == TraitProperty::device_kind_any ||
Property == TraitProperty::target_device_kind_any)
continue;
auto It = VMI.ScoreMap.find(Property);
AddSelectorScore(getOpenMPContextTraitSelectorForProperty(Property),
It == VMI.ScoreMap.end() ? nullptr : &It->second);
}
assert(VMI.ConstructTraits.size() >= ConstructMatches.size() &&
"Mismatch in the construct traits!");
for (unsigned Match : ConstructMatches) {
// ConstructMatches is the position p - 1 and we need 2^(p-1).
AddPowerOfTwo(Match);
}
LLVM_DEBUG({
dbgs() << "[" << DEBUG_TYPE << "] Variant has a score of ";
Score.print(dbgs(), /*isSigned=*/false);
dbgs() << "\n";
});
return Score;
}
int llvm::omp::getBestVariantMatchForContext(
const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext &Ctx) {
APInt BestScore(1, 0);
SmallVector<unsigned, 4> BestVMIIdxs;
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,
/* DeviceOrImplementationSetOnly */ false))
continue;
// Check if its clearly not the best.
APInt Score = getVariantMatchScore(VMI, Ctx, ConstructMatches);
unsigned Width = std::max(Score.getBitWidth(), BestScore.getBitWidth());
Score = Score.zextOrTrunc(Width);
BestScore = BestScore.zextOrTrunc(Width);
if (Score.ult(BestScore))
continue;
if (Score.ugt(BestScore)) {
BestScore = Score;
BestVMIIdxs.clear();
}
BestVMIIdxs.push_back(u);
}
// A strict subset of another tied variant is never best; otherwise the first
// one wins. A variant with a runtime condition can only be a subset of one
// with the same condition, so only those are scanned. Tied variants often
// share a few supersets, so try the ones found so far for the same condition
// first.
struct TiedGroup {
SmallVector<unsigned, 4> Idxs;
SmallVector<unsigned, 1> Supersets;
};
DenseMap<StringRef, TiedGroup> Groups;
for (unsigned Idx : BestVMIIdxs)
Groups[VMIs[Idx].UserCondition].Idxs.push_back(Idx);
for (unsigned Idx : BestVMIIdxs) {
const VariantMatchInfo &VMI = VMIs[Idx];
auto IsStrictSubsetOf = [&](unsigned OtherIdx) {
return isStrictSubset(VMI, VMIs[OtherIdx]);
};
TiedGroup &Group = Groups[VMI.UserCondition];
if (llvm::any_of(Group.Supersets, IsStrictSubsetOf))
continue;
// A variant without a runtime condition can be a subset of any of them.
ArrayRef<unsigned> Others =
VMI.UserCondition.empty() ? BestVMIIdxs : Group.Idxs;
auto *It = llvm::find_if(Others, IsStrictSubsetOf);
if (It == Others.end())
return Idx;
Group.Supersets.push_back(*It);
}
return -1;
}
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::getOpenMPContextTraitSetForSelector(TraitSelector Selector) {
switch (Selector) {
#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp) \
case TraitSelector::Enum: \
return TraitSet::TraitSetEnum;
#include "llvm/Frontend/OpenMP/OMPKinds.def"
}
llvm_unreachable("Unknown trait selector!");
}
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"
}
llvm_unreachable("Unknown trait set!");
}
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,
TraitSet Set) {
if (Set == TraitSet::target_device && S == "kind")
return TraitSelector::target_device_kind;
if (Set == TraitSet::target_device && S == "arch")
return TraitSelector::target_device_arch;
if (Set == TraitSet::target_device && S == "isa")
return TraitSelector::target_device_isa;
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"
}
llvm_unreachable("Unknown trait set!");
}
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) {
// Special handling for `device={isa(...)}` as we accept anything here. It is
// up to the target to decide if the feature is available.
if (Set == TraitSet::device && Selector == TraitSelector::device_isa)
return TraitProperty::device_isa___ANY;
if (Set == TraitSet::target_device &&
Selector == TraitSelector::target_device_isa)
return TraitProperty::target_device_isa___ANY;
#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \
if (Set == TraitSet::TraitSetEnum && 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,
StringRef RawString) {
if (Kind == TraitProperty::device_isa___ANY)
return RawString;
if (Kind == TraitProperty::target_device_isa___ANY)
return RawString;
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 &&
Set != TraitSet::target_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!");
}
std::string llvm::omp::listOpenMPContextTraitSets() {
std::string S;
#define OMP_TRAIT_SET(Enum, Str) \
if (StringRef(Str) != "invalid") \
S.append("'").append(Str).append("'").append(" ");
#include "llvm/Frontend/OpenMP/OMPKinds.def"
S.pop_back();
return S;
}
std::string llvm::omp::listOpenMPContextTraitSelectors(TraitSet Set) {
std::string S;
#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, ReqProp) \
if (TraitSet::TraitSetEnum == Set && StringRef(Str) != "Invalid") \
S.append("'").append(Str).append("'").append(" ");
#include "llvm/Frontend/OpenMP/OMPKinds.def"
S.pop_back();
return S;
}
std::string
llvm::omp::listOpenMPContextTraitProperties(TraitSet Set,
TraitSelector Selector) {
std::string S;
#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \
if (TraitSet::TraitSetEnum == Set && \
TraitSelector::TraitSelectorEnum == Selector && \
StringRef(Str) != "invalid") \
S.append("'").append(Str).append("'").append(" ");
#include "llvm/Frontend/OpenMP/OMPKinds.def"
if (S.empty())
return "<none>";
S.pop_back();
return S;
}