blob: 937a24d38ba48342f47c1d8297845e1208ee9af5 [file] [edit]
//===- 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 "llvm/TargetParser/Triple.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(getOpenMPContextTraitSetKind(Str)));
#define OMP_TRAIT_SELECTOR(Enum, TraitSetEnum, Str, RequiresProperty) \
EXPECT_EQ(TraitSelector::Enum, \
getOpenMPContextTraitSelectorKind( \
getOpenMPContextTraitSelectorName(TraitSelector::Enum), \
TraitSet::TraitSetEnum)); \
EXPECT_EQ(Str, getOpenMPContextTraitSelectorName( \
getOpenMPContextTraitSelectorKind( \
Str, TraitSet::TraitSetEnum)));
#define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \
EXPECT_EQ(TraitProperty::Enum, \
getOpenMPContextTraitPropertyKind( \
TraitSet::TraitSetEnum, TraitSelector::TraitSelectorEnum, \
getOpenMPContextTraitPropertyName(TraitProperty::Enum, Str))); \
EXPECT_EQ(Str, getOpenMPContextTraitPropertyName( \
getOpenMPContextTraitPropertyKind( \
TraitSet::TraitSetEnum, \
TraitSelector::TraitSelectorEnum, Str), \
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"), Triple(), -1);
OMPContext DeviceLinux(true, Triple("x86_64-unknown-linux"), Triple(), -1);
OMPContext HostNVPTX(false, Triple("nvptx64-nvidia-cuda"), Triple(), -1);
OMPContext DeviceNVPTX(true, Triple("nvptx64-nvidia-cuda"), Triple(), -1);
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"),
Triple(), -1);
HostLinuxParallelParallel.addTrait(
TraitProperty::construct_parallel_parallel);
HostLinuxParallelParallel.addTrait(
TraitProperty::construct_parallel_parallel);
OMPContext DeviceLinuxTargetParallel(true, Triple("x86_64-unknown-linux"),
Triple(), -1);
DeviceLinuxTargetParallel.addTrait(TraitProperty::construct_target_target);
DeviceLinuxTargetParallel.addTrait(
TraitProperty::construct_parallel_parallel);
OMPContext HostNVPTXFor(false, Triple("nvptx64-nvidia-cuda"), Triple(), -1);
HostNVPTXFor.addTrait(TraitProperty::construct_for_for);
OMPContext DeviceNVPTXTargetTeamsParallel(true, Triple("nvptx64-nvidia-cuda"),
Triple(), -1);
DeviceNVPTXTargetTeamsParallel.addTrait(
TraitProperty::construct_target_target);
DeviceNVPTXTargetTeamsParallel.addTrait(TraitProperty::construct_teams_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,
DeviceNVPTXTargetTeamsParallel));
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,
DeviceNVPTXTargetTeamsParallel));
APInt Score(32, 1000);
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, "",
&Score);
EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTrue,
HostLinuxParallelParallel));
EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrue,
DeviceLinuxTargetParallel));
EXPECT_TRUE(
isVariantApplicableInContext(LLVMHostUserCondTrue, HostNVPTXFor));
EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrue,
DeviceNVPTXTargetTeamsParallel));
VariantMatchInfo LLVMHostUserCondTrueCPU = LLVMHostUserCondTrue;
LLVMHostUserCondTrueCPU.addTrait(TraitProperty::device_kind_cpu, "");
EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTrueCPU,
HostLinuxParallelParallel));
EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrueCPU,
DeviceLinuxTargetParallel));
EXPECT_FALSE(
isVariantApplicableInContext(LLVMHostUserCondTrueCPU, HostNVPTXFor));
EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrueCPU,
DeviceNVPTXTargetTeamsParallel));
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,
HostLinuxParallelParallel));
EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArmParallel,
DeviceLinuxTargetParallel));
EXPECT_FALSE(
isVariantApplicableInContext(DeviceArchArmParallel, HostNVPTXFor));
EXPECT_FALSE(isVariantApplicableInContext(DeviceArchArmParallel,
DeviceNVPTXTargetTeamsParallel));
VariantMatchInfo LLVMHostUserCondTrueParallel;
LLVMHostUserCondTrueParallel.addTrait(
TraitProperty::implementation_vendor_llvm, "");
LLVMHostUserCondTrueParallel.addTrait(TraitProperty::device_kind_host, "");
LLVMHostUserCondTrueParallel.addTrait(TraitProperty::device_kind_any, "");
LLVMHostUserCondTrueParallel.addTrait(TraitProperty::user_condition_true,
"");
LLVMHostUserCondTrueParallel.addTrait(
TraitProperty::construct_parallel_parallel, "");
EXPECT_TRUE(isVariantApplicableInContext(LLVMHostUserCondTrueParallel,
HostLinuxParallelParallel));
EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrueParallel,
DeviceLinuxTargetParallel));
EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrueParallel,
HostNVPTXFor));
EXPECT_FALSE(isVariantApplicableInContext(LLVMHostUserCondTrueParallel,
DeviceNVPTXTargetTeamsParallel));
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,
HostLinuxParallelParallel));
EXPECT_FALSE(isVariantApplicableInContext(GPUTargetTeams,
DeviceLinuxTargetParallel));
EXPECT_FALSE(isVariantApplicableInContext(GPUTargetTeams, HostNVPTXFor));
EXPECT_TRUE(isVariantApplicableInContext(GPUTargetTeams,
DeviceNVPTXTargetTeamsParallel));
VariantMatchInfo GPUTargetParallel;
GPUTargetParallel.addTrait(TraitProperty::construct_target_target, "");
GPUTargetParallel.addTrait(TraitProperty::construct_parallel_parallel, "");
GPUTargetParallel.addTrait(TraitProperty::device_kind_gpu, "");
EXPECT_FALSE(isVariantApplicableInContext(GPUTargetParallel,
HostLinuxParallelParallel));
EXPECT_FALSE(isVariantApplicableInContext(GPUTargetParallel,
DeviceLinuxTargetParallel));
EXPECT_FALSE(isVariantApplicableInContext(GPUTargetParallel, HostNVPTXFor));
EXPECT_TRUE(isVariantApplicableInContext(GPUTargetParallel,
DeviceNVPTXTargetTeamsParallel));
}
}
TEST_F(OpenMPContextTest, ApplicabilityISATraits) {
struct SSE2Context : OMPContext {
using OMPContext::OMPContext;
bool matchesISATrait(StringRef ISA) const override { return ISA == "sse2"; }
};
SSE2Context Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
// An unsupported ISA in one selector must not fail the other selector.
for (auto [Supported, Unsupported] :
{std::pair(TraitProperty::device_isa___ANY,
TraitProperty::target_device_isa___ANY),
std::pair(TraitProperty::target_device_isa___ANY,
TraitProperty::device_isa___ANY)}) {
VariantMatchInfo VMI;
VMI.addTrait(Supported, "sse2");
VMI.addTrait(Unsupported, "bogus_isa");
EXPECT_FALSE(isVariantApplicableInContext(VMI, Context));
VariantMatchInfo Any = VMI, None = VMI;
Any.addTrait(TraitProperty::implementation_extension_match_any, "");
EXPECT_TRUE(isVariantApplicableInContext(Any, Context));
None.addTrait(TraitProperty::implementation_extension_match_none, "");
EXPECT_FALSE(isVariantApplicableInContext(None, Context));
}
// Every name in one selector is still required.
VariantMatchInfo TwoNames;
TwoNames.addTrait(TraitProperty::device_isa___ANY, "sse2");
TwoNames.addTrait(TraitProperty::device_isa___ANY, "bogus_isa");
TwoNames.addTrait(TraitProperty::implementation_extension_match_any, "");
EXPECT_FALSE(isVariantApplicableInContext(TwoNames, Context));
}
TEST_F(OpenMPContextTest, ScoringSimple) {
OMPContext Parallel(false, Triple("x86_64-unknown-linux"), Triple(), -1);
Parallel.addTrait(TraitProperty::construct_parallel_parallel);
OMPContext NoConstruct(false, Triple("x86_64-unknown-linux"), Triple(), -1);
VariantMatchInfo MatchAny;
MatchAny.addTrait(TraitProperty::construct_target_target, "");
MatchAny.addTrait(TraitProperty::construct_parallel_parallel, "");
MatchAny.addTrait(TraitProperty::implementation_extension_match_any, "");
EXPECT_TRUE(isVariantApplicableInContext(MatchAny, Parallel));
EXPECT_FALSE(isVariantApplicableInContext(MatchAny, NoConstruct));
VariantMatchInfo VendorLLVM;
VendorLLVM.addTrait(TraitProperty::implementation_vendor_llvm, "");
// The matching construct must raise the score, not just win a tie by order.
SmallVector<VariantMatchInfo, 2> MatchAnyCandidates{VendorLLVM, MatchAny};
EXPECT_EQ(getBestVariantMatchForContext(MatchAnyCandidates, Parallel), 1);
VariantMatchInfo MatchNone;
MatchNone.addTrait(TraitProperty::construct_parallel_parallel, "");
MatchNone.addTrait(TraitProperty::implementation_extension_match_none, "");
EXPECT_TRUE(isVariantApplicableInContext(MatchNone, NoConstruct));
EXPECT_FALSE(isVariantApplicableInContext(MatchNone, Parallel));
VariantMatchInfo Empty;
SmallVector<VariantMatchInfo, 2> MatchNoneCandidates{MatchNone, Empty};
EXPECT_EQ(getBestVariantMatchForContext(MatchNoneCandidates, NoConstruct), 0);
}
TEST_F(OpenMPContextTest, ScoringMatchAnyConstructs) {
OMPContext TargetParallel(false, Triple("x86_64-unknown-linux"), Triple(),
-1);
TargetParallel.addTrait(TraitProperty::construct_target_target);
TargetParallel.addTrait(TraitProperty::construct_parallel_parallel);
APInt Score(64, 2);
VariantMatchInfo Scored;
Scored.addTrait(TraitProperty::user_condition_true, "", &Score);
VariantMatchInfo MatchAny;
MatchAny.addTrait(TraitProperty::construct_target_target, "");
MatchAny.addTrait(TraitProperty::construct_parallel_parallel, "");
MatchAny.addTrait(TraitProperty::implementation_extension_match_any, "");
// Both construct matches contribute: 1 + 1 + 2 for MatchAny beats Scored's
// 1 + 2. Keeping only one of the construct matches would not select MatchAny.
SmallVector<VariantMatchInfo, 2> Candidates{Scored, MatchAny};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, TargetParallel), 1);
}
TEST_F(OpenMPContextTest, ScoringMatchAnyWithoutMatchingConstructs) {
OMPContext NoConstruct(false, Triple("x86_64-unknown-linux"), Triple(), -1);
VariantMatchInfo MatchAny;
MatchAny.addTrait(TraitProperty::construct_parallel_parallel, "");
MatchAny.addTrait(TraitProperty::implementation_vendor_llvm, "");
MatchAny.addTrait(TraitProperty::implementation_extension_match_any, "");
EXPECT_TRUE(isVariantApplicableInContext(MatchAny, NoConstruct));
APInt Score(64, 1);
VariantMatchInfo Scored;
Scored.addTrait(TraitProperty::user_condition_true, "", &Score);
// The vendor match makes MatchAny applicable, but the absent construct adds
// no score. Scored wins by 2 to 1.
SmallVector<VariantMatchInfo, 2> Candidates{MatchAny, Scored};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, NoConstruct), 1);
}
TEST_F(OpenMPContextTest, ScoringInvalidProperty) {
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
VariantMatchInfo Unknown;
Unknown.addTrait(TraitProperty::invalid, "bogus_vendor");
EXPECT_FALSE(isVariantApplicableInContext(Unknown, Context));
Unknown.addTrait(TraitProperty::implementation_extension_match_none, "");
EXPECT_TRUE(isVariantApplicableInContext(Unknown, Context));
VariantMatchInfo UserTrue;
UserTrue.addTrait(TraitProperty::user_condition_true, "");
SmallVector<VariantMatchInfo, 2> Candidates{Unknown, UserTrue};
// Scoring an unknown property must not abort. Both score 1, so candidate
// order breaks the tie.
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
APInt Score(64, 1);
Candidates[1].addTrait(TraitProperty::user_condition_true, "", &Score);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
}
TEST_F(OpenMPContextTest, ScoringUserScoreOncePerSelector) {
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
APInt VendorScore(64, 10), Score(64, 11);
VariantMatchInfo TwoVendors, Scored;
TwoVendors.addTrait(TraitProperty::implementation_vendor_llvm, "",
&VendorScore);
TwoVendors.addTrait(TraitProperty::implementation_vendor_amd, "",
&VendorScore);
TwoVendors.addTrait(TraitProperty::implementation_extension_match_any, "");
Scored.addTrait(TraitProperty::user_condition_true, "", &Score);
// The vendor score counts once: 1 + 10 loses to 1 + 11.
SmallVector<VariantMatchInfo, 2> Candidates{TwoVendors, Scored};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
}
TEST_F(OpenMPContextTest, ScoringMultipleProperties) {
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
VariantMatchInfo Device;
Device.addTrait(TraitProperty::device_kind_cpu, "");
Device.addTrait(TraitProperty::device_kind_host, "");
APInt Score(64, 1);
VariantMatchInfo Scored;
Scored.addTrait(TraitProperty::implementation_vendor_llvm, "", &Score);
SmallVector<VariantMatchInfo, 2> Candidates{Scored, Device};
// KIND contributes one weight regardless of its number of properties.
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
TEST_F(OpenMPContextTest, ScoringRepeatedConstructs) {
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
Context.addTrait(TraitProperty::construct_parallel_parallel);
Context.addTrait(TraitProperty::construct_parallel_parallel);
APInt Score(64, 1);
VariantMatchInfo Scored;
Scored.addTrait(TraitProperty::user_condition_true, "", &Score);
VariantMatchInfo Parallel;
Parallel.addTrait(TraitProperty::construct_parallel_parallel, "");
SmallVector<VariantMatchInfo, 2> Candidates{Scored, Parallel};
// The inner PARALLEL scores 3, beating the explicit score's 2.
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
Candidates[1].addTrait(TraitProperty::implementation_extension_match_any, "");
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
// An incomplete match_any selector retains its forward partial match.
VariantMatchInfo Partial;
Partial.addTrait(TraitProperty::construct_target_target, "");
Partial.addTrait(TraitProperty::construct_parallel_parallel, "");
Partial.addTrait(TraitProperty::implementation_extension_match_any, "");
Candidates[1] = Partial;
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
TEST_F(OpenMPContextTest, ScoringHighestOrderedMatch) {
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
Context.addTrait(TraitProperty::construct_parallel_parallel);
Context.addTrait(TraitProperty::construct_for_for);
Context.addTrait(TraitProperty::construct_parallel_parallel);
Context.addTrait(TraitProperty::construct_for_for);
Context.addTrait(TraitProperty::construct_parallel_parallel);
APInt Score(64, 11);
VariantMatchInfo Scored;
Scored.addTrait(TraitProperty::user_condition_true, "", &Score);
VariantMatchInfo ParallelFor;
ParallelFor.addTrait(TraitProperty::construct_parallel_parallel, "");
ParallelFor.addTrait(TraitProperty::construct_for_for, "");
SmallVector<VariantMatchInfo, 2> Candidates{Scored, ParallelFor};
// Positions 3 and 4 score 1 + 4 + 8 = 13. The final PARALLEL cannot be
// chosen because it follows every FOR in the context.
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
Score = APInt(64, 12);
Candidates[0].addTrait(TraitProperty::user_condition_true, "", &Score);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
TEST_F(OpenMPContextTest, ScoringDeviceWeights) {
struct ISAContext : OMPContext {
using OMPContext::OMPContext;
bool matchesISATrait(StringRef) const override { return true; }
};
const TraitProperty Properties[] = {TraitProperty::device_kind_cpu,
TraitProperty::device_arch_arm,
TraitProperty::device_isa___ANY,
TraitProperty::target_device_kind_cpu,
TraitProperty::target_device_arch_arm,
TraitProperty::target_device_isa___ANY};
for (unsigned Depth : {0u, 1u, 2u, 63u, 64u, 65u}) {
ISAContext Context(false, Triple("arm-unknown-linux"), Triple(), -1);
for (unsigned I = 0; I < Depth; ++I)
Context.addTrait(TraitProperty::construct_parallel_parallel);
for (unsigned I = 0; I < 6; ++I) {
SCOPED_TRACE(Depth);
SCOPED_TRACE(I);
APInt Weight = APInt::getOneBitSet(128, Depth + I % 3);
APInt Score = Weight - 1;
VariantMatchInfo Scored, Device;
Scored.addTrait(TraitProperty::user_condition_true, "", &Score);
Device.addTrait(Properties[I], "test-isa");
SmallVector<VariantMatchInfo, 2> Candidates{Scored, Device};
// The device score is exactly 1 + 2^(context depth + trait offset).
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
Candidates[0].addTrait(TraitProperty::user_condition_true, "", &Weight);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
}
}
TEST_F(OpenMPContextTest, ScoringWideTotals) {
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
Context.addTrait(TraitProperty::construct_parallel_parallel);
for (unsigned Bits : {63u, 64u, 127u}) {
SCOPED_TRACE(Bits);
APInt Score = APInt::getLowBitsSet(Bits + 1, Bits);
VariantMatchInfo Large, Small;
Large.addTrait(TraitProperty::user_condition_true, "", &Score);
Large.addTrait(TraitProperty::implementation_vendor_llvm, "", &Score);
Large.addTrait(TraitProperty::construct_parallel_parallel, "");
APInt SmallScore(32, 20);
Small.addTrait(TraitProperty::user_condition_true, "", &SmallScore);
SmallVector<VariantMatchInfo, 2> Candidates{Large, Small};
// The sum is 2^(Bits + 1), not zero after fixed-width overflow.
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
std::swap(Candidates[0], Candidates[1]);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
// Overflow to a nonzero value must not silently reverse the ranking.
Candidates[1].addTrait(TraitProperty::device_kind_cpu, "");
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
}
}
TEST_F(OpenMPContextTest, ScoringDeepConstructs) {
for (unsigned Depth : {63u, 64u, 65u}) {
SCOPED_TRACE(Depth);
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
for (unsigned I = 0; I < Depth; ++I)
Context.addTrait(TraitProperty::construct_parallel_parallel);
APInt Weight = APInt::getOneBitSet(128, Depth - 1);
APInt Score = Weight - 1;
VariantMatchInfo Scored, Parallel;
Scored.addTrait(TraitProperty::user_condition_true, "", &Score);
Parallel.addTrait(TraitProperty::construct_parallel_parallel, "");
SmallVector<VariantMatchInfo, 2> Candidates{Scored, Parallel};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
Candidates[0].addTrait(TraitProperty::user_condition_true, "", &Weight);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
}
TEST_F(OpenMPContextTest, ConstructContextStartsAtTarget) {
OMPContext ParallelTarget(false, Triple("x86_64-unknown-linux"), Triple(),
-1);
ParallelTarget.addTrait(TraitProperty::construct_parallel_parallel);
ParallelTarget.addTrait(TraitProperty::construct_target_target);
OMPContext ParallelTargetParallel(false, Triple("x86_64-unknown-linux"),
Triple(), -1);
ParallelTargetParallel.addTrait(TraitProperty::construct_parallel_parallel);
ParallelTargetParallel.addTrait(TraitProperty::construct_target_target);
ParallelTargetParallel.addTrait(TraitProperty::construct_parallel_parallel);
EXPECT_FALSE(ParallelTarget.ActiveTraits.test(
unsigned(TraitProperty::construct_parallel_parallel)));
EXPECT_TRUE(ParallelTargetParallel.ActiveTraits.test(
unsigned(TraitProperty::construct_parallel_parallel)));
VariantMatchInfo Parallel, ParallelParallel, TargetParallel;
Parallel.addTrait(TraitProperty::construct_parallel_parallel, "");
ParallelParallel.addTrait(TraitProperty::construct_parallel_parallel, "");
ParallelParallel.addTrait(TraitProperty::construct_parallel_parallel, "");
TargetParallel.addTrait(TraitProperty::construct_target_target, "");
TargetParallel.addTrait(TraitProperty::construct_parallel_parallel, "");
EXPECT_FALSE(isVariantApplicableInContext(Parallel, ParallelTarget));
EXPECT_TRUE(isVariantApplicableInContext(Parallel, ParallelTargetParallel));
EXPECT_FALSE(
isVariantApplicableInContext(ParallelParallel, ParallelTargetParallel));
EXPECT_TRUE(
isVariantApplicableInContext(TargetParallel, ParallelTargetParallel));
}
TEST_F(OpenMPContextTest, StrictSubsetWithRepeatedConstruct) {
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
Context.addTrait(TraitProperty::construct_parallel_parallel);
Context.addTrait(TraitProperty::construct_for_for);
Context.addTrait(TraitProperty::construct_parallel_parallel);
APInt Four(64, 4), One(64, 1);
VariantMatchInfo ParallelFor, ParallelForParallel, ForParallel;
ParallelFor.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
ParallelFor.addTrait(TraitProperty::construct_parallel_parallel, "");
ParallelFor.addTrait(TraitProperty::construct_for_for, "");
ParallelForParallel.addTrait(TraitProperty::implementation_vendor_llvm, "");
ParallelForParallel.addTrait(TraitProperty::construct_parallel_parallel, "");
ParallelForParallel.addTrait(TraitProperty::construct_for_for, "");
ParallelForParallel.addTrait(TraitProperty::construct_parallel_parallel, "");
ForParallel.addTrait(TraitProperty::implementation_vendor_llvm, "", &One);
ForParallel.addTrait(TraitProperty::construct_for_for, "");
ForParallel.addTrait(TraitProperty::construct_parallel_parallel, "");
// All score 8 and require the same properties. Only the repeated construct
// makes ParallelFor a strict subset of ParallelForParallel.
SmallVector<VariantMatchInfo, 2> Candidates{ParallelFor, ParallelForParallel};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
std::swap(Candidates[0], Candidates[1]);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
// Sequences of the same length are not strict subsets of each other.
Candidates = {ParallelFor, ForParallel};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
std::swap(Candidates[0], Candidates[1]);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
TEST_F(OpenMPContextTest, RepeatedConstructWithConditionOrISA) {
struct ISAContext : OMPContext {
using OMPContext::OMPContext;
bool matchesISATrait(StringRef) const override { return true; }
} Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
Context.addTrait(TraitProperty::construct_parallel_parallel);
Context.addTrait(TraitProperty::construct_for_for);
Context.addTrait(TraitProperty::construct_parallel_parallel);
// Each pair ties and requires the same traits, but the conditions or ISA
// names may differ, so clause order decides.
APInt Zero(64, 0), Four(64, 4);
for (TraitProperty Property :
{TraitProperty::user_condition_true, TraitProperty::device_isa___ANY}) {
VariantMatchInfo ParallelFor, ParallelForParallel;
ParallelFor.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
ParallelFor.addTrait(Property, "sse", &Zero);
ParallelFor.addTrait(TraitProperty::construct_parallel_parallel, "");
ParallelFor.addTrait(TraitProperty::construct_for_for, "");
ParallelForParallel.addTrait(TraitProperty::implementation_vendor_llvm, "");
ParallelForParallel.addTrait(Property, "sse2", &Zero);
ParallelForParallel.addTrait(TraitProperty::construct_parallel_parallel,
"");
ParallelForParallel.addTrait(TraitProperty::construct_for_for, "");
ParallelForParallel.addTrait(TraitProperty::construct_parallel_parallel,
"");
SmallVector<VariantMatchInfo, 2> Candidates{ParallelFor,
ParallelForParallel};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
std::swap(Candidates[0], Candidates[1]);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
// With all of the shorter selector's ISA names, the longer one wins.
if (Property == TraitProperty::device_isa___ANY) {
Candidates[0].addTrait(Property, "sse");
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
std::swap(Candidates[0], Candidates[1]);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 1);
// The same ISA names in swapped selectors are not subsets of each other.
ParallelFor.addTrait(TraitProperty::target_device_isa___ANY, "sse2",
&Zero);
ParallelForParallel.addTrait(TraitProperty::target_device_isa___ANY,
"sse", &Zero);
Candidates = {ParallelFor, ParallelForParallel};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
std::swap(Candidates[0], Candidates[1]);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
}
}
TEST_F(OpenMPContextTest, ConstructOrderInStrictSubset) {
APInt Five(64, 5);
{
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
Context.addTrait(TraitProperty::construct_for_for);
Context.addTrait(TraitProperty::construct_parallel_parallel);
Context.addTrait(TraitProperty::construct_for_for);
Context.addTrait(TraitProperty::construct_simd_simd);
VariantMatchInfo ParallelFor, ForParallelSimd;
ParallelFor.addTrait(TraitProperty::implementation_vendor_llvm, "", &Five);
ParallelFor.addTrait(TraitProperty::construct_parallel_parallel, "");
ParallelFor.addTrait(TraitProperty::construct_for_for, "");
ForParallelSimd.addTrait(TraitProperty::implementation_vendor_llvm, "");
ForParallelSimd.addTrait(TraitProperty::user_condition_true, "");
ForParallelSimd.addTrait(TraitProperty::construct_for_for, "");
ForParallelSimd.addTrait(TraitProperty::construct_parallel_parallel, "");
ForParallelSimd.addTrait(TraitProperty::construct_simd_simd, "");
// Both score 12. Each property of ParallelFor is also required by
// ForParallelSimd, but its construct sequence is not a subsequence.
SmallVector<VariantMatchInfo, 2> Candidates{ParallelFor, ForParallelSimd};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
std::swap(Candidates[0], Candidates[1]);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
{
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
Context.addTrait(TraitProperty::construct_parallel_parallel);
Context.addTrait(TraitProperty::construct_parallel_parallel);
Context.addTrait(TraitProperty::construct_for_for);
Context.addTrait(TraitProperty::construct_parallel_parallel);
VariantMatchInfo ForParallel, ParallelParallelFor;
ForParallel.addTrait(TraitProperty::implementation_vendor_llvm, "");
ForParallel.addTrait(TraitProperty::construct_for_for, "");
ForParallel.addTrait(TraitProperty::construct_parallel_parallel, "");
ParallelParallelFor.addTrait(TraitProperty::implementation_vendor_llvm, "",
&Five);
ParallelParallelFor.addTrait(TraitProperty::construct_parallel_parallel,
"");
ParallelParallelFor.addTrait(TraitProperty::construct_parallel_parallel,
"");
ParallelParallelFor.addTrait(TraitProperty::construct_for_for, "");
// Both score 13 and require the same properties. The shorter sequence is
// not a subsequence of the longer one.
SmallVector<VariantMatchInfo, 2> Candidates{ForParallel,
ParallelParallelFor};
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
std::swap(Candidates[0], Candidates[1]);
EXPECT_EQ(getBestVariantMatchForContext(Candidates, Context), 0);
}
}
TEST_F(OpenMPContextTest, StrictSubsetOfLaterTiedVariant) {
OMPContext HostLinux(false, Triple("x86_64-unknown-linux"), Triple(), -1);
APInt Three(64, 3), Four(64, 4);
VariantMatchInfo Subset, Other, Superset;
Subset.addTrait(TraitProperty::user_condition_true, "");
Subset.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
Other.addTrait(TraitProperty::device_kind_cpu, "");
Other.addTrait(TraitProperty::implementation_vendor_llvm, "", &Three);
Superset.addTrait(TraitProperty::user_condition_true, "");
Superset.addTrait(TraitProperty::device_kind_host, "");
Superset.addTrait(TraitProperty::implementation_vendor_llvm, "", &Three);
auto Best = [&](std::initializer_list<VariantMatchInfo> VMIs) {
return getBestVariantMatchForContext(SmallVector<VariantMatchInfo, 3>(VMIs),
HostLinux);
};
// All three score 5. Subset is a strict subset of Superset, and the first of
// the other two wins.
EXPECT_EQ(Best({Subset, Other, Superset}), 1);
EXPECT_EQ(Best({Subset, Superset, Other}), 1);
}
TEST_F(OpenMPContextTest, StrictSubsetsOfAlternatingTiedSupersets) {
OMPContext HostLinux(false, Triple("x86_64-unknown-linux"), Triple(), -1);
APInt Three(64, 3);
VariantMatchInfo Host, CPU, HostSuperset, CPUSuperset;
Host.addTrait(TraitProperty::device_kind_host, "");
Host.addTrait(TraitProperty::implementation_vendor_llvm, "", &Three);
CPU.addTrait(TraitProperty::device_kind_cpu, "");
CPU.addTrait(TraitProperty::implementation_vendor_llvm, "", &Three);
HostSuperset = Host;
HostSuperset.addTrait(TraitProperty::user_condition_true, "");
CPUSuperset = CPU;
CPUSuperset.addTrait(TraitProperty::user_condition_true, "");
auto Best = [&](std::initializer_list<VariantMatchInfo> VMIs) {
return getBestVariantMatchForContext(SmallVector<VariantMatchInfo, 6>(VMIs),
HostLinux);
};
// All score 5. Host and CPU are strict subsets of different supersets, so
// the supersets they lose to alternate. The first variant that isn't a strict
// subset of another one wins.
EXPECT_EQ(Best({Host, CPU, Host, CPU, HostSuperset, CPUSuperset}), 4);
EXPECT_EQ(Best({Host, CPU, Host, CPU, CPUSuperset, HostSuperset}), 4);
EXPECT_EQ(Best({Host, CPU, Host, HostSuperset}), 1);
}
TEST_F(OpenMPContextTest, UserConditionInStrictSubset) {
OMPContext Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
APInt Three(64, 3), Four(64, 4), Five(64, 5);
VariantMatchInfo A, B;
A.addTrait(TraitProperty::user_condition_true, "");
A.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
B.addTrait(TraitProperty::user_condition_true, "");
B.addTrait(TraitProperty::implementation_vendor_llvm, "", &Three);
B.addTrait(TraitProperty::device_kind_host, "");
auto Best = [&](const VariantMatchInfo &First,
const VariantMatchInfo &Second) {
return getBestVariantMatchForContext(
SmallVector<VariantMatchInfo, 2>{First, Second}, Context);
};
// Both score 5. Constant conditions are compared by their trait alone.
EXPECT_EQ(Best(A, B), 1);
EXPECT_EQ(Best(B, A), 0);
// Different runtime conditions keep clause order.
A.UserCondition = "a";
B.UserCondition = "b";
EXPECT_EQ(Best(A, B), 0);
EXPECT_EQ(Best(B, A), 0);
// The same runtime condition still makes A a strict subset of B.
B.UserCondition = "a";
EXPECT_EQ(Best(A, B), 1);
EXPECT_EQ(Best(B, A), 0);
// A higher score wins regardless of the conditions.
B.UserCondition = "b";
A.ScoreMap[TraitProperty::implementation_vendor_llvm] = Five;
EXPECT_EQ(Best(A, B), 0);
EXPECT_EQ(Best(B, A), 1);
// A runtime condition left out of the traits is still compared by its key.
VariantMatchInfo C;
C.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
C.UserCondition = "a";
EXPECT_EQ(Best(C, B), 0);
EXPECT_EQ(Best(B, C), 0);
C.UserCondition = "b";
EXPECT_EQ(Best(C, B), 1);
// A constant condition is different from a runtime condition.
C.UserCondition = "";
C.addTrait(TraitProperty::user_condition_true, "");
EXPECT_EQ(Best(C, B), 0);
// A condition left out of the traits still counts as one, so D, which only
// has the key, is not a strict subset of E, which also has the trait.
VariantMatchInfo D, E;
D.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
D.UserCondition = "a";
E.addTrait(TraitProperty::user_condition_true, "");
E.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
E.UserCondition = "a";
EXPECT_EQ(Best(D, E), 0);
EXPECT_EQ(Best(E, D), 0);
// The key also stands for a condition left out of a superset's traits, as
// for a WHEN clause that omits its directive.
VariantMatchInfo F;
F.addTrait(TraitProperty::implementation_vendor_llvm, "", &Three);
F.addTrait(TraitProperty::device_kind_host, "");
F.UserCondition = "a";
EXPECT_EQ(Best(E, F), 1);
EXPECT_EQ(Best(F, E), 0);
F.UserCondition = "b";
EXPECT_EQ(Best(E, F), 0);
// A selector without a condition can be a strict subset of one with a
// runtime condition.
VariantMatchInfo G;
G.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
EXPECT_EQ(Best(G, B), 1);
EXPECT_EQ(Best(B, G), 0);
}
TEST_F(OpenMPContextTest, ISANamesInStrictSubset) {
struct ISAContext : OMPContext {
using OMPContext::OMPContext;
bool matchesISATrait(StringRef) const override { return true; }
} Context(false, Triple("x86_64-unknown-linux"), Triple(), -1);
APInt Three(64, 3), Four(64, 4);
VariantMatchInfo SSE, AVX;
SSE.addTrait(TraitProperty::device_isa___ANY, "sse");
SSE.addTrait(TraitProperty::implementation_vendor_llvm, "", &Four);
AVX.addTrait(TraitProperty::device_isa___ANY, "avx");
AVX.addTrait(TraitProperty::implementation_vendor_llvm, "", &Three);
AVX.addTrait(TraitProperty::device_kind_host, "");
auto Best = [&](const VariantMatchInfo &First,
const VariantMatchInfo &Second) {
return getBestVariantMatchForContext(
SmallVector<VariantMatchInfo, 2>{First, Second}, Context);
};
// Both score 9. AVX requires more traits, but not the `sse` ISA name.
EXPECT_EQ(Best(SSE, AVX), 0);
EXPECT_EQ(Best(AVX, SSE), 0);
// A runtime condition left out of the traits is counted the same way.
VariantMatchInfo AVXWithCondition;
AVXWithCondition.addTrait(TraitProperty::device_isa___ANY, "avx");
AVXWithCondition.addTrait(TraitProperty::implementation_vendor_llvm, "",
&Four);
AVXWithCondition.UserCondition = "a";
EXPECT_EQ(Best(SSE, AVXWithCondition), 0);
EXPECT_EQ(Best(AVXWithCondition, SSE), 0);
// With all of SSE's ISA names, AVX is a strict superset.
AVX.addTrait(TraitProperty::device_isa___ANY, "sse");
EXPECT_EQ(Best(SSE, AVX), 1);
EXPECT_EQ(Best(AVX, SSE), 0);
}
} // namespace