2016-02-23 18:02:02 +08:00
|
|
|
//===- CGSCCPassManagerTest.cpp -------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Analysis/CGSCCPassManager.h"
|
|
|
|
#include "llvm/Analysis/LazyCallGraph.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/IR/PassManager.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class TestModuleAnalysis {
|
|
|
|
public:
|
|
|
|
struct Result {
|
|
|
|
Result(int Count) : FunctionCount(Count) {}
|
|
|
|
int FunctionCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *ID() { return (void *)&PassID; }
|
|
|
|
static StringRef name() { return "TestModuleAnalysis"; }
|
|
|
|
|
|
|
|
TestModuleAnalysis(int &Runs) : Runs(Runs) {}
|
|
|
|
|
2016-03-11 19:05:24 +08:00
|
|
|
Result run(Module &M, ModuleAnalysisManager &AM) {
|
2016-02-23 18:02:02 +08:00
|
|
|
++Runs;
|
|
|
|
return Result(M.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static char PassID;
|
|
|
|
|
|
|
|
int &Runs;
|
|
|
|
};
|
|
|
|
|
|
|
|
char TestModuleAnalysis::PassID;
|
|
|
|
|
|
|
|
class TestSCCAnalysis {
|
|
|
|
public:
|
|
|
|
struct Result {
|
|
|
|
Result(int Count) : FunctionCount(Count) {}
|
|
|
|
int FunctionCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *ID() { return (void *)&PassID; }
|
|
|
|
static StringRef name() { return "TestSCCAnalysis"; }
|
|
|
|
|
|
|
|
TestSCCAnalysis(int &Runs) : Runs(Runs) {}
|
|
|
|
|
2016-03-11 19:05:24 +08:00
|
|
|
Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
|
2016-02-23 18:02:02 +08:00
|
|
|
++Runs;
|
|
|
|
return Result(C.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static char PassID;
|
|
|
|
|
|
|
|
int &Runs;
|
|
|
|
};
|
|
|
|
|
|
|
|
char TestSCCAnalysis::PassID;
|
|
|
|
|
|
|
|
class TestFunctionAnalysis {
|
|
|
|
public:
|
|
|
|
struct Result {
|
|
|
|
Result(int Count) : InstructionCount(Count) {}
|
|
|
|
int InstructionCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *ID() { return (void *)&PassID; }
|
|
|
|
static StringRef name() { return "TestFunctionAnalysis"; }
|
|
|
|
|
|
|
|
TestFunctionAnalysis(int &Runs) : Runs(Runs) {}
|
|
|
|
|
2016-03-11 19:05:24 +08:00
|
|
|
Result run(Function &F, FunctionAnalysisManager &AM) {
|
2016-02-23 18:02:02 +08:00
|
|
|
++Runs;
|
|
|
|
int Count = 0;
|
|
|
|
for (Instruction &I : instructions(F)) {
|
|
|
|
(void)I;
|
|
|
|
++Count;
|
|
|
|
}
|
|
|
|
return Result(Count);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static char PassID;
|
|
|
|
|
|
|
|
int &Runs;
|
|
|
|
};
|
|
|
|
|
|
|
|
char TestFunctionAnalysis::PassID;
|
|
|
|
|
2016-02-23 18:47:57 +08:00
|
|
|
class TestImmutableFunctionAnalysis {
|
|
|
|
public:
|
|
|
|
struct Result {
|
|
|
|
bool invalidate(Function &, const PreservedAnalyses &) { return false; }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *ID() { return (void *)&PassID; }
|
|
|
|
static StringRef name() { return "TestImmutableFunctionAnalysis"; }
|
|
|
|
|
|
|
|
TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {}
|
|
|
|
|
2016-03-11 19:05:24 +08:00
|
|
|
Result run(Function &F, FunctionAnalysisManager &AM) {
|
2016-02-23 18:47:57 +08:00
|
|
|
++Runs;
|
|
|
|
return Result();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static char PassID;
|
|
|
|
|
|
|
|
int &Runs;
|
|
|
|
};
|
|
|
|
|
|
|
|
char TestImmutableFunctionAnalysis::PassID;
|
|
|
|
|
2016-02-23 18:02:02 +08:00
|
|
|
struct TestModulePass {
|
|
|
|
TestModulePass(int &RunCount) : RunCount(RunCount) {}
|
|
|
|
|
2016-03-11 19:05:24 +08:00
|
|
|
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
|
2016-02-23 18:02:02 +08:00
|
|
|
++RunCount;
|
2016-03-11 19:05:24 +08:00
|
|
|
(void)AM.getResult<TestModuleAnalysis>(M);
|
2016-02-23 18:02:02 +08:00
|
|
|
return PreservedAnalyses::all();
|
|
|
|
}
|
|
|
|
|
|
|
|
static StringRef name() { return "TestModulePass"; }
|
|
|
|
|
|
|
|
int &RunCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TestSCCPass {
|
|
|
|
TestSCCPass(int &RunCount, int &AnalyzedInstrCount,
|
2016-06-17 15:15:29 +08:00
|
|
|
int &AnalyzedSCCFunctionCount, int &AnalyzedModuleFunctionCount,
|
|
|
|
bool OnlyUseCachedResults = false)
|
2016-02-23 18:02:02 +08:00
|
|
|
: RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
|
|
|
|
AnalyzedSCCFunctionCount(AnalyzedSCCFunctionCount),
|
|
|
|
AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount),
|
|
|
|
OnlyUseCachedResults(OnlyUseCachedResults) {}
|
|
|
|
|
2016-03-11 19:05:24 +08:00
|
|
|
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
|
2016-02-23 18:02:02 +08:00
|
|
|
++RunCount;
|
|
|
|
|
|
|
|
const ModuleAnalysisManager &MAM =
|
2016-03-11 19:05:24 +08:00
|
|
|
AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager();
|
2016-02-23 18:02:02 +08:00
|
|
|
FunctionAnalysisManager &FAM =
|
2016-03-11 19:05:24 +08:00
|
|
|
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
|
2016-02-23 18:02:02 +08:00
|
|
|
if (TestModuleAnalysis::Result *TMA =
|
|
|
|
MAM.getCachedResult<TestModuleAnalysis>(
|
|
|
|
*C.begin()->getFunction().getParent()))
|
|
|
|
AnalyzedModuleFunctionCount += TMA->FunctionCount;
|
|
|
|
|
|
|
|
if (OnlyUseCachedResults) {
|
|
|
|
// Hack to force the use of the cached interface.
|
2016-03-11 19:05:24 +08:00
|
|
|
if (TestSCCAnalysis::Result *AR = AM.getCachedResult<TestSCCAnalysis>(C))
|
2016-02-23 18:02:02 +08:00
|
|
|
AnalyzedSCCFunctionCount += AR->FunctionCount;
|
|
|
|
for (LazyCallGraph::Node &N : C)
|
|
|
|
if (TestFunctionAnalysis::Result *FAR =
|
|
|
|
FAM.getCachedResult<TestFunctionAnalysis>(N.getFunction()))
|
|
|
|
AnalyzedInstrCount += FAR->InstructionCount;
|
|
|
|
} else {
|
|
|
|
// Typical path just runs the analysis as needed.
|
2016-03-11 19:05:24 +08:00
|
|
|
TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C);
|
2016-02-23 18:02:02 +08:00
|
|
|
AnalyzedSCCFunctionCount += AR.FunctionCount;
|
|
|
|
for (LazyCallGraph::Node &N : C) {
|
|
|
|
TestFunctionAnalysis::Result &FAR =
|
|
|
|
FAM.getResult<TestFunctionAnalysis>(N.getFunction());
|
|
|
|
AnalyzedInstrCount += FAR.InstructionCount;
|
2016-02-23 18:47:57 +08:00
|
|
|
|
|
|
|
// Just ensure we get the immutable results.
|
|
|
|
(void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
|
2016-02-23 18:02:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
}
|
|
|
|
|
|
|
|
static StringRef name() { return "TestSCCPass"; }
|
|
|
|
|
|
|
|
int &RunCount;
|
|
|
|
int &AnalyzedInstrCount;
|
|
|
|
int &AnalyzedSCCFunctionCount;
|
|
|
|
int &AnalyzedModuleFunctionCount;
|
|
|
|
bool OnlyUseCachedResults;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TestFunctionPass {
|
|
|
|
TestFunctionPass(int &RunCount) : RunCount(RunCount) {}
|
|
|
|
|
2016-08-09 08:28:15 +08:00
|
|
|
PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
|
2016-02-23 18:02:02 +08:00
|
|
|
++RunCount;
|
|
|
|
return PreservedAnalyses::none();
|
|
|
|
}
|
|
|
|
|
|
|
|
static StringRef name() { return "TestFunctionPass"; }
|
|
|
|
|
|
|
|
int &RunCount;
|
|
|
|
};
|
|
|
|
|
2016-06-28 08:38:42 +08:00
|
|
|
std::unique_ptr<Module> parseIR(const char *IR) {
|
|
|
|
// We just use a static context here. This is never called from multiple
|
|
|
|
// threads so it is harmless no matter how it is implemented. We just need
|
|
|
|
// the context to outlive the module which it does.
|
|
|
|
static LLVMContext C;
|
2016-02-23 18:02:02 +08:00
|
|
|
SMDiagnostic Err;
|
|
|
|
return parseAssemblyString(IR, Err, C);
|
|
|
|
}
|
|
|
|
|
2016-06-28 08:38:42 +08:00
|
|
|
TEST(CGSCCPassManagerTest, Basic) {
|
|
|
|
auto M = parseIR("define void @f() {\n"
|
|
|
|
"entry:\n"
|
|
|
|
" call void @g()\n"
|
|
|
|
" call void @h1()\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n"
|
|
|
|
"define void @g() {\n"
|
|
|
|
"entry:\n"
|
|
|
|
" call void @g()\n"
|
|
|
|
" call void @x()\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n"
|
|
|
|
"define void @h1() {\n"
|
|
|
|
"entry:\n"
|
|
|
|
" call void @h2()\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n"
|
|
|
|
"define void @h2() {\n"
|
|
|
|
"entry:\n"
|
|
|
|
" call void @h3()\n"
|
|
|
|
" call void @x()\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n"
|
|
|
|
"define void @h3() {\n"
|
|
|
|
"entry:\n"
|
|
|
|
" call void @h1()\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n"
|
|
|
|
"define void @x() {\n"
|
|
|
|
"entry:\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n");
|
2016-02-23 18:02:02 +08:00
|
|
|
FunctionAnalysisManager FAM(/*DebugLogging*/ true);
|
|
|
|
int FunctionAnalysisRuns = 0;
|
|
|
|
FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
|
2016-02-23 18:47:57 +08:00
|
|
|
int ImmutableFunctionAnalysisRuns = 0;
|
|
|
|
FAM.registerPass([&] {
|
|
|
|
return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
|
|
|
|
});
|
2016-02-23 18:02:02 +08:00
|
|
|
|
|
|
|
CGSCCAnalysisManager CGAM(/*DebugLogging*/ true);
|
|
|
|
int SCCAnalysisRuns = 0;
|
|
|
|
CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
|
|
|
|
|
|
|
|
ModuleAnalysisManager MAM(/*DebugLogging*/ true);
|
|
|
|
int ModuleAnalysisRuns = 0;
|
|
|
|
MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
|
|
|
|
MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
|
|
|
|
|
|
|
|
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
|
|
|
|
MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
|
|
|
|
CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
|
|
|
|
CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
|
|
|
|
FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
|
|
|
|
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
|
|
|
|
|
|
|
|
ModulePassManager MPM(/*DebugLogging*/ true);
|
|
|
|
int ModulePassRunCount1 = 0;
|
|
|
|
MPM.addPass(TestModulePass(ModulePassRunCount1));
|
|
|
|
|
|
|
|
CGSCCPassManager CGPM1(/*DebugLogging*/ true);
|
|
|
|
int SCCPassRunCount1 = 0;
|
|
|
|
int AnalyzedInstrCount1 = 0;
|
|
|
|
int AnalyzedSCCFunctionCount1 = 0;
|
|
|
|
int AnalyzedModuleFunctionCount1 = 0;
|
|
|
|
CGPM1.addPass(TestSCCPass(SCCPassRunCount1, AnalyzedInstrCount1,
|
|
|
|
AnalyzedSCCFunctionCount1,
|
|
|
|
AnalyzedModuleFunctionCount1));
|
|
|
|
|
|
|
|
FunctionPassManager FPM1(/*DebugLogging*/ true);
|
|
|
|
int FunctionPassRunCount1 = 0;
|
|
|
|
FPM1.addPass(TestFunctionPass(FunctionPassRunCount1));
|
|
|
|
CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
|
|
|
|
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
|
|
|
|
|
2016-03-11 19:05:24 +08:00
|
|
|
MPM.run(*M, MAM);
|
2016-02-23 18:02:02 +08:00
|
|
|
|
|
|
|
EXPECT_EQ(1, ModulePassRunCount1);
|
|
|
|
|
|
|
|
EXPECT_EQ(1, ModuleAnalysisRuns);
|
|
|
|
EXPECT_EQ(4, SCCAnalysisRuns);
|
|
|
|
EXPECT_EQ(6, FunctionAnalysisRuns);
|
2016-02-23 18:47:57 +08:00
|
|
|
EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
|
2016-02-23 18:02:02 +08:00
|
|
|
|
|
|
|
EXPECT_EQ(4, SCCPassRunCount1);
|
|
|
|
EXPECT_EQ(14, AnalyzedInstrCount1);
|
|
|
|
EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
|
|
|
|
EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|