diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:46:15 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:46:15 +0000 |
commit | dd58ef019b700900793a1eb48b52123db01b654e (patch) | |
tree | fcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /unittests/Analysis | |
parent | 2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff) | |
download | src-dd58ef019b700900793a1eb48b52123db01b654e.tar.gz src-dd58ef019b700900793a1eb48b52123db01b654e.zip |
Vendor import of llvm trunk r256633:
Notes
Notes:
svn path=/vendor/llvm/dist/; revision=292915
Diffstat (limited to 'unittests/Analysis')
-rw-r--r-- | unittests/Analysis/AliasAnalysisTest.cpp | 252 | ||||
-rw-r--r-- | unittests/Analysis/CFGTest.cpp | 2 | ||||
-rw-r--r-- | unittests/Analysis/CMakeLists.txt | 2 | ||||
-rw-r--r-- | unittests/Analysis/Makefile | 2 | ||||
-rw-r--r-- | unittests/Analysis/MixedTBAATest.cpp | 3 | ||||
-rw-r--r-- | unittests/Analysis/ScalarEvolutionTest.cpp | 35 | ||||
-rw-r--r-- | unittests/Analysis/ValueTrackingTest.cpp | 189 |
7 files changed, 417 insertions, 68 deletions
diff --git a/unittests/Analysis/AliasAnalysisTest.cpp b/unittests/Analysis/AliasAnalysisTest.cpp index 62bfaa125133..ee116992fe76 100644 --- a/unittests/Analysis/AliasAnalysisTest.cpp +++ b/unittests/Analysis/AliasAnalysisTest.cpp @@ -8,63 +8,162 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/Passes.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/AsmParser/Parser.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" +using namespace llvm; + +// Set up some test passes. namespace llvm { +void initializeAATestPassPass(PassRegistry&); +void initializeTestCustomAAWrapperPassPass(PassRegistry&); +} + namespace { +struct AATestPass : FunctionPass { + static char ID; + AATestPass() : FunctionPass(ID) { + initializeAATestPassPass(*PassRegistry::getPassRegistry()); + } -class AliasAnalysisTest : public testing::Test { -protected: - AliasAnalysisTest() : M("AliasAnalysisTBAATest", C) {} - - // This is going to check that calling getModRefInfo without a location, and - // with a default location, first, doesn't crash, and second, gives the right - // answer. - void CheckModRef(Instruction *I, AliasAnalysis::ModRefResult Result) { - static char ID; - class CheckModRefTestPass : public FunctionPass { - public: - CheckModRefTestPass(Instruction *I, AliasAnalysis::ModRefResult Result) - : FunctionPass(ID), ExpectResult(Result), I(I) {} - static int initialize() { - PassInfo *PI = new PassInfo("CheckModRef testing pass", "", &ID, - nullptr, true, true); - PassRegistry::getPassRegistry()->registerPass(*PI, false); - initializeAliasAnalysisAnalysisGroup(*PassRegistry::getPassRegistry()); - initializeBasicAliasAnalysisPass(*PassRegistry::getPassRegistry()); - return 0; - } - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - AU.addRequiredTransitive<AliasAnalysis>(); - } - bool runOnFunction(Function &) override { - AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); - EXPECT_EQ(AA.getModRefInfo(I, MemoryLocation()), ExpectResult); - EXPECT_EQ(AA.getModRefInfo(I), ExpectResult); - return false; - } - AliasAnalysis::ModRefResult ExpectResult; - Instruction *I; - }; - static int initialize = CheckModRefTestPass::initialize(); - (void)initialize; - CheckModRefTestPass *P = new CheckModRefTestPass(I, Result); - legacy::PassManager PM; - PM.add(createBasicAliasAnalysisPass()); - PM.add(P); - PM.run(M); + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired<AAResultsWrapperPass>(); + AU.setPreservesAll(); } + bool runOnFunction(Function &F) override { + AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); + + SetVector<Value *> Pointers; + for (Argument &A : F.args()) + if (A.getType()->isPointerTy()) + Pointers.insert(&A); + for (Instruction &I : instructions(F)) + if (I.getType()->isPointerTy()) + Pointers.insert(&I); + + for (Value *P1 : Pointers) + for (Value *P2 : Pointers) + (void)AA.alias(P1, MemoryLocation::UnknownSize, P2, + MemoryLocation::UnknownSize); + + return false; + } +}; +} + +char AATestPass::ID = 0; +INITIALIZE_PASS_BEGIN(AATestPass, "aa-test-pas", "Alias Analysis Test Pass", + false, true) +INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) +INITIALIZE_PASS_END(AATestPass, "aa-test-pass", "Alias Analysis Test Pass", + false, true) + +namespace { +/// A test customizable AA result. It merely accepts a callback to run whenever +/// it receives an alias query. Useful for testing that a particular AA result +/// is reached. +struct TestCustomAAResult : AAResultBase<TestCustomAAResult> { + friend AAResultBase<TestCustomAAResult>; + + std::function<void()> CB; + + explicit TestCustomAAResult(const TargetLibraryInfo &TLI, + std::function<void()> CB) + : AAResultBase(TLI), CB(std::move(CB)) {} + TestCustomAAResult(TestCustomAAResult &&Arg) + : AAResultBase(std::move(Arg)), CB(std::move(Arg.CB)) {} + + bool invalidate(Function &, const PreservedAnalyses &) { return false; } + + AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) { + CB(); + return MayAlias; + } +}; +} + +namespace { +/// A wrapper pass for the legacy pass manager to use with the above custom AA +/// result. +class TestCustomAAWrapperPass : public ImmutablePass { + std::function<void()> CB; + std::unique_ptr<TestCustomAAResult> Result; + +public: + static char ID; + + explicit TestCustomAAWrapperPass( + std::function<void()> CB = std::function<void()>()) + : ImmutablePass(ID), CB(std::move(CB)) { + initializeTestCustomAAWrapperPassPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + AU.addRequired<TargetLibraryInfoWrapperPass>(); + } + + bool doInitialization(Module &M) override { + Result.reset(new TestCustomAAResult( + getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(), std::move(CB))); + return true; + } + + bool doFinalization(Module &M) override { + Result.reset(); + return true; + } + + TestCustomAAResult &getResult() { return *Result; } + const TestCustomAAResult &getResult() const { return *Result; } +}; +} + +char TestCustomAAWrapperPass::ID = 0; +INITIALIZE_PASS_BEGIN(TestCustomAAWrapperPass, "test-custom-aa", + "Test Custom AA Wrapper Pass", false, true) +INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) +INITIALIZE_PASS_END(TestCustomAAWrapperPass, "test-custom-aa", + "Test Custom AA Wrapper Pass", false, true) + +namespace { + +class AliasAnalysisTest : public testing::Test { +protected: LLVMContext C; Module M; + TargetLibraryInfoImpl TLII; + TargetLibraryInfo TLI; + std::unique_ptr<AssumptionCache> AC; + std::unique_ptr<BasicAAResult> BAR; + std::unique_ptr<AAResults> AAR; + + AliasAnalysisTest() : M("AliasAnalysisTest", C), TLI(TLII) {} + + AAResults &getAAResults(Function &F) { + // Reset the Function AA results first to clear out any references. + AAR.reset(new AAResults()); + + // Build the various AA results and register them. + AC.reset(new AssumptionCache(F)); + BAR.reset(new BasicAAResult(M.getDataLayout(), TLI, *AC)); + AAR->addAAResult(*BAR); + + return *AAR; + } }; TEST_F(AliasAnalysisTest, getModRefInfo) { @@ -91,14 +190,67 @@ TEST_F(AliasAnalysisTest, getModRefInfo) { ReturnInst::Create(C, nullptr, BB); + auto &AA = getAAResults(*F); + // Check basic results - CheckModRef(Store1, AliasAnalysis::ModRefResult::Mod); - CheckModRef(Load1, AliasAnalysis::ModRefResult::Ref); - CheckModRef(Add1, AliasAnalysis::ModRefResult::NoModRef); - CheckModRef(VAArg1, AliasAnalysis::ModRefResult::ModRef); - CheckModRef(CmpXChg1, AliasAnalysis::ModRefResult::ModRef); - CheckModRef(AtomicRMW, AliasAnalysis::ModRefResult::ModRef); + EXPECT_EQ(AA.getModRefInfo(Store1, MemoryLocation()), MRI_Mod); + EXPECT_EQ(AA.getModRefInfo(Store1), MRI_Mod); + EXPECT_EQ(AA.getModRefInfo(Load1, MemoryLocation()), MRI_Ref); + EXPECT_EQ(AA.getModRefInfo(Load1), MRI_Ref); + EXPECT_EQ(AA.getModRefInfo(Add1, MemoryLocation()), MRI_NoModRef); + EXPECT_EQ(AA.getModRefInfo(Add1), MRI_NoModRef); + EXPECT_EQ(AA.getModRefInfo(VAArg1, MemoryLocation()), MRI_ModRef); + EXPECT_EQ(AA.getModRefInfo(VAArg1), MRI_ModRef); + EXPECT_EQ(AA.getModRefInfo(CmpXChg1, MemoryLocation()), MRI_ModRef); + EXPECT_EQ(AA.getModRefInfo(CmpXChg1), MRI_ModRef); + EXPECT_EQ(AA.getModRefInfo(AtomicRMW, MemoryLocation()), MRI_ModRef); + EXPECT_EQ(AA.getModRefInfo(AtomicRMW), MRI_ModRef); +} + +class AAPassInfraTest : public testing::Test { +protected: + LLVMContext &C; + SMDiagnostic Err; + std::unique_ptr<Module> M; + +public: + AAPassInfraTest() + : C(getGlobalContext()), + M(parseAssemblyString("define i32 @f(i32* %x, i32* %y) {\n" + "entry:\n" + " %lx = load i32, i32* %x\n" + " %ly = load i32, i32* %y\n" + " %sum = add i32 %lx, %ly\n" + " ret i32 %sum\n" + "}\n", + Err, C)) { + assert(M && "Failed to build the module!"); + } +}; + +TEST_F(AAPassInfraTest, injectExternalAA) { + legacy::PassManager PM; + + // Register our custom AA's wrapper pass manually. + bool IsCustomAAQueried = false; + PM.add(new TestCustomAAWrapperPass([&] { IsCustomAAQueried = true; })); + + // Now add the external AA wrapper with a lambda which queries for the + // wrapper around our custom AA and adds it to the results. + PM.add(createExternalAAWrapperPass([](Pass &P, Function &, AAResults &AAR) { + if (auto *WrapperPass = P.getAnalysisIfAvailable<TestCustomAAWrapperPass>()) + AAR.addAAResult(WrapperPass->getResult()); + })); + + // And run a pass that will make some alias queries. This will automatically + // trigger the rest of the alias analysis stack to be run. It is analagous to + // building a full pass pipeline with any of the existing pass manager + // builders. + PM.add(new AATestPass()); + PM.run(*M); + + // Finally, ensure that our custom AA was indeed queried. + EXPECT_TRUE(IsCustomAAQueried); } } // end anonymous namspace -} // end llvm namespace diff --git a/unittests/Analysis/CFGTest.cpp b/unittests/Analysis/CFGTest.cpp index b29c168ce08b..44f0fe681dff 100644 --- a/unittests/Analysis/CFGTest.cpp +++ b/unittests/Analysis/CFGTest.cpp @@ -378,7 +378,7 @@ TEST_F(IsPotentiallyReachableTest, BranchInsideLoop) { TEST_F(IsPotentiallyReachableTest, ModifyTest) { ParseAssembly(BranchInsideLoopIR); - succ_iterator S = succ_begin(++M->getFunction("test")->begin()); + succ_iterator S = succ_begin(&*++M->getFunction("test")->begin()); BasicBlock *OldBB = S[0]; S[0] = S[1]; ExpectPath(false); diff --git a/unittests/Analysis/CMakeLists.txt b/unittests/Analysis/CMakeLists.txt index 35a6d92ce179..06560cf14d4a 100644 --- a/unittests/Analysis/CMakeLists.txt +++ b/unittests/Analysis/CMakeLists.txt @@ -1,5 +1,4 @@ set(LLVM_LINK_COMPONENTS - IPA Analysis AsmParser Core @@ -13,4 +12,5 @@ add_llvm_unittest(AnalysisTests LazyCallGraphTest.cpp ScalarEvolutionTest.cpp MixedTBAATest.cpp + ValueTrackingTest.cpp ) diff --git a/unittests/Analysis/Makefile b/unittests/Analysis/Makefile index 52296e7b3db2..527f4525e87e 100644 --- a/unittests/Analysis/Makefile +++ b/unittests/Analysis/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. TESTNAME = Analysis -LINK_COMPONENTS := ipa analysis asmparser +LINK_COMPONENTS := analysis asmparser include $(LEVEL)/Makefile.config include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Analysis/MixedTBAATest.cpp b/unittests/Analysis/MixedTBAATest.cpp index 7b8a25c44389..d0cfa59f6459 100644 --- a/unittests/Analysis/MixedTBAATest.cpp +++ b/unittests/Analysis/MixedTBAATest.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Analysis/TypeBasedAliasAnalysis.h" #include "llvm/Analysis/Passes.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" @@ -67,7 +68,7 @@ TEST_F(MixedTBAATest, MixedTBAA) { // because the AA eval pass only runs one test per store-pair. const char* args[] = { "MixedTBAATest", "-evaluate-aa-metadata" }; cl::ParseCommandLineOptions(sizeof(args) / sizeof(const char*), args); - PM.add(createTypeBasedAliasAnalysisPass()); + PM.add(createTypeBasedAAWrapperPass()); PM.add(createAAEvalPass()); PM.run(M); } diff --git a/unittests/Analysis/ScalarEvolutionTest.cpp b/unittests/Analysis/ScalarEvolutionTest.cpp index 6ce7ff43a312..938dafe60384 100644 --- a/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/unittests/Analysis/ScalarEvolutionTest.cpp @@ -8,9 +8,13 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -24,16 +28,23 @@ namespace { // deleting the PassManager. class ScalarEvolutionsTest : public testing::Test { protected: - ScalarEvolutionsTest() : M("", Context), SE(*new ScalarEvolution) {} - ~ScalarEvolutionsTest() override { - // Manually clean up, since we allocated new SCEV objects after the - // pass was finished. - SE.releaseMemory(); - } LLVMContext Context; Module M; - legacy::PassManager PM; - ScalarEvolution &SE; + TargetLibraryInfoImpl TLII; + TargetLibraryInfo TLI; + + std::unique_ptr<AssumptionCache> AC; + std::unique_ptr<DominatorTree> DT; + std::unique_ptr<LoopInfo> LI; + + ScalarEvolutionsTest() : M("", Context), TLII(), TLI(TLII) {} + + ScalarEvolution buildSE(Function &F) { + AC.reset(new AssumptionCache(F)); + DT.reset(new DominatorTree(F)); + LI.reset(new LoopInfo(*DT)); + return ScalarEvolution(F, TLI, *AC, *DT, *LI); + } }; TEST_F(ScalarEvolutionsTest, SCEVUnknownRAUW) { @@ -49,9 +60,7 @@ TEST_F(ScalarEvolutionsTest, SCEVUnknownRAUW) { Value *V1 = new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage, Init, "V1"); Value *V2 = new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage, Init, "V2"); - // Create a ScalarEvolution and "run" it so that it gets initialized. - PM.add(&SE); - PM.run(M); + ScalarEvolution SE = buildSE(*F); const SCEV *S0 = SE.getSCEV(V0); const SCEV *S1 = SE.getSCEV(V1); @@ -96,9 +105,7 @@ TEST_F(ScalarEvolutionsTest, SCEVMultiplyAddRecs) { BasicBlock *BB = BasicBlock::Create(Context, "entry", F); ReturnInst::Create(Context, nullptr, BB); - // Create a ScalarEvolution and "run" it so that it gets initialized. - PM.add(&SE); - PM.run(M); + ScalarEvolution SE = buildSE(*F); // It's possible to produce an empty loop through the default constructor, // but you can't add any blocks to it without a LoopInfo pass. diff --git a/unittests/Analysis/ValueTrackingTest.cpp b/unittests/Analysis/ValueTrackingTest.cpp new file mode 100644 index 000000000000..3af856ea2039 --- /dev/null +++ b/unittests/Analysis/ValueTrackingTest.cpp @@ -0,0 +1,189 @@ +//===- ValueTrackingTest.cpp - ValueTracking tests ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class MatchSelectPatternTest : public testing::Test { +protected: + void parseAssembly(const char *Assembly) { + SMDiagnostic Error; + M = parseAssemblyString(Assembly, Error, getGlobalContext()); + + std::string errMsg; + raw_string_ostream os(errMsg); + Error.print("", os); + + // A failure here means that the test itself is buggy. + if (!M) + report_fatal_error(os.str()); + + Function *F = M->getFunction("test"); + if (F == nullptr) + report_fatal_error("Test must have a function named @test"); + + A = nullptr; + for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { + if (I->hasName()) { + if (I->getName() == "A") + A = &*I; + } + } + if (A == nullptr) + report_fatal_error("@test must have an instruction %A"); + } + + void expectPattern(const SelectPatternResult &P) { + Value *LHS, *RHS; + Instruction::CastOps CastOp; + SelectPatternResult R = matchSelectPattern(A, LHS, RHS, &CastOp); + EXPECT_EQ(P.Flavor, R.Flavor); + EXPECT_EQ(P.NaNBehavior, R.NaNBehavior); + EXPECT_EQ(P.Ordered, R.Ordered); + } + + std::unique_ptr<Module> M; + Instruction *A, *B; +}; + +} + +TEST_F(MatchSelectPatternTest, SimpleFMin) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp ult float %a, 5.0\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMINNUM, SPNB_RETURNS_NAN, false}); +} + +TEST_F(MatchSelectPatternTest, SimpleFMax) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp ogt float %a, 5.0\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, true}); +} + +TEST_F(MatchSelectPatternTest, SwappedFMax) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp olt float 5.0, %a\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, false}); +} + +TEST_F(MatchSelectPatternTest, SwappedFMax2) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp olt float %a, 5.0\n" + " %A = select i1 %1, float 5.0, float %a\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_NAN, false}); +} + +TEST_F(MatchSelectPatternTest, SwappedFMax3) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp ult float %a, 5.0\n" + " %A = select i1 %1, float 5.0, float %a\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, true}); +} + +TEST_F(MatchSelectPatternTest, FastFMin) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp nnan olt float %a, 5.0\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMINNUM, SPNB_RETURNS_ANY, false}); +} + +TEST_F(MatchSelectPatternTest, FMinConstantZero) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp ole float %a, 0.0\n" + " %A = select i1 %1, float %a, float 0.0\n" + " ret float %A\n" + "}\n"); + // This shouldn't be matched, as %a could be -0.0. + expectPattern({SPF_UNKNOWN, SPNB_NA, false}); +} + +TEST_F(MatchSelectPatternTest, FMinConstantZeroNsz) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp nsz ole float %a, 0.0\n" + " %A = select i1 %1, float %a, float 0.0\n" + " ret float %A\n" + "}\n"); + // But this should be, because we've ignored signed zeroes. + expectPattern({SPF_FMINNUM, SPNB_RETURNS_OTHER, true}); +} + +TEST_F(MatchSelectPatternTest, DoubleCastU) { + parseAssembly( + "define i32 @test(i8 %a, i8 %b) {\n" + " %1 = icmp ult i8 %a, %b\n" + " %2 = zext i8 %a to i32\n" + " %3 = zext i8 %b to i32\n" + " %A = select i1 %1, i32 %2, i32 %3\n" + " ret i32 %A\n" + "}\n"); + // We should be able to look through the situation where we cast both operands + // to the select. + expectPattern({SPF_UMIN, SPNB_NA, false}); +} + +TEST_F(MatchSelectPatternTest, DoubleCastS) { + parseAssembly( + "define i32 @test(i8 %a, i8 %b) {\n" + " %1 = icmp slt i8 %a, %b\n" + " %2 = sext i8 %a to i32\n" + " %3 = sext i8 %b to i32\n" + " %A = select i1 %1, i32 %2, i32 %3\n" + " ret i32 %A\n" + "}\n"); + // We should be able to look through the situation where we cast both operands + // to the select. + expectPattern({SPF_SMIN, SPNB_NA, false}); +} + +TEST_F(MatchSelectPatternTest, DoubleCastBad) { + parseAssembly( + "define i32 @test(i8 %a, i8 %b) {\n" + " %1 = icmp ult i8 %a, %b\n" + " %2 = zext i8 %a to i32\n" + " %3 = sext i8 %b to i32\n" + " %A = select i1 %1, i32 %2, i32 %3\n" + " ret i32 %A\n" + "}\n"); + // The cast types here aren't the same, so we cannot match an UMIN. + expectPattern({SPF_UNKNOWN, SPNB_NA, false}); +} |