forked from OSchip/llvm-project
206 lines
6.7 KiB
C++
206 lines
6.7 KiB
C++
//===- llvm/unittest/Analysis/LoopPassManagerTest.cpp - LPM tests ---------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "llvm/Analysis/LoopPassManager.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/IR/Dominators.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/PassManager.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
class TestLoopAnalysis {
|
|
/// \brief Private static data to provide unique ID.
|
|
static char PassID;
|
|
|
|
int &Runs;
|
|
|
|
public:
|
|
struct Result {
|
|
Result(int Count) : BlockCount(Count) {}
|
|
int BlockCount;
|
|
};
|
|
|
|
/// \brief Returns an opaque, unique ID for this pass type.
|
|
static void *ID() { return (void *)&PassID; }
|
|
|
|
/// \brief Returns the name of the analysis.
|
|
static StringRef name() { return "TestLoopAnalysis"; }
|
|
|
|
TestLoopAnalysis(int &Runs) : Runs(Runs) {}
|
|
|
|
/// \brief Run the analysis pass over the loop and return a result.
|
|
Result run(Loop &L, LoopAnalysisManager &AM) {
|
|
++Runs;
|
|
int Count = 0;
|
|
|
|
for (auto I = L.block_begin(), E = L.block_end(); I != E; ++I)
|
|
++Count;
|
|
return Result(Count);
|
|
}
|
|
};
|
|
|
|
char TestLoopAnalysis::PassID;
|
|
|
|
class TestLoopPass {
|
|
std::vector<StringRef> &VisitedLoops;
|
|
int &AnalyzedBlockCount;
|
|
bool OnlyUseCachedResults;
|
|
|
|
public:
|
|
TestLoopPass(std::vector<StringRef> &VisitedLoops, int &AnalyzedBlockCount,
|
|
bool OnlyUseCachedResults = false)
|
|
: VisitedLoops(VisitedLoops), AnalyzedBlockCount(AnalyzedBlockCount),
|
|
OnlyUseCachedResults(OnlyUseCachedResults) {}
|
|
|
|
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM) {
|
|
VisitedLoops.push_back(L.getName());
|
|
|
|
if (OnlyUseCachedResults) {
|
|
// Hack to force the use of the cached interface.
|
|
if (auto *AR = AM.getCachedResult<TestLoopAnalysis>(L))
|
|
AnalyzedBlockCount += AR->BlockCount;
|
|
} else {
|
|
// Typical path just runs the analysis as needed.
|
|
auto &AR = AM.getResult<TestLoopAnalysis>(L);
|
|
AnalyzedBlockCount += AR.BlockCount;
|
|
}
|
|
|
|
return PreservedAnalyses::all();
|
|
}
|
|
|
|
static StringRef name() { return "TestLoopPass"; }
|
|
};
|
|
|
|
// A test loop pass that invalidates the analysis for loops with the given name.
|
|
class TestLoopInvalidatingPass {
|
|
StringRef Name;
|
|
|
|
public:
|
|
TestLoopInvalidatingPass(StringRef LoopName) : Name(LoopName) {}
|
|
|
|
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM) {
|
|
return L.getName() == Name ? getLoopPassPreservedAnalyses()
|
|
: PreservedAnalyses::all();
|
|
}
|
|
|
|
static StringRef name() { return "TestLoopInvalidatingPass"; }
|
|
};
|
|
|
|
std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
|
|
SMDiagnostic Err;
|
|
return parseAssemblyString(IR, Err, C);
|
|
}
|
|
|
|
class LoopPassManagerTest : public ::testing::Test {
|
|
protected:
|
|
LLVMContext Context;
|
|
std::unique_ptr<Module> M;
|
|
|
|
public:
|
|
LoopPassManagerTest()
|
|
: M(parseIR(Context, "define void @f() {\n"
|
|
"entry:\n"
|
|
" br label %loop.0\n"
|
|
"loop.0:\n"
|
|
" br i1 undef, label %loop.0.0, label %end\n"
|
|
"loop.0.0:\n"
|
|
" br i1 undef, label %loop.0.0, label %loop.0.1\n"
|
|
"loop.0.1:\n"
|
|
" br i1 undef, label %loop.0.1, label %loop.0\n"
|
|
"end:\n"
|
|
" ret void\n"
|
|
"}\n"
|
|
"\n"
|
|
"define void @g() {\n"
|
|
"entry:\n"
|
|
" br label %loop.g.0\n"
|
|
"loop.g.0:\n"
|
|
" br i1 undef, label %loop.g.0, label %end\n"
|
|
"end:\n"
|
|
" ret void\n"
|
|
"}\n")) {}
|
|
};
|
|
|
|
#define EXPECT_N_ELEMENTS_EQ(N, EXPECTED, ACTUAL) \
|
|
do { \
|
|
EXPECT_EQ(N##UL, ACTUAL.size()); \
|
|
for (int I = 0; I < N; ++I) \
|
|
EXPECT_TRUE(EXPECTED[I] == ACTUAL[I]) << "Element " << I << " is " \
|
|
<< ACTUAL[I] << ". Expected " \
|
|
<< EXPECTED[I] << "."; \
|
|
} while (0)
|
|
|
|
TEST_F(LoopPassManagerTest, Basic) {
|
|
LoopAnalysisManager LAM(true);
|
|
int LoopAnalysisRuns = 0;
|
|
LAM.registerPass([&] { return TestLoopAnalysis(LoopAnalysisRuns); });
|
|
|
|
FunctionAnalysisManager FAM(true);
|
|
// We need DominatorTreeAnalysis for LoopAnalysis.
|
|
FAM.registerPass([&] { return DominatorTreeAnalysis(); });
|
|
FAM.registerPass([&] { return LoopAnalysis(); });
|
|
FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); });
|
|
LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
|
|
|
|
ModuleAnalysisManager MAM(true);
|
|
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
|
|
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
|
|
|
|
ModulePassManager MPM(true);
|
|
FunctionPassManager FPM(true);
|
|
|
|
// Visit all of the loops.
|
|
std::vector<StringRef> VisitedLoops1;
|
|
int AnalyzedBlockCount1 = 0;
|
|
{
|
|
LoopPassManager LPM;
|
|
LPM.addPass(TestLoopPass(VisitedLoops1, AnalyzedBlockCount1));
|
|
|
|
FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
|
|
}
|
|
|
|
// Only use cached analyses.
|
|
std::vector<StringRef> VisitedLoops2;
|
|
int AnalyzedBlockCount2 = 0;
|
|
{
|
|
LoopPassManager LPM;
|
|
LPM.addPass(TestLoopInvalidatingPass("loop.g.0"));
|
|
LPM.addPass(TestLoopPass(VisitedLoops2, AnalyzedBlockCount2,
|
|
/*OnlyUseCachedResults=*/true));
|
|
|
|
FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
|
|
}
|
|
|
|
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
|
|
MPM.run(*M, MAM);
|
|
|
|
StringRef ExpectedLoops[] = {"loop.0.0", "loop.0.1", "loop.0", "loop.g.0"};
|
|
|
|
// Validate the counters and order of loops visited.
|
|
// loop.0 has 3 blocks whereas loop.0.0, loop.0.1, and loop.g.0 each have 1.
|
|
EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops1);
|
|
EXPECT_EQ(6, AnalyzedBlockCount1);
|
|
|
|
EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops2);
|
|
// The block from loop.g.0 won't be counted, since it wasn't cached.
|
|
EXPECT_EQ(5, AnalyzedBlockCount2);
|
|
|
|
// The first LPM runs the loop analysis for all four loops, the second uses
|
|
// cached results for everything.
|
|
EXPECT_EQ(4, LoopAnalysisRuns);
|
|
}
|
|
}
|