| //===- 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 |