mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
2ed363a464
from the old pass manager in the new one. I'm not trying to support (initially) the numerous options that are currently available to customize the pass pipeline. If we end up really wanting them, we can add them later, but I suspect many are no longer interesting. The simplicity of omitting them will help a lot as we sort out what the pipeline should look like in the new PM. I've also documented to the best of my ability *why* each pass or group of passes is used so that reading the pipeline is more helpful. In many cases I think we have some questionable choices of ordering and I've left FIXME comments in place so we know what to come back and revisit going forward. But for now, I've left it as similar to the current pipeline as I could. Lastly, I've had to comment out several places where passes are not ported to the new pass manager or where the loop pass infrastructure is not yet ready. I did at least fix a few bugs in the loop pass infrastructure uncovered by running the full pipeline, but I didn't want to go too far in this patch -- I'll come back and re-enable these as the infrastructure comes online. But I'd like to keep the comments in place because I don't want to lose track of which passes need to be enabled and where they go. One thing that seemed like a significant API improvement was to require that we don't build pipelines for O0. It seems to have no real benefit. I've also switched back to returning pass managers by value as at this API layer it feels much more natural to me for composition. But if others disagree, I'm happy to go back to an output parameter. I'm not 100% happy with the testing strategy currently, but it seems at least OK. I may come back and try to refactor or otherwise improve this in subsequent patches but I wanted to at least get a good starting point in place. Differential Revision: https://reviews.llvm.org/D28042 llvm-svn: 290325
210 lines
7.0 KiB
C++
210 lines
7.0 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 "llvm/Analysis/AliasAnalysis.h"
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
|
#include "llvm/Analysis/LoopPassManager.h"
|
|
#include "llvm/Analysis/ScalarEvolution.h"
|
|
#include "llvm/Analysis/TargetLibraryInfo.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"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
class TestLoopAnalysis : public AnalysisInfoMixin<TestLoopAnalysis> {
|
|
friend AnalysisInfoMixin<TestLoopAnalysis>;
|
|
static AnalysisKey Key;
|
|
|
|
int &Runs;
|
|
|
|
public:
|
|
struct Result {
|
|
Result(int Count) : BlockCount(Count) {}
|
|
int BlockCount;
|
|
};
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
AnalysisKey TestLoopAnalysis::Key;
|
|
|
|
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(); });
|
|
// We also allow loop passes to assume a set of other analyses and so need
|
|
// those.
|
|
FAM.registerPass([&] { return AAManager(); });
|
|
FAM.registerPass([&] { return TargetLibraryAnalysis(); });
|
|
FAM.registerPass([&] { return ScalarEvolutionAnalysis(); });
|
|
FAM.registerPass([&] { return AssumptionAnalysis(); });
|
|
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);
|
|
}
|
|
}
|