aboutsummaryrefslogtreecommitdiff
path: root/unittests/Analysis
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
commitdd58ef019b700900793a1eb48b52123db01b654e (patch)
treefcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /unittests/Analysis
parent2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff)
downloadsrc-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.cpp252
-rw-r--r--unittests/Analysis/CFGTest.cpp2
-rw-r--r--unittests/Analysis/CMakeLists.txt2
-rw-r--r--unittests/Analysis/Makefile2
-rw-r--r--unittests/Analysis/MixedTBAATest.cpp3
-rw-r--r--unittests/Analysis/ScalarEvolutionTest.cpp35
-rw-r--r--unittests/Analysis/ValueTrackingTest.cpp189
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});
+}