174319922SChandler Carruth //===- CGSCCPassManagerTest.cpp -------------------------------------------===//
274319922SChandler Carruth //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
674319922SChandler Carruth //
774319922SChandler Carruth //===----------------------------------------------------------------------===//
874319922SChandler Carruth
974319922SChandler Carruth #include "llvm/Analysis/CGSCCPassManager.h"
1074319922SChandler Carruth #include "llvm/Analysis/LazyCallGraph.h"
11f59a8387SChandler Carruth #include "llvm/Analysis/TargetLibraryInfo.h"
1274319922SChandler Carruth #include "llvm/AsmParser/Parser.h"
13*823b32fbSBill Wendling #include "llvm/IR/Constants.h"
1474319922SChandler Carruth #include "llvm/IR/Function.h"
1574319922SChandler Carruth #include "llvm/IR/InstIterator.h"
168e140869SCraig Topper #include "llvm/IR/Instructions.h"
1774319922SChandler Carruth #include "llvm/IR/LLVMContext.h"
1874319922SChandler Carruth #include "llvm/IR/Module.h"
1974319922SChandler Carruth #include "llvm/IR/PassManager.h"
204c8c6368SArthur Eubanks #include "llvm/IR/Verifier.h"
2174319922SChandler Carruth #include "llvm/Support/SourceMgr.h"
2272277ecdSJohannes Doerfert #include "llvm/Transforms/Utils/CallGraphUpdater.h"
2374319922SChandler Carruth #include "gtest/gtest.h"
2474319922SChandler Carruth
2574319922SChandler Carruth using namespace llvm;
2674319922SChandler Carruth
2774319922SChandler Carruth namespace {
2874319922SChandler Carruth
29dab4eae2SChandler Carruth class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> {
3074319922SChandler Carruth public:
3174319922SChandler Carruth struct Result {
Result__anone177e1640111::TestModuleAnalysis::Result3274319922SChandler Carruth Result(int Count) : FunctionCount(Count) {}
3374319922SChandler Carruth int FunctionCount;
invalidate__anone177e1640111::TestModuleAnalysis::Result3454356b4bSAlina Sbirlea bool invalidate(Module &, const PreservedAnalyses &PA,
3554356b4bSAlina Sbirlea ModuleAnalysisManager::Invalidator &) {
3654356b4bSAlina Sbirlea // Check whether the analysis or all analyses on modules have been
3754356b4bSAlina Sbirlea // preserved.
3854356b4bSAlina Sbirlea auto PAC = PA.getChecker<TestModuleAnalysis>();
3954356b4bSAlina Sbirlea return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Module>>());
4054356b4bSAlina Sbirlea }
4174319922SChandler Carruth };
4274319922SChandler Carruth
TestModuleAnalysis(int & Runs)4374319922SChandler Carruth TestModuleAnalysis(int &Runs) : Runs(Runs) {}
4474319922SChandler Carruth
run(Module & M,ModuleAnalysisManager & AM)45b47f8010SChandler Carruth Result run(Module &M, ModuleAnalysisManager &AM) {
4674319922SChandler Carruth ++Runs;
4774319922SChandler Carruth return Result(M.size());
4874319922SChandler Carruth }
4974319922SChandler Carruth
5074319922SChandler Carruth private:
51dab4eae2SChandler Carruth friend AnalysisInfoMixin<TestModuleAnalysis>;
52dab4eae2SChandler Carruth static AnalysisKey Key;
5374319922SChandler Carruth
5474319922SChandler Carruth int &Runs;
5574319922SChandler Carruth };
5674319922SChandler Carruth
57dab4eae2SChandler Carruth AnalysisKey TestModuleAnalysis::Key;
5874319922SChandler Carruth
59dab4eae2SChandler Carruth class TestSCCAnalysis : public AnalysisInfoMixin<TestSCCAnalysis> {
6074319922SChandler Carruth public:
6174319922SChandler Carruth struct Result {
Result__anone177e1640111::TestSCCAnalysis::Result6274319922SChandler Carruth Result(int Count) : FunctionCount(Count) {}
6374319922SChandler Carruth int FunctionCount;
invalidate__anone177e1640111::TestSCCAnalysis::Result6454356b4bSAlina Sbirlea bool invalidate(LazyCallGraph::SCC &, const PreservedAnalyses &PA,
6554356b4bSAlina Sbirlea CGSCCAnalysisManager::Invalidator &) {
6654356b4bSAlina Sbirlea // Check whether the analysis or all analyses on SCCs have been
6754356b4bSAlina Sbirlea // preserved.
6854356b4bSAlina Sbirlea auto PAC = PA.getChecker<TestSCCAnalysis>();
6954356b4bSAlina Sbirlea return !(PAC.preserved() ||
7054356b4bSAlina Sbirlea PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>());
7154356b4bSAlina Sbirlea }
7274319922SChandler Carruth };
7374319922SChandler Carruth
TestSCCAnalysis(int & Runs)7474319922SChandler Carruth TestSCCAnalysis(int &Runs) : Runs(Runs) {}
7574319922SChandler Carruth
run(LazyCallGraph::SCC & C,CGSCCAnalysisManager & AM,LazyCallGraph &)7688823468SChandler Carruth Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &) {
7774319922SChandler Carruth ++Runs;
7874319922SChandler Carruth return Result(C.size());
7974319922SChandler Carruth }
8074319922SChandler Carruth
8174319922SChandler Carruth private:
82dab4eae2SChandler Carruth friend AnalysisInfoMixin<TestSCCAnalysis>;
83dab4eae2SChandler Carruth static AnalysisKey Key;
8474319922SChandler Carruth
8574319922SChandler Carruth int &Runs;
8674319922SChandler Carruth };
8774319922SChandler Carruth
88dab4eae2SChandler Carruth AnalysisKey TestSCCAnalysis::Key;
8974319922SChandler Carruth
90dab4eae2SChandler Carruth class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> {
9174319922SChandler Carruth public:
9274319922SChandler Carruth struct Result {
Result__anone177e1640111::TestFunctionAnalysis::Result9374319922SChandler Carruth Result(int Count) : InstructionCount(Count) {}
9474319922SChandler Carruth int InstructionCount;
invalidate__anone177e1640111::TestFunctionAnalysis::Result9554356b4bSAlina Sbirlea bool invalidate(Function &, const PreservedAnalyses &PA,
9654356b4bSAlina Sbirlea FunctionAnalysisManager::Invalidator &) {
9754356b4bSAlina Sbirlea // Check whether the analysis or all analyses on functions have been
9854356b4bSAlina Sbirlea // preserved.
9954356b4bSAlina Sbirlea auto PAC = PA.getChecker<TestFunctionAnalysis>();
10054356b4bSAlina Sbirlea return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>());
10154356b4bSAlina Sbirlea }
10274319922SChandler Carruth };
10374319922SChandler Carruth
TestFunctionAnalysis(int & Runs)10474319922SChandler Carruth TestFunctionAnalysis(int &Runs) : Runs(Runs) {}
10574319922SChandler Carruth
run(Function & F,FunctionAnalysisManager & AM)106b47f8010SChandler Carruth Result run(Function &F, FunctionAnalysisManager &AM) {
10774319922SChandler Carruth ++Runs;
10874319922SChandler Carruth int Count = 0;
10974319922SChandler Carruth for (Instruction &I : instructions(F)) {
11074319922SChandler Carruth (void)I;
11174319922SChandler Carruth ++Count;
11274319922SChandler Carruth }
11374319922SChandler Carruth return Result(Count);
11474319922SChandler Carruth }
11574319922SChandler Carruth
11674319922SChandler Carruth private:
117dab4eae2SChandler Carruth friend AnalysisInfoMixin<TestFunctionAnalysis>;
118dab4eae2SChandler Carruth static AnalysisKey Key;
11974319922SChandler Carruth
12074319922SChandler Carruth int &Runs;
12174319922SChandler Carruth };
12274319922SChandler Carruth
123dab4eae2SChandler Carruth AnalysisKey TestFunctionAnalysis::Key;
12474319922SChandler Carruth
125dab4eae2SChandler Carruth class TestImmutableFunctionAnalysis
126dab4eae2SChandler Carruth : public AnalysisInfoMixin<TestImmutableFunctionAnalysis> {
127c5d211efSChandler Carruth public:
128c5d211efSChandler Carruth struct Result {
invalidate__anone177e1640111::TestImmutableFunctionAnalysis::Result1293ab2a5a8SChandler Carruth bool invalidate(Function &, const PreservedAnalyses &,
1303ab2a5a8SChandler Carruth FunctionAnalysisManager::Invalidator &) {
1313ab2a5a8SChandler Carruth return false;
1323ab2a5a8SChandler Carruth }
133c5d211efSChandler Carruth };
134c5d211efSChandler Carruth
TestImmutableFunctionAnalysis(int & Runs)135c5d211efSChandler Carruth TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {}
136c5d211efSChandler Carruth
run(Function & F,FunctionAnalysisManager & AM)137b47f8010SChandler Carruth Result run(Function &F, FunctionAnalysisManager &AM) {
138c5d211efSChandler Carruth ++Runs;
139c5d211efSChandler Carruth return Result();
140c5d211efSChandler Carruth }
141c5d211efSChandler Carruth
142c5d211efSChandler Carruth private:
143dab4eae2SChandler Carruth friend AnalysisInfoMixin<TestImmutableFunctionAnalysis>;
144dab4eae2SChandler Carruth static AnalysisKey Key;
145c5d211efSChandler Carruth
146c5d211efSChandler Carruth int &Runs;
147c5d211efSChandler Carruth };
148c5d211efSChandler Carruth
149dab4eae2SChandler Carruth AnalysisKey TestImmutableFunctionAnalysis::Key;
150c5d211efSChandler Carruth
1516b981647SChandler Carruth struct LambdaModulePass : public PassInfoMixin<LambdaModulePass> {
1526b981647SChandler Carruth template <typename T>
LambdaModulePass__anone177e1640111::LambdaModulePass1536b981647SChandler Carruth LambdaModulePass(T &&Arg) : Func(std::forward<T>(Arg)) {}
1546b981647SChandler Carruth
run__anone177e1640111::LambdaModulePass1556b981647SChandler Carruth PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) {
1566b981647SChandler Carruth return Func(F, AM);
1576b981647SChandler Carruth }
1586b981647SChandler Carruth
1596b981647SChandler Carruth std::function<PreservedAnalyses(Module &, ModuleAnalysisManager &)> Func;
1606b981647SChandler Carruth };
1616b981647SChandler Carruth
162d4e80a96SChandler Carruth struct LambdaSCCPass : public PassInfoMixin<LambdaSCCPass> {
LambdaSCCPass__anone177e1640111::LambdaSCCPass163d4e80a96SChandler Carruth template <typename T> LambdaSCCPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
16474319922SChandler Carruth
run__anone177e1640111::LambdaSCCPass16588823468SChandler Carruth PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
16688823468SChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &UR) {
167d4e80a96SChandler Carruth return Func(C, AM, CG, UR);
16874319922SChandler Carruth }
16974319922SChandler Carruth
170d4e80a96SChandler Carruth std::function<PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
171d4e80a96SChandler Carruth LazyCallGraph &, CGSCCUpdateResult &)>
172d4e80a96SChandler Carruth Func;
17374319922SChandler Carruth };
17474319922SChandler Carruth
175d4e80a96SChandler Carruth struct LambdaFunctionPass : public PassInfoMixin<LambdaFunctionPass> {
1766b981647SChandler Carruth template <typename T>
LambdaFunctionPass__anone177e1640111::LambdaFunctionPass1776b981647SChandler Carruth LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
17874319922SChandler Carruth
run__anone177e1640111::LambdaFunctionPass179d4e80a96SChandler Carruth PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
180d4e80a96SChandler Carruth return Func(F, AM);
18174319922SChandler Carruth }
18274319922SChandler Carruth
183d4e80a96SChandler Carruth std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)> Func;
18474319922SChandler Carruth };
18574319922SChandler Carruth
parseIR(const char * IR)1866c138ce3SChandler Carruth std::unique_ptr<Module> parseIR(const char *IR) {
1876c138ce3SChandler Carruth // We just use a static context here. This is never called from multiple
1886c138ce3SChandler Carruth // threads so it is harmless no matter how it is implemented. We just need
1896c138ce3SChandler Carruth // the context to outlive the module which it does.
1906c138ce3SChandler Carruth static LLVMContext C;
19174319922SChandler Carruth SMDiagnostic Err;
19274319922SChandler Carruth return parseAssemblyString(IR, Err, C);
19374319922SChandler Carruth }
19474319922SChandler Carruth
1954f83742aSChandler Carruth class CGSCCPassManagerTest : public ::testing::Test {
1964f83742aSChandler Carruth protected:
1974f83742aSChandler Carruth LLVMContext Context;
198dc288a89SChandler Carruth FunctionAnalysisManager FAM;
199dc288a89SChandler Carruth CGSCCAnalysisManager CGAM;
200dc288a89SChandler Carruth ModuleAnalysisManager MAM;
201dc288a89SChandler Carruth
2024f83742aSChandler Carruth std::unique_ptr<Module> M;
2034f83742aSChandler Carruth
2044f83742aSChandler Carruth public:
CGSCCPassManagerTest()2054f83742aSChandler Carruth CGSCCPassManagerTest()
2066f713100SArthur Eubanks : FAM(), CGAM(), MAM(),
2074cf2c898SChandler Carruth M(parseIR(
2084cf2c898SChandler Carruth // Define a module with the following call graph, where calls go
2094cf2c898SChandler Carruth // out the bottom of nodes and enter the top:
2104cf2c898SChandler Carruth //
2114cf2c898SChandler Carruth // f
2124cf2c898SChandler Carruth // |\ _
2134cf2c898SChandler Carruth // | \ / |
2144cf2c898SChandler Carruth // g h1 |
2154cf2c898SChandler Carruth // | | |
2164cf2c898SChandler Carruth // | h2 |
2174cf2c898SChandler Carruth // | | |
2184cf2c898SChandler Carruth // | h3 |
2194cf2c898SChandler Carruth // | / \_/
2204cf2c898SChandler Carruth // |/
2214cf2c898SChandler Carruth // x
2224cf2c898SChandler Carruth //
223491dd271SFangrui Song "define void @x() {\n"
22474319922SChandler Carruth "entry:\n"
225491dd271SFangrui Song " ret void\n"
226491dd271SFangrui Song "}\n"
227491dd271SFangrui Song "define void @h3() {\n"
228491dd271SFangrui Song "entry:\n"
22974319922SChandler Carruth " call void @h1()\n"
23074319922SChandler Carruth " ret void\n"
23174319922SChandler Carruth "}\n"
23274319922SChandler Carruth "define void @h2() {\n"
23374319922SChandler Carruth "entry:\n"
23474319922SChandler Carruth " call void @h3()\n"
23574319922SChandler Carruth " call void @x()\n"
23674319922SChandler Carruth " ret void\n"
23774319922SChandler Carruth "}\n"
238491dd271SFangrui Song "define void @h1() {\n"
23974319922SChandler Carruth "entry:\n"
240491dd271SFangrui Song " call void @h2()\n"
24174319922SChandler Carruth " ret void\n"
24274319922SChandler Carruth "}\n"
243491dd271SFangrui Song "define void @g() {\n"
24474319922SChandler Carruth "entry:\n"
245491dd271SFangrui Song " call void @g()\n"
246491dd271SFangrui Song " call void @x()\n"
247491dd271SFangrui Song " ret void\n"
248491dd271SFangrui Song "}\n"
249491dd271SFangrui Song "define void @f() {\n"
250491dd271SFangrui Song "entry:\n"
251491dd271SFangrui Song " call void @g()\n"
252491dd271SFangrui Song " call void @h1()\n"
25374319922SChandler Carruth " ret void\n"
254dc288a89SChandler Carruth "}\n")) {
2559c27b59cSTeresa Johnson FAM.registerPass([&] { return TargetLibraryAnalysis(); });
256dc288a89SChandler Carruth MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
257dc288a89SChandler Carruth MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
258ee8d31c4SFedor Sergeev
259ee8d31c4SFedor Sergeev // Register required pass instrumentation analysis.
260ee8d31c4SFedor Sergeev MAM.registerPass([&] { return PassInstrumentationAnalysis(); });
261ee8d31c4SFedor Sergeev CGAM.registerPass([&] { return PassInstrumentationAnalysis(); });
262ee8d31c4SFedor Sergeev FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
263ee8d31c4SFedor Sergeev
264ee8d31c4SFedor Sergeev // Cross-register proxies.
265dc288a89SChandler Carruth MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
2666b981647SChandler Carruth CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(); });
267dc288a89SChandler Carruth CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
268dc288a89SChandler Carruth FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
269dc288a89SChandler Carruth FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
270dc288a89SChandler Carruth }
2714f83742aSChandler Carruth };
2724f83742aSChandler Carruth
TEST_F(CGSCCPassManagerTest,Basic)2734f83742aSChandler Carruth TEST_F(CGSCCPassManagerTest, Basic) {
27474319922SChandler Carruth int FunctionAnalysisRuns = 0;
27574319922SChandler Carruth FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
276c5d211efSChandler Carruth int ImmutableFunctionAnalysisRuns = 0;
277c5d211efSChandler Carruth FAM.registerPass([&] {
278c5d211efSChandler Carruth return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
279c5d211efSChandler Carruth });
28074319922SChandler Carruth
28174319922SChandler Carruth int SCCAnalysisRuns = 0;
28274319922SChandler Carruth CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
28374319922SChandler Carruth
28474319922SChandler Carruth int ModuleAnalysisRuns = 0;
28574319922SChandler Carruth MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
28674319922SChandler Carruth
28734a8a437SArthur Eubanks ModulePassManager MPM;
288d4e80a96SChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
28974319922SChandler Carruth
29034a8a437SArthur Eubanks CGSCCPassManager CGPM1;
29134a8a437SArthur Eubanks FunctionPassManager FPM1;
2926b981647SChandler Carruth int FunctionPassRunCount1 = 0;
2936b981647SChandler Carruth FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
2946b981647SChandler Carruth ++FunctionPassRunCount1;
2956b981647SChandler Carruth return PreservedAnalyses::none();
2966b981647SChandler Carruth }));
2976b981647SChandler Carruth CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
2986b981647SChandler Carruth
29974319922SChandler Carruth int SCCPassRunCount1 = 0;
30074319922SChandler Carruth int AnalyzedInstrCount1 = 0;
30174319922SChandler Carruth int AnalyzedSCCFunctionCount1 = 0;
30274319922SChandler Carruth int AnalyzedModuleFunctionCount1 = 0;
303d4e80a96SChandler Carruth CGPM1.addPass(
304d4e80a96SChandler Carruth LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
305d4e80a96SChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &UR) {
306d4e80a96SChandler Carruth ++SCCPassRunCount1;
307d4e80a96SChandler Carruth
308bd541b21SAlina Sbirlea // Note: The proper way to get to a module pass from a CGSCC pass is
309bd541b21SAlina Sbirlea // through the ModuleAnalysisManagerCGSCCProxy:
310bd541b21SAlina Sbirlea // ```
311bd541b21SAlina Sbirlea // const auto &MAMProxy =
312bd541b21SAlina Sbirlea // AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG);
313bd541b21SAlina Sbirlea // ```
314bd541b21SAlina Sbirlea // However getting a stateful analysis is incorrect usage, and the call
315bd541b21SAlina Sbirlea // to getCachedResult below asserts:
316bd541b21SAlina Sbirlea // ```
317bd541b21SAlina Sbirlea // if (TestModuleAnalysis::Result *TMA =
318bd541b21SAlina Sbirlea // MAMProxy.getCachedResult<TestModuleAnalysis>(
319bd541b21SAlina Sbirlea // *C.begin()->getFunction().getParent()))
320bd541b21SAlina Sbirlea // AnalyzedModuleFunctionCount1 += TMA->FunctionCount;
321bd541b21SAlina Sbirlea // ```
322bd541b21SAlina Sbirlea // For the purposes of this unittest, use the above MAM directly.
323d4e80a96SChandler Carruth if (TestModuleAnalysis::Result *TMA =
324d4e80a96SChandler Carruth MAM.getCachedResult<TestModuleAnalysis>(
325d4e80a96SChandler Carruth *C.begin()->getFunction().getParent()))
326d4e80a96SChandler Carruth AnalyzedModuleFunctionCount1 += TMA->FunctionCount;
327d4e80a96SChandler Carruth
328bd541b21SAlina Sbirlea FunctionAnalysisManager &FAM =
329bd541b21SAlina Sbirlea AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
330d4e80a96SChandler Carruth TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C, CG);
331d4e80a96SChandler Carruth AnalyzedSCCFunctionCount1 += AR.FunctionCount;
332d4e80a96SChandler Carruth for (LazyCallGraph::Node &N : C) {
333d4e80a96SChandler Carruth TestFunctionAnalysis::Result &FAR =
334d4e80a96SChandler Carruth FAM.getResult<TestFunctionAnalysis>(N.getFunction());
335d4e80a96SChandler Carruth AnalyzedInstrCount1 += FAR.InstructionCount;
336d4e80a96SChandler Carruth
337d4e80a96SChandler Carruth // Just ensure we get the immutable results.
338d4e80a96SChandler Carruth (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
339d4e80a96SChandler Carruth }
340d4e80a96SChandler Carruth
341d4e80a96SChandler Carruth return PreservedAnalyses::all();
342d4e80a96SChandler Carruth }));
34374319922SChandler Carruth
34434a8a437SArthur Eubanks FunctionPassManager FPM2;
3456b981647SChandler Carruth int FunctionPassRunCount2 = 0;
3466b981647SChandler Carruth FPM2.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
3476b981647SChandler Carruth ++FunctionPassRunCount2;
3486b981647SChandler Carruth return PreservedAnalyses::none();
349d4e80a96SChandler Carruth }));
3506b981647SChandler Carruth CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
3516b981647SChandler Carruth
35274319922SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
35374319922SChandler Carruth
35434a8a437SArthur Eubanks FunctionPassManager FPM3;
3556b981647SChandler Carruth int FunctionPassRunCount3 = 0;
3566b981647SChandler Carruth FPM3.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
3576b981647SChandler Carruth ++FunctionPassRunCount3;
3586b981647SChandler Carruth return PreservedAnalyses::none();
3596b981647SChandler Carruth }));
3606b981647SChandler Carruth MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM3)));
3616b981647SChandler Carruth
362b47f8010SChandler Carruth MPM.run(*M, MAM);
36374319922SChandler Carruth
3646b981647SChandler Carruth EXPECT_EQ(4, SCCPassRunCount1);
3656b981647SChandler Carruth EXPECT_EQ(6, FunctionPassRunCount1);
3666b981647SChandler Carruth EXPECT_EQ(6, FunctionPassRunCount2);
3676b981647SChandler Carruth EXPECT_EQ(6, FunctionPassRunCount3);
3686b981647SChandler Carruth
36974319922SChandler Carruth EXPECT_EQ(1, ModuleAnalysisRuns);
37074319922SChandler Carruth EXPECT_EQ(4, SCCAnalysisRuns);
37174319922SChandler Carruth EXPECT_EQ(6, FunctionAnalysisRuns);
372c5d211efSChandler Carruth EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
37374319922SChandler Carruth
37474319922SChandler Carruth EXPECT_EQ(14, AnalyzedInstrCount1);
37574319922SChandler Carruth EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
37674319922SChandler Carruth EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
37774319922SChandler Carruth }
37874319922SChandler Carruth
379b52b573dSChandler Carruth // Test that an SCC pass which fails to preserve a module analysis does in fact
380b52b573dSChandler Carruth // invalidate that module analysis.
TEST_F(CGSCCPassManagerTest,TestSCCPassInvalidatesModuleAnalysis)381b52b573dSChandler Carruth TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesModuleAnalysis) {
382b52b573dSChandler Carruth int ModuleAnalysisRuns = 0;
383b52b573dSChandler Carruth MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
384b52b573dSChandler Carruth
38534a8a437SArthur Eubanks ModulePassManager MPM;
386b52b573dSChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
387b52b573dSChandler Carruth
388b52b573dSChandler Carruth // The first CGSCC run we preserve everything and make sure that works and
389b52b573dSChandler Carruth // the module analysis is available in the second CGSCC run from the one
390b52b573dSChandler Carruth // required module pass above.
39134a8a437SArthur Eubanks CGSCCPassManager CGPM1;
392b52b573dSChandler Carruth int CountFoundModuleAnalysis1 = 0;
393bd541b21SAlina Sbirlea CGPM1.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C,
394bd541b21SAlina Sbirlea CGSCCAnalysisManager &AM, LazyCallGraph &CG,
395bd541b21SAlina Sbirlea CGSCCUpdateResult &UR) {
396bd541b21SAlina Sbirlea const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG);
397bd541b21SAlina Sbirlea if (MAMProxy.cachedResultExists<TestModuleAnalysis>(
398bd541b21SAlina Sbirlea *C.begin()->getFunction().getParent()))
399b52b573dSChandler Carruth ++CountFoundModuleAnalysis1;
400b52b573dSChandler Carruth
401b52b573dSChandler Carruth return PreservedAnalyses::all();
402b52b573dSChandler Carruth }));
403b52b573dSChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
404b52b573dSChandler Carruth
405b52b573dSChandler Carruth // The second CGSCC run checks that the module analysis got preserved the
406b52b573dSChandler Carruth // previous time and in one SCC fails to preserve it.
40734a8a437SArthur Eubanks CGSCCPassManager CGPM2;
408b52b573dSChandler Carruth int CountFoundModuleAnalysis2 = 0;
409b52b573dSChandler Carruth CGPM2.addPass(
410b52b573dSChandler Carruth LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
411b52b573dSChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &UR) {
412bd541b21SAlina Sbirlea const auto &MAMProxy =
413bd541b21SAlina Sbirlea AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG);
414bd541b21SAlina Sbirlea if (MAMProxy.cachedResultExists<TestModuleAnalysis>(
415bd541b21SAlina Sbirlea *C.begin()->getFunction().getParent()))
416b52b573dSChandler Carruth ++CountFoundModuleAnalysis2;
417b52b573dSChandler Carruth
418b52b573dSChandler Carruth // Only fail to preserve analyses on one SCC and make sure that gets
419b52b573dSChandler Carruth // propagated.
420b52b573dSChandler Carruth return C.getName() == "(g)" ? PreservedAnalyses::none()
421b52b573dSChandler Carruth : PreservedAnalyses::all();
422b52b573dSChandler Carruth }));
423b52b573dSChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
424b52b573dSChandler Carruth
425b52b573dSChandler Carruth // The third CGSCC run should fail to find a cached module analysis as it
426b52b573dSChandler Carruth // should have been invalidated by the above CGSCC run.
42734a8a437SArthur Eubanks CGSCCPassManager CGPM3;
428b52b573dSChandler Carruth int CountFoundModuleAnalysis3 = 0;
429bd541b21SAlina Sbirlea CGPM3.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C,
430bd541b21SAlina Sbirlea CGSCCAnalysisManager &AM, LazyCallGraph &CG,
431bd541b21SAlina Sbirlea CGSCCUpdateResult &UR) {
432bd541b21SAlina Sbirlea const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG);
433bd541b21SAlina Sbirlea if (MAMProxy.cachedResultExists<TestModuleAnalysis>(
434bd541b21SAlina Sbirlea *C.begin()->getFunction().getParent()))
435b52b573dSChandler Carruth ++CountFoundModuleAnalysis3;
436b52b573dSChandler Carruth
437b52b573dSChandler Carruth return PreservedAnalyses::none();
438b52b573dSChandler Carruth }));
439b52b573dSChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3)));
440b52b573dSChandler Carruth
441b52b573dSChandler Carruth MPM.run(*M, MAM);
442b52b573dSChandler Carruth
443b52b573dSChandler Carruth EXPECT_EQ(1, ModuleAnalysisRuns);
444b52b573dSChandler Carruth EXPECT_EQ(4, CountFoundModuleAnalysis1);
445b52b573dSChandler Carruth EXPECT_EQ(4, CountFoundModuleAnalysis2);
446b52b573dSChandler Carruth EXPECT_EQ(0, CountFoundModuleAnalysis3);
447b52b573dSChandler Carruth }
448b52b573dSChandler Carruth
449e35f84a2SChandler Carruth // Similar to the above, but test that this works for function passes embedded
450e35f84a2SChandler Carruth // *within* a CGSCC layer.
TEST_F(CGSCCPassManagerTest,TestFunctionPassInsideCGSCCInvalidatesModuleAnalysis)451e35f84a2SChandler Carruth TEST_F(CGSCCPassManagerTest, TestFunctionPassInsideCGSCCInvalidatesModuleAnalysis) {
452e35f84a2SChandler Carruth int ModuleAnalysisRuns = 0;
453e35f84a2SChandler Carruth MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
454e35f84a2SChandler Carruth
45534a8a437SArthur Eubanks ModulePassManager MPM;
456e35f84a2SChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
457e35f84a2SChandler Carruth
458e35f84a2SChandler Carruth // The first run we preserve everything and make sure that works and the
459e35f84a2SChandler Carruth // module analysis is available in the second run from the one required
460e35f84a2SChandler Carruth // module pass above.
46134a8a437SArthur Eubanks FunctionPassManager FPM1;
462e35f84a2SChandler Carruth // Start true and mark false if we ever failed to find a module analysis
463e35f84a2SChandler Carruth // because we expect this to succeed for each SCC.
464e35f84a2SChandler Carruth bool FoundModuleAnalysis1 = true;
465bd541b21SAlina Sbirlea FPM1.addPass(LambdaFunctionPass([&](Function &F,
466bd541b21SAlina Sbirlea FunctionAnalysisManager &AM) {
467bd541b21SAlina Sbirlea const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
468bd541b21SAlina Sbirlea if (!MAMProxy.cachedResultExists<TestModuleAnalysis>(*F.getParent()))
469e35f84a2SChandler Carruth FoundModuleAnalysis1 = false;
470e35f84a2SChandler Carruth
471e35f84a2SChandler Carruth return PreservedAnalyses::all();
472e35f84a2SChandler Carruth }));
47334a8a437SArthur Eubanks CGSCCPassManager CGPM1;
474e35f84a2SChandler Carruth CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
475e35f84a2SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
476e35f84a2SChandler Carruth
477e35f84a2SChandler Carruth // The second run checks that the module analysis got preserved the previous
478e35f84a2SChandler Carruth // time and in one function fails to preserve it.
47934a8a437SArthur Eubanks FunctionPassManager FPM2;
480e35f84a2SChandler Carruth // Again, start true and mark false if we ever failed to find a module analysis
481e35f84a2SChandler Carruth // because we expect this to succeed for each SCC.
482e35f84a2SChandler Carruth bool FoundModuleAnalysis2 = true;
483bd541b21SAlina Sbirlea FPM2.addPass(LambdaFunctionPass([&](Function &F,
484bd541b21SAlina Sbirlea FunctionAnalysisManager &AM) {
485bd541b21SAlina Sbirlea const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
486bd541b21SAlina Sbirlea if (!MAMProxy.cachedResultExists<TestModuleAnalysis>(*F.getParent()))
487e35f84a2SChandler Carruth FoundModuleAnalysis2 = false;
488e35f84a2SChandler Carruth
489e35f84a2SChandler Carruth // Only fail to preserve analyses on one SCC and make sure that gets
490e35f84a2SChandler Carruth // propagated.
491e35f84a2SChandler Carruth return F.getName() == "h2" ? PreservedAnalyses::none()
492e35f84a2SChandler Carruth : PreservedAnalyses::all();
493e35f84a2SChandler Carruth }));
49434a8a437SArthur Eubanks CGSCCPassManager CGPM2;
495e35f84a2SChandler Carruth CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
496e35f84a2SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
497e35f84a2SChandler Carruth
498e35f84a2SChandler Carruth // The third run should fail to find a cached module analysis as it should
499e35f84a2SChandler Carruth // have been invalidated by the above run.
50034a8a437SArthur Eubanks FunctionPassManager FPM3;
501e35f84a2SChandler Carruth // Start false and mark true if we ever *succeeded* to find a module
502e35f84a2SChandler Carruth // analysis, as we expect this to fail for every function.
503e35f84a2SChandler Carruth bool FoundModuleAnalysis3 = false;
504bd541b21SAlina Sbirlea FPM3.addPass(LambdaFunctionPass([&](Function &F,
505bd541b21SAlina Sbirlea FunctionAnalysisManager &AM) {
506bd541b21SAlina Sbirlea const auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
507bd541b21SAlina Sbirlea if (MAMProxy.cachedResultExists<TestModuleAnalysis>(*F.getParent()))
508e35f84a2SChandler Carruth FoundModuleAnalysis3 = true;
509e35f84a2SChandler Carruth
510e35f84a2SChandler Carruth return PreservedAnalyses::none();
511e35f84a2SChandler Carruth }));
51234a8a437SArthur Eubanks CGSCCPassManager CGPM3;
513e35f84a2SChandler Carruth CGPM3.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM3)));
514e35f84a2SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3)));
515e35f84a2SChandler Carruth
516e35f84a2SChandler Carruth MPM.run(*M, MAM);
517e35f84a2SChandler Carruth
518e35f84a2SChandler Carruth EXPECT_EQ(1, ModuleAnalysisRuns);
519e35f84a2SChandler Carruth EXPECT_TRUE(FoundModuleAnalysis1);
520e35f84a2SChandler Carruth EXPECT_TRUE(FoundModuleAnalysis2);
521e35f84a2SChandler Carruth EXPECT_FALSE(FoundModuleAnalysis3);
522e35f84a2SChandler Carruth }
523e35f84a2SChandler Carruth
5246b981647SChandler Carruth // Test that a Module pass which fails to preserve an SCC analysis in fact
5256b981647SChandler Carruth // invalidates that analysis.
TEST_F(CGSCCPassManagerTest,TestModulePassInvalidatesSCCAnalysis)5266b981647SChandler Carruth TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysis) {
5276b981647SChandler Carruth int SCCAnalysisRuns = 0;
5286b981647SChandler Carruth CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
5296b981647SChandler Carruth
53034a8a437SArthur Eubanks ModulePassManager MPM;
5316b981647SChandler Carruth
5326b981647SChandler Carruth // First force the analysis to be run.
53334a8a437SArthur Eubanks CGSCCPassManager CGPM1;
5346b981647SChandler Carruth CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
5356b981647SChandler Carruth CGSCCAnalysisManager, LazyCallGraph &,
5366b981647SChandler Carruth CGSCCUpdateResult &>());
5376b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
5386b981647SChandler Carruth
5396b981647SChandler Carruth // Now run a module pass that preserves the LazyCallGraph and the proxy but
5406b981647SChandler Carruth // not the SCC analysis.
5416b981647SChandler Carruth MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
5426b981647SChandler Carruth PreservedAnalyses PA;
5436b981647SChandler Carruth PA.preserve<LazyCallGraphAnalysis>();
5446b981647SChandler Carruth PA.preserve<CGSCCAnalysisManagerModuleProxy>();
5456b981647SChandler Carruth PA.preserve<FunctionAnalysisManagerModuleProxy>();
5466b981647SChandler Carruth return PA;
5476b981647SChandler Carruth }));
5486b981647SChandler Carruth
5496b981647SChandler Carruth // And now a second CGSCC run which requires the SCC analysis again. This
5506b981647SChandler Carruth // will trigger re-running it.
55134a8a437SArthur Eubanks CGSCCPassManager CGPM2;
5526b981647SChandler Carruth CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
5536b981647SChandler Carruth CGSCCAnalysisManager, LazyCallGraph &,
5546b981647SChandler Carruth CGSCCUpdateResult &>());
5556b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
5566b981647SChandler Carruth
5576b981647SChandler Carruth MPM.run(*M, MAM);
5586b981647SChandler Carruth // Two runs and four SCCs.
5596b981647SChandler Carruth EXPECT_EQ(2 * 4, SCCAnalysisRuns);
5606b981647SChandler Carruth }
5616b981647SChandler Carruth
5626b981647SChandler Carruth // Check that marking the SCC analysis preserved is sufficient to avoid
5636b981647SChandler Carruth // invaliadtion. This should only run the analysis once for each SCC.
TEST_F(CGSCCPassManagerTest,TestModulePassCanPreserveSCCAnalysis)5646b981647SChandler Carruth TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveSCCAnalysis) {
5656b981647SChandler Carruth int SCCAnalysisRuns = 0;
5666b981647SChandler Carruth CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
5676b981647SChandler Carruth
56834a8a437SArthur Eubanks ModulePassManager MPM;
5696b981647SChandler Carruth
5706b981647SChandler Carruth // First force the analysis to be run.
57134a8a437SArthur Eubanks CGSCCPassManager CGPM1;
5726b981647SChandler Carruth CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
5736b981647SChandler Carruth CGSCCAnalysisManager, LazyCallGraph &,
5746b981647SChandler Carruth CGSCCUpdateResult &>());
5756b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
5766b981647SChandler Carruth
5776b981647SChandler Carruth // Now run a module pass that preserves each of the necessary components
5786b981647SChandler Carruth // (but not everything).
5796b981647SChandler Carruth MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
5806b981647SChandler Carruth PreservedAnalyses PA;
5816b981647SChandler Carruth PA.preserve<LazyCallGraphAnalysis>();
5826b981647SChandler Carruth PA.preserve<CGSCCAnalysisManagerModuleProxy>();
5836b981647SChandler Carruth PA.preserve<FunctionAnalysisManagerModuleProxy>();
5846b981647SChandler Carruth PA.preserve<TestSCCAnalysis>();
5856b981647SChandler Carruth return PA;
5866b981647SChandler Carruth }));
5876b981647SChandler Carruth
5886b981647SChandler Carruth // And now a second CGSCC run which requires the SCC analysis again but find
5896b981647SChandler Carruth // it in the cache.
59034a8a437SArthur Eubanks CGSCCPassManager CGPM2;
5916b981647SChandler Carruth CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
5926b981647SChandler Carruth CGSCCAnalysisManager, LazyCallGraph &,
5936b981647SChandler Carruth CGSCCUpdateResult &>());
5946b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
5956b981647SChandler Carruth
5966b981647SChandler Carruth MPM.run(*M, MAM);
5976b981647SChandler Carruth // Four SCCs
5986b981647SChandler Carruth EXPECT_EQ(4, SCCAnalysisRuns);
5996b981647SChandler Carruth }
6006b981647SChandler Carruth
6016b981647SChandler Carruth // Check that even when the analysis is preserved, if the SCC information isn't
6026b981647SChandler Carruth // we still nuke things because the SCC keys could change.
TEST_F(CGSCCPassManagerTest,TestModulePassInvalidatesSCCAnalysisOnCGChange)6036b981647SChandler Carruth TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysisOnCGChange) {
6046b981647SChandler Carruth int SCCAnalysisRuns = 0;
6056b981647SChandler Carruth CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
6066b981647SChandler Carruth
60734a8a437SArthur Eubanks ModulePassManager MPM;
6086b981647SChandler Carruth
6096b981647SChandler Carruth // First force the analysis to be run.
61034a8a437SArthur Eubanks CGSCCPassManager CGPM1;
6116b981647SChandler Carruth CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
6126b981647SChandler Carruth CGSCCAnalysisManager, LazyCallGraph &,
6136b981647SChandler Carruth CGSCCUpdateResult &>());
6146b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
6156b981647SChandler Carruth
6166b981647SChandler Carruth // Now run a module pass that preserves the analysis but not the call
6176b981647SChandler Carruth // graph or proxy.
6186b981647SChandler Carruth MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
6196b981647SChandler Carruth PreservedAnalyses PA;
6206b981647SChandler Carruth PA.preserve<TestSCCAnalysis>();
6216b981647SChandler Carruth return PA;
6226b981647SChandler Carruth }));
6236b981647SChandler Carruth
6246b981647SChandler Carruth // And now a second CGSCC run which requires the SCC analysis again.
62534a8a437SArthur Eubanks CGSCCPassManager CGPM2;
6266b981647SChandler Carruth CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
6276b981647SChandler Carruth CGSCCAnalysisManager, LazyCallGraph &,
6286b981647SChandler Carruth CGSCCUpdateResult &>());
6296b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
6306b981647SChandler Carruth
6316b981647SChandler Carruth MPM.run(*M, MAM);
6326b981647SChandler Carruth // Two runs and four SCCs.
6336b981647SChandler Carruth EXPECT_EQ(2 * 4, SCCAnalysisRuns);
6346b981647SChandler Carruth }
6356b981647SChandler Carruth
6366b981647SChandler Carruth // Test that an SCC pass which fails to preserve a Function analysis in fact
6376b981647SChandler Carruth // invalidates that analysis.
TEST_F(CGSCCPassManagerTest,TestSCCPassInvalidatesFunctionAnalysis)6386b981647SChandler Carruth TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesFunctionAnalysis) {
6396b981647SChandler Carruth int FunctionAnalysisRuns = 0;
6406b981647SChandler Carruth FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
6416b981647SChandler Carruth
6426b981647SChandler Carruth // Create a very simple module with a single function and SCC to make testing
6436b981647SChandler Carruth // these issues much easier.
6446b981647SChandler Carruth std::unique_ptr<Module> M = parseIR("declare void @g()\n"
6456b981647SChandler Carruth "declare void @h()\n"
6466b981647SChandler Carruth "define void @f() {\n"
6476b981647SChandler Carruth "entry:\n"
6486b981647SChandler Carruth " call void @g()\n"
6496b981647SChandler Carruth " call void @h()\n"
6506b981647SChandler Carruth " ret void\n"
6516b981647SChandler Carruth "}\n");
6526b981647SChandler Carruth
65334a8a437SArthur Eubanks CGSCCPassManager CGPM;
6546b981647SChandler Carruth
6556b981647SChandler Carruth // First force the analysis to be run.
65634a8a437SArthur Eubanks FunctionPassManager FPM1;
6576b981647SChandler Carruth FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
6586b981647SChandler Carruth CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
6596b981647SChandler Carruth
6606b981647SChandler Carruth // Now run a module pass that preserves the LazyCallGraph and proxy but not
6616b981647SChandler Carruth // the SCC analysis.
6626b981647SChandler Carruth CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
6636b981647SChandler Carruth LazyCallGraph &, CGSCCUpdateResult &) {
6646b981647SChandler Carruth PreservedAnalyses PA;
6656b981647SChandler Carruth PA.preserve<LazyCallGraphAnalysis>();
6666b981647SChandler Carruth return PA;
6676b981647SChandler Carruth }));
6686b981647SChandler Carruth
6696b981647SChandler Carruth // And now a second CGSCC run which requires the SCC analysis again. This
6706b981647SChandler Carruth // will trigger re-running it.
67134a8a437SArthur Eubanks FunctionPassManager FPM2;
6726b981647SChandler Carruth FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
6736b981647SChandler Carruth CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
6746b981647SChandler Carruth
67534a8a437SArthur Eubanks ModulePassManager MPM;
6766b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
6776b981647SChandler Carruth MPM.run(*M, MAM);
6786b981647SChandler Carruth EXPECT_EQ(2, FunctionAnalysisRuns);
6796b981647SChandler Carruth }
6806b981647SChandler Carruth
6816b981647SChandler Carruth // Check that marking the SCC analysis preserved is sufficient. This should
6826b981647SChandler Carruth // only run the analysis once the SCC.
TEST_F(CGSCCPassManagerTest,TestSCCPassCanPreserveFunctionAnalysis)6836b981647SChandler Carruth TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunctionAnalysis) {
6846b981647SChandler Carruth int FunctionAnalysisRuns = 0;
6856b981647SChandler Carruth FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
6866b981647SChandler Carruth
6876b981647SChandler Carruth // Create a very simple module with a single function and SCC to make testing
6886b981647SChandler Carruth // these issues much easier.
6896b981647SChandler Carruth std::unique_ptr<Module> M = parseIR("declare void @g()\n"
6906b981647SChandler Carruth "declare void @h()\n"
6916b981647SChandler Carruth "define void @f() {\n"
6926b981647SChandler Carruth "entry:\n"
6936b981647SChandler Carruth " call void @g()\n"
6946b981647SChandler Carruth " call void @h()\n"
6956b981647SChandler Carruth " ret void\n"
6966b981647SChandler Carruth "}\n");
6976b981647SChandler Carruth
69834a8a437SArthur Eubanks CGSCCPassManager CGPM;
6996b981647SChandler Carruth
7006b981647SChandler Carruth // First force the analysis to be run.
70134a8a437SArthur Eubanks FunctionPassManager FPM1;
7026b981647SChandler Carruth FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
7036b981647SChandler Carruth CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
7046b981647SChandler Carruth
7056b981647SChandler Carruth // Now run a module pass that preserves each of the necessary components
7066b981647SChandler Carruth // (but
7076b981647SChandler Carruth // not everything).
7086b981647SChandler Carruth CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
7096b981647SChandler Carruth LazyCallGraph &, CGSCCUpdateResult &) {
7106b981647SChandler Carruth PreservedAnalyses PA;
7116b981647SChandler Carruth PA.preserve<LazyCallGraphAnalysis>();
712bd9c2903SChandler Carruth PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
7136b981647SChandler Carruth PA.preserve<TestFunctionAnalysis>();
7146b981647SChandler Carruth return PA;
7156b981647SChandler Carruth }));
7166b981647SChandler Carruth
7176b981647SChandler Carruth // And now a second CGSCC run which requires the SCC analysis again but find
7186b981647SChandler Carruth // it in the cache.
71934a8a437SArthur Eubanks FunctionPassManager FPM2;
7206b981647SChandler Carruth FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
7216b981647SChandler Carruth CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
7226b981647SChandler Carruth
72334a8a437SArthur Eubanks ModulePassManager MPM;
7246b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
7256b981647SChandler Carruth MPM.run(*M, MAM);
7266b981647SChandler Carruth EXPECT_EQ(1, FunctionAnalysisRuns);
7276b981647SChandler Carruth }
7286b981647SChandler Carruth
7296b981647SChandler Carruth // Note that there is no test for invalidating the call graph or other
7306b981647SChandler Carruth // structure with an SCC pass because there is no mechanism to do that from
7316b981647SChandler Carruth // withinsuch a pass. Instead, such a pass has to directly update the call
7326b981647SChandler Carruth // graph structure.
7336b981647SChandler Carruth
7346b981647SChandler Carruth // Test that a madule pass invalidates function analyses when the CGSCC proxies
7356b981647SChandler Carruth // and pass manager.
TEST_F(CGSCCPassManagerTest,TestModulePassInvalidatesFunctionAnalysisNestedInCGSCC)7366b981647SChandler Carruth TEST_F(CGSCCPassManagerTest,
7376b981647SChandler Carruth TestModulePassInvalidatesFunctionAnalysisNestedInCGSCC) {
7386b981647SChandler Carruth MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
7396b981647SChandler Carruth
7406b981647SChandler Carruth int FunctionAnalysisRuns = 0;
7416b981647SChandler Carruth FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
7426b981647SChandler Carruth
74334a8a437SArthur Eubanks ModulePassManager MPM;
7446b981647SChandler Carruth
7456b981647SChandler Carruth // First force the analysis to be run.
74634a8a437SArthur Eubanks FunctionPassManager FPM1;
7476b981647SChandler Carruth FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
74834a8a437SArthur Eubanks CGSCCPassManager CGPM1;
7496b981647SChandler Carruth CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
7506b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
7516b981647SChandler Carruth
752bd9c2903SChandler Carruth // Now run a module pass that preserves the LazyCallGraph and proxies but not
7536b981647SChandler Carruth // the Function analysis.
7546b981647SChandler Carruth MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
7556b981647SChandler Carruth PreservedAnalyses PA;
7566b981647SChandler Carruth PA.preserve<LazyCallGraphAnalysis>();
7576b981647SChandler Carruth PA.preserve<CGSCCAnalysisManagerModuleProxy>();
758bd9c2903SChandler Carruth PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
759bd9c2903SChandler Carruth PA.preserve<FunctionAnalysisManagerModuleProxy>();
7606b981647SChandler Carruth return PA;
7616b981647SChandler Carruth }));
7626b981647SChandler Carruth
7636b981647SChandler Carruth // And now a second CGSCC run which requires the SCC analysis again. This
7646b981647SChandler Carruth // will trigger re-running it.
76534a8a437SArthur Eubanks FunctionPassManager FPM2;
7666b981647SChandler Carruth FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
76734a8a437SArthur Eubanks CGSCCPassManager CGPM2;
7686b981647SChandler Carruth CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
7696b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
7706b981647SChandler Carruth
7716b981647SChandler Carruth MPM.run(*M, MAM);
7726b981647SChandler Carruth // Two runs and 6 functions.
7736b981647SChandler Carruth EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
7746b981647SChandler Carruth }
7756b981647SChandler Carruth
776bd9c2903SChandler Carruth // Check that by marking the function pass and proxies as preserved, this
7776b981647SChandler Carruth // propagates all the way through.
TEST_F(CGSCCPassManagerTest,TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC)7786b981647SChandler Carruth TEST_F(CGSCCPassManagerTest,
7796b981647SChandler Carruth TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC) {
7806b981647SChandler Carruth MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
7816b981647SChandler Carruth
7826b981647SChandler Carruth int FunctionAnalysisRuns = 0;
7836b981647SChandler Carruth FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
7846b981647SChandler Carruth
78534a8a437SArthur Eubanks ModulePassManager MPM;
7866b981647SChandler Carruth
7876b981647SChandler Carruth // First force the analysis to be run.
78834a8a437SArthur Eubanks FunctionPassManager FPM1;
7896b981647SChandler Carruth FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
79034a8a437SArthur Eubanks CGSCCPassManager CGPM1;
7916b981647SChandler Carruth CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
7926b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
7936b981647SChandler Carruth
7946b981647SChandler Carruth // Now run a module pass that preserves the LazyCallGraph, the proxy, and
7956b981647SChandler Carruth // the Function analysis.
7966b981647SChandler Carruth MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
7976b981647SChandler Carruth PreservedAnalyses PA;
7986b981647SChandler Carruth PA.preserve<LazyCallGraphAnalysis>();
7996b981647SChandler Carruth PA.preserve<CGSCCAnalysisManagerModuleProxy>();
800bd9c2903SChandler Carruth PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
8016b981647SChandler Carruth PA.preserve<FunctionAnalysisManagerModuleProxy>();
8026b981647SChandler Carruth PA.preserve<TestFunctionAnalysis>();
8036b981647SChandler Carruth return PA;
8046b981647SChandler Carruth }));
8056b981647SChandler Carruth
8066b981647SChandler Carruth // And now a second CGSCC run which requires the SCC analysis again. This
8076b981647SChandler Carruth // will trigger re-running it.
80834a8a437SArthur Eubanks FunctionPassManager FPM2;
8096b981647SChandler Carruth FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
81034a8a437SArthur Eubanks CGSCCPassManager CGPM2;
8116b981647SChandler Carruth CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
8126b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
8136b981647SChandler Carruth
8146b981647SChandler Carruth MPM.run(*M, MAM);
8156b981647SChandler Carruth // One run and 6 functions.
8166b981647SChandler Carruth EXPECT_EQ(6, FunctionAnalysisRuns);
8176b981647SChandler Carruth }
8186b981647SChandler Carruth
8196b981647SChandler Carruth // Check that if the lazy call graph itself isn't preserved we still manage to
8206b981647SChandler Carruth // invalidate everything.
TEST_F(CGSCCPassManagerTest,TestModulePassInvalidatesFunctionAnalysisNestedInCGSCCOnCGChange)8216b981647SChandler Carruth TEST_F(CGSCCPassManagerTest,
8226b981647SChandler Carruth TestModulePassInvalidatesFunctionAnalysisNestedInCGSCCOnCGChange) {
8236b981647SChandler Carruth MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
8246b981647SChandler Carruth
8256b981647SChandler Carruth int FunctionAnalysisRuns = 0;
8266b981647SChandler Carruth FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
8276b981647SChandler Carruth
82834a8a437SArthur Eubanks ModulePassManager MPM;
8296b981647SChandler Carruth
8306b981647SChandler Carruth // First force the analysis to be run.
83134a8a437SArthur Eubanks FunctionPassManager FPM1;
8326b981647SChandler Carruth FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
83334a8a437SArthur Eubanks CGSCCPassManager CGPM1;
8346b981647SChandler Carruth CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
8356b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
8366b981647SChandler Carruth
8376b981647SChandler Carruth // Now run a module pass that preserves the LazyCallGraph but not the
8386b981647SChandler Carruth // Function analysis.
8396b981647SChandler Carruth MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
8406b981647SChandler Carruth PreservedAnalyses PA;
8416b981647SChandler Carruth return PA;
8426b981647SChandler Carruth }));
8436b981647SChandler Carruth
8446b981647SChandler Carruth // And now a second CGSCC run which requires the SCC analysis again. This
8456b981647SChandler Carruth // will trigger re-running it.
84634a8a437SArthur Eubanks FunctionPassManager FPM2;
8476b981647SChandler Carruth FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
84834a8a437SArthur Eubanks CGSCCPassManager CGPM2;
8496b981647SChandler Carruth CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
8506b981647SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
8516b981647SChandler Carruth
8526b981647SChandler Carruth MPM.run(*M, MAM);
8536b981647SChandler Carruth // Two runs and 6 functions.
8546b981647SChandler Carruth EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
8556b981647SChandler Carruth }
856ba90ae96SChandler Carruth
857ba90ae96SChandler Carruth /// A test CGSCC-level analysis pass which caches in its result another
858ba90ae96SChandler Carruth /// analysis pass and uses it to serve queries. This requires the result to
859ba90ae96SChandler Carruth /// invalidate itself when its dependency is invalidated.
860ba90ae96SChandler Carruth ///
861ba90ae96SChandler Carruth /// FIXME: Currently this doesn't also depend on a function analysis, and if it
862ba90ae96SChandler Carruth /// did we would fail to invalidate it correctly.
863ba90ae96SChandler Carruth struct TestIndirectSCCAnalysis
864ba90ae96SChandler Carruth : public AnalysisInfoMixin<TestIndirectSCCAnalysis> {
865ba90ae96SChandler Carruth struct Result {
Result__anone177e1640111::TestIndirectSCCAnalysis::Result866ba90ae96SChandler Carruth Result(TestSCCAnalysis::Result &SCCDep, TestModuleAnalysis::Result &MDep)
867ba90ae96SChandler Carruth : SCCDep(SCCDep), MDep(MDep) {}
868ba90ae96SChandler Carruth TestSCCAnalysis::Result &SCCDep;
869ba90ae96SChandler Carruth TestModuleAnalysis::Result &MDep;
870ba90ae96SChandler Carruth
invalidate__anone177e1640111::TestIndirectSCCAnalysis::Result871ba90ae96SChandler Carruth bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
872ba90ae96SChandler Carruth CGSCCAnalysisManager::Invalidator &Inv) {
873ba90ae96SChandler Carruth auto PAC = PA.getChecker<TestIndirectSCCAnalysis>();
874ba90ae96SChandler Carruth return !(PAC.preserved() ||
875ba90ae96SChandler Carruth PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()) ||
876ba90ae96SChandler Carruth Inv.invalidate<TestSCCAnalysis>(C, PA);
877ba90ae96SChandler Carruth }
878ba90ae96SChandler Carruth };
879ba90ae96SChandler Carruth
TestIndirectSCCAnalysis__anone177e1640111::TestIndirectSCCAnalysis880bd541b21SAlina Sbirlea TestIndirectSCCAnalysis(int &Runs, ModuleAnalysisManager &MAM)
881bd541b21SAlina Sbirlea : Runs(Runs), MAM(MAM) {}
882ba90ae96SChandler Carruth
883ba90ae96SChandler Carruth /// Run the analysis pass over the function and return a result.
run__anone177e1640111::TestIndirectSCCAnalysis884ba90ae96SChandler Carruth Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
885ba90ae96SChandler Carruth LazyCallGraph &CG) {
886ba90ae96SChandler Carruth ++Runs;
887ba90ae96SChandler Carruth auto &SCCDep = AM.getResult<TestSCCAnalysis>(C, CG);
888ba90ae96SChandler Carruth
889ba90ae96SChandler Carruth auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG);
890ba90ae96SChandler Carruth // For the test, we insist that the module analysis starts off in the
891bd541b21SAlina Sbirlea // cache. Getting a cached result that isn't stateless triggers an assert.
892bd541b21SAlina Sbirlea // auto &MDep = *ModuleProxy.getCachedResult<TestModuleAnalysis>(
893bd541b21SAlina Sbirlea // *C.begin()->getFunction().getParent());
894bd541b21SAlina Sbirlea // Use MAM, for the purposes of this unittest.
895ba90ae96SChandler Carruth auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(
896ba90ae96SChandler Carruth *C.begin()->getFunction().getParent());
897ba90ae96SChandler Carruth // Register the dependency as module analysis dependencies have to be
898ba90ae96SChandler Carruth // pre-registered on the proxy.
899ba90ae96SChandler Carruth ModuleProxy.registerOuterAnalysisInvalidation<TestModuleAnalysis,
900ba90ae96SChandler Carruth TestIndirectSCCAnalysis>();
901ba90ae96SChandler Carruth
902ba90ae96SChandler Carruth return Result(SCCDep, MDep);
903ba90ae96SChandler Carruth }
904ba90ae96SChandler Carruth
905ba90ae96SChandler Carruth private:
906ba90ae96SChandler Carruth friend AnalysisInfoMixin<TestIndirectSCCAnalysis>;
907ba90ae96SChandler Carruth static AnalysisKey Key;
908ba90ae96SChandler Carruth
909ba90ae96SChandler Carruth int &Runs;
910bd541b21SAlina Sbirlea ModuleAnalysisManager &MAM;
911ba90ae96SChandler Carruth };
912ba90ae96SChandler Carruth
913ba90ae96SChandler Carruth AnalysisKey TestIndirectSCCAnalysis::Key;
914ba90ae96SChandler Carruth
915ba90ae96SChandler Carruth /// A test analysis pass which caches in its result the result from the above
916ba90ae96SChandler Carruth /// indirect analysis pass.
917ba90ae96SChandler Carruth ///
918ba90ae96SChandler Carruth /// This allows us to ensure that whenever an analysis pass is invalidated due
919ba90ae96SChandler Carruth /// to dependencies (especially dependencies across IR units that trigger
920ba90ae96SChandler Carruth /// asynchronous invalidation) we correctly detect that this may in turn cause
921ba90ae96SChandler Carruth /// other analysis to be invalidated.
922ba90ae96SChandler Carruth struct TestDoublyIndirectSCCAnalysis
923ba90ae96SChandler Carruth : public AnalysisInfoMixin<TestDoublyIndirectSCCAnalysis> {
924ba90ae96SChandler Carruth struct Result {
Result__anone177e1640111::TestDoublyIndirectSCCAnalysis::Result925ba90ae96SChandler Carruth Result(TestIndirectSCCAnalysis::Result &IDep) : IDep(IDep) {}
926ba90ae96SChandler Carruth TestIndirectSCCAnalysis::Result &IDep;
927ba90ae96SChandler Carruth
invalidate__anone177e1640111::TestDoublyIndirectSCCAnalysis::Result928ba90ae96SChandler Carruth bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
929ba90ae96SChandler Carruth CGSCCAnalysisManager::Invalidator &Inv) {
930ba90ae96SChandler Carruth auto PAC = PA.getChecker<TestDoublyIndirectSCCAnalysis>();
931ba90ae96SChandler Carruth return !(PAC.preserved() ||
932ba90ae96SChandler Carruth PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()) ||
933ba90ae96SChandler Carruth Inv.invalidate<TestIndirectSCCAnalysis>(C, PA);
934ba90ae96SChandler Carruth }
935ba90ae96SChandler Carruth };
936ba90ae96SChandler Carruth
TestDoublyIndirectSCCAnalysis__anone177e1640111::TestDoublyIndirectSCCAnalysis937ba90ae96SChandler Carruth TestDoublyIndirectSCCAnalysis(int &Runs) : Runs(Runs) {}
938ba90ae96SChandler Carruth
939ba90ae96SChandler Carruth /// Run the analysis pass over the function and return a result.
run__anone177e1640111::TestDoublyIndirectSCCAnalysis940ba90ae96SChandler Carruth Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
941ba90ae96SChandler Carruth LazyCallGraph &CG) {
942ba90ae96SChandler Carruth ++Runs;
943ba90ae96SChandler Carruth auto &IDep = AM.getResult<TestIndirectSCCAnalysis>(C, CG);
944ba90ae96SChandler Carruth return Result(IDep);
945ba90ae96SChandler Carruth }
946ba90ae96SChandler Carruth
947ba90ae96SChandler Carruth private:
948ba90ae96SChandler Carruth friend AnalysisInfoMixin<TestDoublyIndirectSCCAnalysis>;
949ba90ae96SChandler Carruth static AnalysisKey Key;
950ba90ae96SChandler Carruth
951ba90ae96SChandler Carruth int &Runs;
952ba90ae96SChandler Carruth };
953ba90ae96SChandler Carruth
954ba90ae96SChandler Carruth AnalysisKey TestDoublyIndirectSCCAnalysis::Key;
955ba90ae96SChandler Carruth
956ba90ae96SChandler Carruth /// A test analysis pass which caches results from three different IR unit
957ba90ae96SChandler Carruth /// layers and requires intermediate layers to correctly propagate the entire
958ba90ae96SChandler Carruth /// distance.
959ba90ae96SChandler Carruth struct TestIndirectFunctionAnalysis
960ba90ae96SChandler Carruth : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> {
961ba90ae96SChandler Carruth struct Result {
Result__anone177e1640111::TestIndirectFunctionAnalysis::Result962ba90ae96SChandler Carruth Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep,
963ba90ae96SChandler Carruth TestSCCAnalysis::Result &SCCDep)
964ba90ae96SChandler Carruth : FDep(FDep), MDep(MDep), SCCDep(SCCDep) {}
965ba90ae96SChandler Carruth TestFunctionAnalysis::Result &FDep;
966ba90ae96SChandler Carruth TestModuleAnalysis::Result &MDep;
967ba90ae96SChandler Carruth TestSCCAnalysis::Result &SCCDep;
968ba90ae96SChandler Carruth
invalidate__anone177e1640111::TestIndirectFunctionAnalysis::Result969ba90ae96SChandler Carruth bool invalidate(Function &F, const PreservedAnalyses &PA,
970ba90ae96SChandler Carruth FunctionAnalysisManager::Invalidator &Inv) {
971ba90ae96SChandler Carruth auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>();
972ba90ae96SChandler Carruth return !(PAC.preserved() ||
973ba90ae96SChandler Carruth PAC.preservedSet<AllAnalysesOn<Function>>()) ||
974ba90ae96SChandler Carruth Inv.invalidate<TestFunctionAnalysis>(F, PA);
975ba90ae96SChandler Carruth }
976ba90ae96SChandler Carruth };
977ba90ae96SChandler Carruth
TestIndirectFunctionAnalysis__anone177e1640111::TestIndirectFunctionAnalysis978bd541b21SAlina Sbirlea TestIndirectFunctionAnalysis(int &Runs, ModuleAnalysisManager &MAM,
979bd541b21SAlina Sbirlea CGSCCAnalysisManager &CGAM)
980bd541b21SAlina Sbirlea : Runs(Runs), MAM(MAM), CGAM(CGAM) {}
981ba90ae96SChandler Carruth
982ba90ae96SChandler Carruth /// Run the analysis pass over the function and return a result.
run__anone177e1640111::TestIndirectFunctionAnalysis983ba90ae96SChandler Carruth Result run(Function &F, FunctionAnalysisManager &AM) {
984ba90ae96SChandler Carruth ++Runs;
985ba90ae96SChandler Carruth auto &FDep = AM.getResult<TestFunctionAnalysis>(F);
986ba90ae96SChandler Carruth
987ba90ae96SChandler Carruth auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
988ba90ae96SChandler Carruth // For the test, we insist that the module analysis starts off in the
989bd541b21SAlina Sbirlea // cache. Getting a cached result that isn't stateless triggers an assert.
990bd541b21SAlina Sbirlea // Use MAM, for the purposes of this unittest.
991ba90ae96SChandler Carruth auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());
992ba90ae96SChandler Carruth // Register the dependency as module analysis dependencies have to be
993ba90ae96SChandler Carruth // pre-registered on the proxy.
994ba90ae96SChandler Carruth ModuleProxy.registerOuterAnalysisInvalidation<
995ba90ae96SChandler Carruth TestModuleAnalysis, TestIndirectFunctionAnalysis>();
996ba90ae96SChandler Carruth
997bd541b21SAlina Sbirlea // For the test we assume this is run inside a CGSCC pass manager.
998bd541b21SAlina Sbirlea // Use MAM, for the purposes of this unittest.
999ba90ae96SChandler Carruth const LazyCallGraph &CG =
1000ba90ae96SChandler Carruth *MAM.getCachedResult<LazyCallGraphAnalysis>(*F.getParent());
1001ba90ae96SChandler Carruth auto &CGSCCProxy = AM.getResult<CGSCCAnalysisManagerFunctionProxy>(F);
1002ba90ae96SChandler Carruth // For the test, we insist that the CGSCC analysis starts off in the cache.
1003bd541b21SAlina Sbirlea // Getting a cached result that isn't stateless triggers an assert.
1004bd541b21SAlina Sbirlea // Use CGAM, for the purposes of this unittest.
1005ba90ae96SChandler Carruth auto &SCCDep =
1006ba90ae96SChandler Carruth *CGAM.getCachedResult<TestSCCAnalysis>(*CG.lookupSCC(*CG.lookup(F)));
1007ba90ae96SChandler Carruth // Register the dependency as CGSCC analysis dependencies have to be
1008ba90ae96SChandler Carruth // pre-registered on the proxy.
1009ba90ae96SChandler Carruth CGSCCProxy.registerOuterAnalysisInvalidation<
1010ba90ae96SChandler Carruth TestSCCAnalysis, TestIndirectFunctionAnalysis>();
1011ba90ae96SChandler Carruth
1012ba90ae96SChandler Carruth return Result(FDep, MDep, SCCDep);
1013ba90ae96SChandler Carruth }
1014ba90ae96SChandler Carruth
1015ba90ae96SChandler Carruth private:
1016ba90ae96SChandler Carruth friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>;
1017ba90ae96SChandler Carruth static AnalysisKey Key;
1018ba90ae96SChandler Carruth
1019ba90ae96SChandler Carruth int &Runs;
1020bd541b21SAlina Sbirlea ModuleAnalysisManager &MAM;
1021bd541b21SAlina Sbirlea CGSCCAnalysisManager &CGAM;
1022ba90ae96SChandler Carruth };
1023ba90ae96SChandler Carruth
1024ba90ae96SChandler Carruth AnalysisKey TestIndirectFunctionAnalysis::Key;
1025ba90ae96SChandler Carruth
TEST_F(CGSCCPassManagerTest,TestIndirectAnalysisInvalidation)1026ba90ae96SChandler Carruth TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) {
1027ba90ae96SChandler Carruth int ModuleAnalysisRuns = 0;
1028ba90ae96SChandler Carruth MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
1029ba90ae96SChandler Carruth
1030ba90ae96SChandler Carruth int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0,
1031ba90ae96SChandler Carruth DoublyIndirectSCCAnalysisRuns = 0;
1032ba90ae96SChandler Carruth CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
1033ba90ae96SChandler Carruth CGAM.registerPass(
1034bd541b21SAlina Sbirlea [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns, MAM); });
1035ba90ae96SChandler Carruth CGAM.registerPass([&] {
1036ba90ae96SChandler Carruth return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns);
1037ba90ae96SChandler Carruth });
1038ba90ae96SChandler Carruth
1039ba90ae96SChandler Carruth int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0;
1040ba90ae96SChandler Carruth FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
1041ba90ae96SChandler Carruth FAM.registerPass([&] {
1042bd541b21SAlina Sbirlea return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns, MAM,
1043bd541b21SAlina Sbirlea CGAM);
1044ba90ae96SChandler Carruth });
1045ba90ae96SChandler Carruth
104634a8a437SArthur Eubanks ModulePassManager MPM;
1047ba90ae96SChandler Carruth
1048ba90ae96SChandler Carruth int FunctionCount = 0;
104934a8a437SArthur Eubanks CGSCCPassManager CGPM;
1050ba90ae96SChandler Carruth // First just use the analysis to get the function count and preserve
1051ba90ae96SChandler Carruth // everything.
1052ba90ae96SChandler Carruth CGPM.addPass(
1053ba90ae96SChandler Carruth LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
1054ba90ae96SChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &) {
1055ba90ae96SChandler Carruth auto &DoublyIndirectResult =
1056ba90ae96SChandler Carruth AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
1057ba90ae96SChandler Carruth auto &IndirectResult = DoublyIndirectResult.IDep;
1058ba90ae96SChandler Carruth FunctionCount += IndirectResult.SCCDep.FunctionCount;
1059ba90ae96SChandler Carruth return PreservedAnalyses::all();
1060ba90ae96SChandler Carruth }));
1061bd9c2903SChandler Carruth CGPM.addPass(createCGSCCToFunctionPassAdaptor(
1062bd9c2903SChandler Carruth RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>()));
1063bd9c2903SChandler Carruth
1064ba90ae96SChandler Carruth // Next, invalidate
1065ba90ae96SChandler Carruth // - both analyses for the (f) and (x) SCCs,
1066ba90ae96SChandler Carruth // - just the underlying (indirect) analysis for (g) SCC, and
1067ba90ae96SChandler Carruth // - just the direct analysis for (h1,h2,h3) SCC.
1068ba90ae96SChandler Carruth CGPM.addPass(
1069ba90ae96SChandler Carruth LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
1070ba90ae96SChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &) {
1071ba90ae96SChandler Carruth auto &DoublyIndirectResult =
1072ba90ae96SChandler Carruth AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
1073ba90ae96SChandler Carruth auto &IndirectResult = DoublyIndirectResult.IDep;
1074ba90ae96SChandler Carruth FunctionCount += IndirectResult.SCCDep.FunctionCount;
1075ba90ae96SChandler Carruth auto PA = PreservedAnalyses::none();
1076bd9c2903SChandler Carruth PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
1077bd9c2903SChandler Carruth PA.preserveSet<AllAnalysesOn<Function>>();
1078ba90ae96SChandler Carruth if (C.getName() == "(g)")
1079ba90ae96SChandler Carruth PA.preserve<TestSCCAnalysis>();
1080ba90ae96SChandler Carruth else if (C.getName() == "(h3, h1, h2)")
1081ba90ae96SChandler Carruth PA.preserve<TestIndirectSCCAnalysis>();
1082ba90ae96SChandler Carruth return PA;
1083ba90ae96SChandler Carruth }));
1084bd9c2903SChandler Carruth // Finally, use the analysis again on each SCC (and function), forcing
1085bd9c2903SChandler Carruth // re-computation for all of them.
1086ba90ae96SChandler Carruth CGPM.addPass(
1087ba90ae96SChandler Carruth LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
1088ba90ae96SChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &) {
1089ba90ae96SChandler Carruth auto &DoublyIndirectResult =
1090ba90ae96SChandler Carruth AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
1091ba90ae96SChandler Carruth auto &IndirectResult = DoublyIndirectResult.IDep;
1092ba90ae96SChandler Carruth FunctionCount += IndirectResult.SCCDep.FunctionCount;
1093ba90ae96SChandler Carruth return PreservedAnalyses::all();
1094ba90ae96SChandler Carruth }));
1095bd9c2903SChandler Carruth CGPM.addPass(createCGSCCToFunctionPassAdaptor(
1096bd9c2903SChandler Carruth RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>()));
1097ba90ae96SChandler Carruth
1098ba90ae96SChandler Carruth // Create a second CGSCC pass manager. This will cause the module-level
1099ba90ae96SChandler Carruth // invalidation to occur, which will force yet another invalidation of the
1100ba90ae96SChandler Carruth // indirect SCC-level analysis as the module analysis it depends on gets
1101ba90ae96SChandler Carruth // invalidated.
110234a8a437SArthur Eubanks CGSCCPassManager CGPM2;
1103ba90ae96SChandler Carruth CGPM2.addPass(
1104ba90ae96SChandler Carruth LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
1105ba90ae96SChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &) {
1106ba90ae96SChandler Carruth auto &DoublyIndirectResult =
1107ba90ae96SChandler Carruth AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
1108ba90ae96SChandler Carruth auto &IndirectResult = DoublyIndirectResult.IDep;
1109ba90ae96SChandler Carruth FunctionCount += IndirectResult.SCCDep.FunctionCount;
1110ba90ae96SChandler Carruth return PreservedAnalyses::all();
1111ba90ae96SChandler Carruth }));
1112bd9c2903SChandler Carruth CGPM2.addPass(createCGSCCToFunctionPassAdaptor(
1113bd9c2903SChandler Carruth RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>()));
1114ba90ae96SChandler Carruth
1115bd9c2903SChandler Carruth // Add a requires pass to populate the module analysis and then our CGSCC
1116ba90ae96SChandler Carruth // pass pipeline.
1117ba90ae96SChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
1118ba90ae96SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
1119ba90ae96SChandler Carruth // Now require the module analysis again (it will have been invalidated once)
1120bd9c2903SChandler Carruth // and then use it again from our second CGSCC pipeline..
1121ba90ae96SChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
1122ba90ae96SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
1123ba90ae96SChandler Carruth MPM.run(*M, MAM);
1124ba90ae96SChandler Carruth
1125ba90ae96SChandler Carruth // There are generally two possible runs for each of the four SCCs. But
1126ba90ae96SChandler Carruth // for one SCC, we only invalidate the indirect analysis so the base one
1127ba90ae96SChandler Carruth // only gets run seven times.
1128ba90ae96SChandler Carruth EXPECT_EQ(7, SCCAnalysisRuns);
1129ba90ae96SChandler Carruth // The module analysis pass should be run twice here.
1130ba90ae96SChandler Carruth EXPECT_EQ(2, ModuleAnalysisRuns);
1131ba90ae96SChandler Carruth // The indirect analysis is invalidated (either directly or indirectly) three
1132ba90ae96SChandler Carruth // times for each of four SCCs.
1133ba90ae96SChandler Carruth EXPECT_EQ(3 * 4, IndirectSCCAnalysisRuns);
1134ba90ae96SChandler Carruth EXPECT_EQ(3 * 4, DoublyIndirectSCCAnalysisRuns);
1135ba90ae96SChandler Carruth
1136bd9c2903SChandler Carruth // We run the indirect function analysis once per function the first time.
1137bd9c2903SChandler Carruth // Then we re-run it for every SCC but "(g)". Then we re-run it for every
1138bd9c2903SChandler Carruth // function again.
1139bd9c2903SChandler Carruth EXPECT_EQ(6 + 5 + 6, IndirectFunctionAnalysisRuns);
1140bd9c2903SChandler Carruth
1141ba90ae96SChandler Carruth // Four passes count each of six functions once (via SCCs).
1142ba90ae96SChandler Carruth EXPECT_EQ(4 * 6, FunctionCount);
1143ba90ae96SChandler Carruth }
11447c8964d8SChandler Carruth
TEST_F(CGSCCPassManagerTest,TestAnalysisInvalidationCGSCCUpdate)11457c8964d8SChandler Carruth TEST_F(CGSCCPassManagerTest, TestAnalysisInvalidationCGSCCUpdate) {
11467c8964d8SChandler Carruth int ModuleAnalysisRuns = 0;
11477c8964d8SChandler Carruth MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
11487c8964d8SChandler Carruth
11497c8964d8SChandler Carruth int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0,
11507c8964d8SChandler Carruth DoublyIndirectSCCAnalysisRuns = 0;
11517c8964d8SChandler Carruth CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
11527c8964d8SChandler Carruth CGAM.registerPass(
1153bd541b21SAlina Sbirlea [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns, MAM); });
11547c8964d8SChandler Carruth CGAM.registerPass([&] {
11557c8964d8SChandler Carruth return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns);
11567c8964d8SChandler Carruth });
11577c8964d8SChandler Carruth
11587c8964d8SChandler Carruth int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0;
11597c8964d8SChandler Carruth FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
11607c8964d8SChandler Carruth FAM.registerPass([&] {
1161bd541b21SAlina Sbirlea return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns, MAM,
1162bd541b21SAlina Sbirlea CGAM);
11637c8964d8SChandler Carruth });
11647c8964d8SChandler Carruth
116534a8a437SArthur Eubanks ModulePassManager MPM;
11667c8964d8SChandler Carruth
116734a8a437SArthur Eubanks CGSCCPassManager CGPM;
11687c8964d8SChandler Carruth // First just use the analysis to get the function count and preserve
11697c8964d8SChandler Carruth // everything.
11707c8964d8SChandler Carruth using RequireTestIndirectFunctionAnalysisPass =
11717c8964d8SChandler Carruth RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>;
11727c8964d8SChandler Carruth using RequireTestDoublyIndirectSCCAnalysisPass =
11737c8964d8SChandler Carruth RequireAnalysisPass<TestDoublyIndirectSCCAnalysis, LazyCallGraph::SCC,
11747c8964d8SChandler Carruth CGSCCAnalysisManager, LazyCallGraph &,
11757c8964d8SChandler Carruth CGSCCUpdateResult &>;
11767c8964d8SChandler Carruth CGPM.addPass(RequireTestDoublyIndirectSCCAnalysisPass());
11777c8964d8SChandler Carruth CGPM.addPass(createCGSCCToFunctionPassAdaptor(
11787c8964d8SChandler Carruth RequireTestIndirectFunctionAnalysisPass()));
11797c8964d8SChandler Carruth
11807c8964d8SChandler Carruth // Next, we inject an SCC pass that invalidates everything for the `(h3, h1,
11817c8964d8SChandler Carruth // h2)` SCC but also deletes the call edge from `h2` to `h3` and updates the
11827c8964d8SChandler Carruth // CG. This should successfully invalidate (and force to be re-run) all the
11837c8964d8SChandler Carruth // analyses for that SCC and for the functions.
11847c8964d8SChandler Carruth CGPM.addPass(
11857c8964d8SChandler Carruth LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
11867c8964d8SChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &UR) {
11877c8964d8SChandler Carruth (void)AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
11887c8964d8SChandler Carruth if (C.getName() != "(h3, h1, h2)")
11897c8964d8SChandler Carruth return PreservedAnalyses::all();
11907c8964d8SChandler Carruth
11917c8964d8SChandler Carruth // Build the preserved set.
11927c8964d8SChandler Carruth auto PA = PreservedAnalyses::none();
11937c8964d8SChandler Carruth PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
11947c8964d8SChandler Carruth PA.preserve<TestIndirectSCCAnalysis>();
11957c8964d8SChandler Carruth PA.preserve<TestDoublyIndirectSCCAnalysis>();
11967c8964d8SChandler Carruth
11977c8964d8SChandler Carruth // Delete the call from `h2` to `h3`.
11987c8964d8SChandler Carruth auto &H2N = *llvm::find_if(
11997c8964d8SChandler Carruth C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; });
12007c8964d8SChandler Carruth auto &H2F = H2N.getFunction();
12017c8964d8SChandler Carruth auto &H3F = *cast<CallInst>(H2F.begin()->begin())->getCalledFunction();
12027c8964d8SChandler Carruth assert(H3F.getName() == "h3" && "Wrong called function!");
12037c8964d8SChandler Carruth H2F.begin()->begin()->eraseFromParent();
12047c8964d8SChandler Carruth // Insert a bitcast of `h3` so that we retain a ref edge to it.
12057c8964d8SChandler Carruth (void)CastInst::CreatePointerCast(&H3F,
12067c8964d8SChandler Carruth Type::getInt8PtrTy(H2F.getContext()),
12077c8964d8SChandler Carruth "dummy", &*H2F.begin()->begin());
12087c8964d8SChandler Carruth
12097c8964d8SChandler Carruth // Now update the call graph.
121019913b22SChandler Carruth auto &NewC =
1211bd541b21SAlina Sbirlea updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM);
12127c8964d8SChandler Carruth assert(&NewC != &C && "Should get a new SCC due to update!");
12133733fc40SNAKAMURA Takumi (void)&NewC;
12147c8964d8SChandler Carruth
12157c8964d8SChandler Carruth return PA;
12167c8964d8SChandler Carruth }));
12177c8964d8SChandler Carruth // Now use the analysis again on each SCC and function, forcing
12187c8964d8SChandler Carruth // re-computation for all of them.
12197c8964d8SChandler Carruth CGPM.addPass(RequireTestDoublyIndirectSCCAnalysisPass());
12207c8964d8SChandler Carruth CGPM.addPass(createCGSCCToFunctionPassAdaptor(
12217c8964d8SChandler Carruth RequireTestIndirectFunctionAnalysisPass()));
12227c8964d8SChandler Carruth
12237c8964d8SChandler Carruth // Create another CGSCC pipeline that requires all the analyses again.
122434a8a437SArthur Eubanks CGSCCPassManager CGPM2;
12257c8964d8SChandler Carruth CGPM2.addPass(RequireTestDoublyIndirectSCCAnalysisPass());
12267c8964d8SChandler Carruth CGPM2.addPass(createCGSCCToFunctionPassAdaptor(
12277c8964d8SChandler Carruth RequireTestIndirectFunctionAnalysisPass()));
12287c8964d8SChandler Carruth
12297c8964d8SChandler Carruth // Next we inject an SCC pass that finds the `(h2)` SCC, adds a call to `h3`
12307c8964d8SChandler Carruth // back to `h2`, and then invalidates everything for what will then be the
12317c8964d8SChandler Carruth // `(h3, h1, h2)` SCC again.
123234a8a437SArthur Eubanks CGSCCPassManager CGPM3;
12337c8964d8SChandler Carruth CGPM3.addPass(
12347c8964d8SChandler Carruth LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
12357c8964d8SChandler Carruth LazyCallGraph &CG, CGSCCUpdateResult &UR) {
12367c8964d8SChandler Carruth (void)AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
12377c8964d8SChandler Carruth if (C.getName() != "(h2)")
12387c8964d8SChandler Carruth return PreservedAnalyses::all();
12397c8964d8SChandler Carruth
12407c8964d8SChandler Carruth // Build the preserved set.
12417c8964d8SChandler Carruth auto PA = PreservedAnalyses::none();
12427c8964d8SChandler Carruth PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
12437c8964d8SChandler Carruth PA.preserve<TestIndirectSCCAnalysis>();
12447c8964d8SChandler Carruth PA.preserve<TestDoublyIndirectSCCAnalysis>();
12457c8964d8SChandler Carruth
12467c8964d8SChandler Carruth // Delete the bitcast of `h3` that we added earlier.
12477c8964d8SChandler Carruth auto &H2N = *C.begin();
12487c8964d8SChandler Carruth auto &H2F = H2N.getFunction();
12497c8964d8SChandler Carruth auto &H3F = *cast<Function>(cast<BitCastInst>(H2F.begin()->begin())->getOperand(0));
12507c8964d8SChandler Carruth assert(H3F.getName() == "h3" && "Wrong called function!");
12517c8964d8SChandler Carruth H2F.begin()->begin()->eraseFromParent();
12527c8964d8SChandler Carruth // And insert a call to `h3`.
12537c8964d8SChandler Carruth (void)CallInst::Create(&H3F, {}, "", &*H2F.begin()->begin());
12547c8964d8SChandler Carruth
12557c8964d8SChandler Carruth // Now update the call graph.
125619913b22SChandler Carruth auto &NewC =
1257bd541b21SAlina Sbirlea updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM);
12587c8964d8SChandler Carruth assert(&NewC != &C && "Should get a new SCC due to update!");
12593733fc40SNAKAMURA Takumi (void)&NewC;
12607c8964d8SChandler Carruth
12617c8964d8SChandler Carruth return PA;
12627c8964d8SChandler Carruth }));
12637c8964d8SChandler Carruth // Now use the analysis again on each SCC and function, forcing
12647c8964d8SChandler Carruth // re-computation for all of them.
12657c8964d8SChandler Carruth CGPM3.addPass(RequireTestDoublyIndirectSCCAnalysisPass());
12667c8964d8SChandler Carruth CGPM3.addPass(createCGSCCToFunctionPassAdaptor(
12677c8964d8SChandler Carruth RequireTestIndirectFunctionAnalysisPass()));
12687c8964d8SChandler Carruth
12697c8964d8SChandler Carruth // Create a second CGSCC pass manager. This will cause the module-level
12707c8964d8SChandler Carruth // invalidation to occur, which will force yet another invalidation of the
12717c8964d8SChandler Carruth // indirect SCC-level analysis as the module analysis it depends on gets
12727c8964d8SChandler Carruth // invalidated.
127334a8a437SArthur Eubanks CGSCCPassManager CGPM4;
12747c8964d8SChandler Carruth CGPM4.addPass(RequireTestDoublyIndirectSCCAnalysisPass());
12757c8964d8SChandler Carruth CGPM4.addPass(createCGSCCToFunctionPassAdaptor(
12767c8964d8SChandler Carruth RequireTestIndirectFunctionAnalysisPass()));
12777c8964d8SChandler Carruth
12787c8964d8SChandler Carruth // Add a requires pass to populate the module analysis and then one of our
12797c8964d8SChandler Carruth // CGSCC pipelines. Repeat for all four CGSCC pipelines.
12807c8964d8SChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
12817c8964d8SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
12827c8964d8SChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
12837c8964d8SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
12847c8964d8SChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
12857c8964d8SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3)));
12867c8964d8SChandler Carruth MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
12877c8964d8SChandler Carruth MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM4)));
12887c8964d8SChandler Carruth MPM.run(*M, MAM);
12897c8964d8SChandler Carruth
12907c8964d8SChandler Carruth // We run over four SCCs the first time. But then we split an SCC into three.
1291923ff550SChandler Carruth // And then we merge those three back into one. However, this also
1292923ff550SChandler Carruth // invalidates all three SCCs further down in the PO walk.
1293b559535aSWenlei He EXPECT_EQ(4 + 3 + 3, SCCAnalysisRuns);
12947c8964d8SChandler Carruth // The module analysis pass should be run three times.
12957c8964d8SChandler Carruth EXPECT_EQ(3, ModuleAnalysisRuns);
12967c8964d8SChandler Carruth // We run over four SCCs the first time. Then over the two new ones. Then the
12977c8964d8SChandler Carruth // entire module is invalidated causing a full run over all seven. Then we
1298923ff550SChandler Carruth // fold three SCCs back to one, re-compute for it and the two SCCs above it
1299923ff550SChandler Carruth // in the graph, and then run over the whole module again.
1300b559535aSWenlei He EXPECT_EQ(4 + 2 + 7 + 3 + 4, IndirectSCCAnalysisRuns);
1301b559535aSWenlei He EXPECT_EQ(4 + 2 + 7 + 3 + 4, DoublyIndirectSCCAnalysisRuns);
13027c8964d8SChandler Carruth
13037c8964d8SChandler Carruth // First we run over all six functions. Then we re-run it over three when we
13047c8964d8SChandler Carruth // split their SCCs. Then we re-run over the whole module. Then we re-run
1305923ff550SChandler Carruth // over three functions merged back into a single SCC, then those three
1306923ff550SChandler Carruth // functions again, the two functions in SCCs above it in the graph, and then
1307923ff550SChandler Carruth // over the whole module again.
1308b559535aSWenlei He EXPECT_EQ(6 + 3 + 6 + 3 + 2 + 6, FunctionAnalysisRuns);
13097c8964d8SChandler Carruth
1310051bdb0bSChandler Carruth // Re run the function analysis over the entire module, and then re-run it
1311051bdb0bSChandler Carruth // over the `(h3, h1, h2)` SCC due to invalidation. Then we re-run it over
1312051bdb0bSChandler Carruth // the entire module, then the three functions merged back into a single SCC,
1313923ff550SChandler Carruth // those three functions again, then the two functions in SCCs above it in
1314923ff550SChandler Carruth // the graph, and then over the whole module.
1315b559535aSWenlei He EXPECT_EQ(6 + 3 + 6 + 3 + 2 + 6, IndirectFunctionAnalysisRuns);
13167c8964d8SChandler Carruth }
131701377453SJohannes Doerfert
131801377453SJohannes Doerfert // The (negative) tests below check for assertions so we only run them if NDEBUG
131901377453SJohannes Doerfert // is not defined.
132001377453SJohannes Doerfert #ifndef NDEBUG
132101377453SJohannes Doerfert
132201377453SJohannes Doerfert struct LambdaSCCPassNoPreserve : public PassInfoMixin<LambdaSCCPassNoPreserve> {
132301377453SJohannes Doerfert template <typename T>
LambdaSCCPassNoPreserve__anone177e1640111::LambdaSCCPassNoPreserve132401377453SJohannes Doerfert LambdaSCCPassNoPreserve(T &&Arg) : Func(std::forward<T>(Arg)) {}
132501377453SJohannes Doerfert
run__anone177e1640111::LambdaSCCPassNoPreserve132601377453SJohannes Doerfert PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
132701377453SJohannes Doerfert LazyCallGraph &CG, CGSCCUpdateResult &UR) {
132801377453SJohannes Doerfert Func(C, AM, CG, UR);
132972277ecdSJohannes Doerfert PreservedAnalyses PA;
133072277ecdSJohannes Doerfert // We update the core CGSCC data structures and so can preserve the proxy to
133172277ecdSJohannes Doerfert // the function analysis manager.
133272277ecdSJohannes Doerfert PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
133372277ecdSJohannes Doerfert return PA;
133474319922SChandler Carruth }
133501377453SJohannes Doerfert
133601377453SJohannes Doerfert std::function<void(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
133701377453SJohannes Doerfert LazyCallGraph &, CGSCCUpdateResult &)>
133801377453SJohannes Doerfert Func;
133901377453SJohannes Doerfert };
134001377453SJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses0)134101377453SJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses0) {
134234a8a437SArthur Eubanks CGSCCPassManager CGPM;
134301377453SJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve(
134401377453SJohannes Doerfert [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
134501377453SJohannes Doerfert CGSCCUpdateResult &UR) {
134601377453SJohannes Doerfert if (C.getName() != "(h3, h1, h2)")
134701377453SJohannes Doerfert return;
134801377453SJohannes Doerfert
1349bd541b21SAlina Sbirlea auto &FAM =
1350bd541b21SAlina Sbirlea AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
135101377453SJohannes Doerfert Function *FnX = M->getFunction("x");
135201377453SJohannes Doerfert Function *FnH1 = M->getFunction("h1");
135301377453SJohannes Doerfert Function *FnH2 = M->getFunction("h2");
135401377453SJohannes Doerfert Function *FnH3 = M->getFunction("h3");
135501377453SJohannes Doerfert ASSERT_NE(FnX, nullptr);
135601377453SJohannes Doerfert ASSERT_NE(FnH1, nullptr);
135701377453SJohannes Doerfert ASSERT_NE(FnH2, nullptr);
135801377453SJohannes Doerfert ASSERT_NE(FnH3, nullptr);
135901377453SJohannes Doerfert
136001377453SJohannes Doerfert // And insert a call to `h1`, `h2`, and `h3`.
136101377453SJohannes Doerfert Instruction *IP = &FnH2->getEntryBlock().front();
136201377453SJohannes Doerfert (void)CallInst::Create(FnH1, {}, "", IP);
136301377453SJohannes Doerfert (void)CallInst::Create(FnH2, {}, "", IP);
136401377453SJohannes Doerfert (void)CallInst::Create(FnH3, {}, "", IP);
136501377453SJohannes Doerfert
136601377453SJohannes Doerfert auto &H2N = *llvm::find_if(
136701377453SJohannes Doerfert C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; });
136801377453SJohannes Doerfert ASSERT_NO_FATAL_FAILURE(
1369bd541b21SAlina Sbirlea updateCGAndAnalysisManagerForCGSCCPass(CG, C, H2N, AM, UR, FAM));
137001377453SJohannes Doerfert }));
137101377453SJohannes Doerfert
137234a8a437SArthur Eubanks ModulePassManager MPM;
137301377453SJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
137401377453SJohannes Doerfert MPM.run(*M, MAM);
137501377453SJohannes Doerfert }
137601377453SJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses1)137701377453SJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses1) {
137834a8a437SArthur Eubanks CGSCCPassManager CGPM;
137901377453SJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C,
138001377453SJohannes Doerfert CGSCCAnalysisManager &AM,
138101377453SJohannes Doerfert LazyCallGraph &CG,
138201377453SJohannes Doerfert CGSCCUpdateResult &UR) {
138301377453SJohannes Doerfert if (C.getName() != "(h3, h1, h2)")
138401377453SJohannes Doerfert return;
138501377453SJohannes Doerfert
1386bd541b21SAlina Sbirlea auto &FAM =
1387bd541b21SAlina Sbirlea AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
138801377453SJohannes Doerfert Function *FnX = M->getFunction("x");
138901377453SJohannes Doerfert Function *FnH1 = M->getFunction("h1");
139001377453SJohannes Doerfert Function *FnH2 = M->getFunction("h2");
139101377453SJohannes Doerfert Function *FnH3 = M->getFunction("h3");
139201377453SJohannes Doerfert ASSERT_NE(FnX, nullptr);
139301377453SJohannes Doerfert ASSERT_NE(FnH1, nullptr);
139401377453SJohannes Doerfert ASSERT_NE(FnH2, nullptr);
139501377453SJohannes Doerfert ASSERT_NE(FnH3, nullptr);
139601377453SJohannes Doerfert
139701377453SJohannes Doerfert // And insert a call to `h1`, `h2`, and `h3`.
139801377453SJohannes Doerfert Instruction *IP = &FnH2->getEntryBlock().front();
139901377453SJohannes Doerfert (void)CallInst::Create(FnH1, {}, "", IP);
140001377453SJohannes Doerfert (void)CallInst::Create(FnH2, {}, "", IP);
140101377453SJohannes Doerfert (void)CallInst::Create(FnH3, {}, "", IP);
140201377453SJohannes Doerfert
140301377453SJohannes Doerfert auto &H2N = *llvm::find_if(
140401377453SJohannes Doerfert C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; });
1405bd541b21SAlina Sbirlea ASSERT_DEATH(
1406bd541b21SAlina Sbirlea updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM),
140701377453SJohannes Doerfert "Any new calls should be modeled as");
140801377453SJohannes Doerfert }));
140901377453SJohannes Doerfert
141034a8a437SArthur Eubanks ModulePassManager MPM;
141101377453SJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
141201377453SJohannes Doerfert MPM.run(*M, MAM);
141301377453SJohannes Doerfert }
141401377453SJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses2)141501377453SJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses2) {
141634a8a437SArthur Eubanks CGSCCPassManager CGPM;
141701377453SJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve(
141801377453SJohannes Doerfert [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
141901377453SJohannes Doerfert CGSCCUpdateResult &UR) {
142001377453SJohannes Doerfert if (C.getName() != "(f)")
142101377453SJohannes Doerfert return;
142201377453SJohannes Doerfert
1423bd541b21SAlina Sbirlea auto &FAM =
1424bd541b21SAlina Sbirlea AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
142501377453SJohannes Doerfert Function *FnF = M->getFunction("f");
142601377453SJohannes Doerfert Function *FnH2 = M->getFunction("h2");
142701377453SJohannes Doerfert ASSERT_NE(FnF, nullptr);
142801377453SJohannes Doerfert ASSERT_NE(FnH2, nullptr);
142901377453SJohannes Doerfert
143001377453SJohannes Doerfert // And insert a call to `h2`
143101377453SJohannes Doerfert Instruction *IP = &FnF->getEntryBlock().front();
143201377453SJohannes Doerfert (void)CallInst::Create(FnH2, {}, "", IP);
143301377453SJohannes Doerfert
143401377453SJohannes Doerfert auto &FN = *llvm::find_if(
143501377453SJohannes Doerfert C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; });
143601377453SJohannes Doerfert ASSERT_NO_FATAL_FAILURE(
1437bd541b21SAlina Sbirlea updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR, FAM));
143801377453SJohannes Doerfert }));
143901377453SJohannes Doerfert
144034a8a437SArthur Eubanks ModulePassManager MPM;
144101377453SJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
144201377453SJohannes Doerfert MPM.run(*M, MAM);
144301377453SJohannes Doerfert }
144401377453SJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses3)144501377453SJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses3) {
144634a8a437SArthur Eubanks CGSCCPassManager CGPM;
144701377453SJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C,
144801377453SJohannes Doerfert CGSCCAnalysisManager &AM,
144901377453SJohannes Doerfert LazyCallGraph &CG,
145001377453SJohannes Doerfert CGSCCUpdateResult &UR) {
145101377453SJohannes Doerfert if (C.getName() != "(f)")
145201377453SJohannes Doerfert return;
145301377453SJohannes Doerfert
1454bd541b21SAlina Sbirlea auto &FAM =
1455bd541b21SAlina Sbirlea AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
145601377453SJohannes Doerfert Function *FnF = M->getFunction("f");
145701377453SJohannes Doerfert Function *FnH2 = M->getFunction("h2");
145801377453SJohannes Doerfert ASSERT_NE(FnF, nullptr);
145901377453SJohannes Doerfert ASSERT_NE(FnH2, nullptr);
146001377453SJohannes Doerfert
146101377453SJohannes Doerfert // And insert a call to `h2`
146201377453SJohannes Doerfert Instruction *IP = &FnF->getEntryBlock().front();
146301377453SJohannes Doerfert (void)CallInst::Create(FnH2, {}, "", IP);
146401377453SJohannes Doerfert
146501377453SJohannes Doerfert auto &FN = *llvm::find_if(
146601377453SJohannes Doerfert C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; });
1467bd541b21SAlina Sbirlea ASSERT_DEATH(
1468bd541b21SAlina Sbirlea updateCGAndAnalysisManagerForFunctionPass(CG, C, FN, AM, UR, FAM),
146901377453SJohannes Doerfert "Any new calls should be modeled as");
147001377453SJohannes Doerfert }));
147101377453SJohannes Doerfert
147234a8a437SArthur Eubanks ModulePassManager MPM;
147301377453SJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
147401377453SJohannes Doerfert MPM.run(*M, MAM);
147501377453SJohannes Doerfert }
147601377453SJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses4)147772277ecdSJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses4) {
147834a8a437SArthur Eubanks CGSCCPassManager CGPM;
147972277ecdSJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve(
148072277ecdSJohannes Doerfert [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
148172277ecdSJohannes Doerfert CGSCCUpdateResult &UR) {
148272277ecdSJohannes Doerfert if (C.getName() != "(f)")
148372277ecdSJohannes Doerfert return;
148472277ecdSJohannes Doerfert
1485bd541b21SAlina Sbirlea auto &FAM =
1486bd541b21SAlina Sbirlea AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
148772277ecdSJohannes Doerfert Function *FnF = M->getFunction("f");
148872277ecdSJohannes Doerfert Function *FnewF = Function::Create(FnF->getFunctionType(),
148972277ecdSJohannes Doerfert FnF->getLinkage(), "newF", *M);
149072277ecdSJohannes Doerfert BasicBlock *BB = BasicBlock::Create(FnewF->getContext(), "", FnewF);
149172277ecdSJohannes Doerfert ReturnInst::Create(FnewF->getContext(), BB);
149272277ecdSJohannes Doerfert
14937fea561eSArthur Eubanks // And insert a call to `newF`
14947fea561eSArthur Eubanks Instruction *IP = &FnF->getEntryBlock().front();
14957fea561eSArthur Eubanks (void)CallInst::Create(FnewF, {}, "", IP);
14967fea561eSArthur Eubanks
149772277ecdSJohannes Doerfert // Use the CallGraphUpdater to update the call graph for the new
149872277ecdSJohannes Doerfert // function.
149972277ecdSJohannes Doerfert CallGraphUpdater CGU;
150072277ecdSJohannes Doerfert CGU.initialize(CG, C, AM, UR);
15017fea561eSArthur Eubanks CGU.registerOutlinedFunction(*FnF, *FnewF);
150272277ecdSJohannes Doerfert
150372277ecdSJohannes Doerfert auto &FN = *llvm::find_if(
150472277ecdSJohannes Doerfert C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; });
150572277ecdSJohannes Doerfert
150672277ecdSJohannes Doerfert ASSERT_NO_FATAL_FAILURE(
1507bd541b21SAlina Sbirlea updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR, FAM));
150872277ecdSJohannes Doerfert }));
150972277ecdSJohannes Doerfert
151034a8a437SArthur Eubanks ModulePassManager MPM;
151172277ecdSJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
151272277ecdSJohannes Doerfert MPM.run(*M, MAM);
151372277ecdSJohannes Doerfert }
151472277ecdSJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses5)151572277ecdSJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses5) {
151634a8a437SArthur Eubanks CGSCCPassManager CGPM;
151772277ecdSJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C,
151872277ecdSJohannes Doerfert CGSCCAnalysisManager &AM,
151972277ecdSJohannes Doerfert LazyCallGraph &CG,
152072277ecdSJohannes Doerfert CGSCCUpdateResult &UR) {
152172277ecdSJohannes Doerfert if (C.getName() != "(f)")
152272277ecdSJohannes Doerfert return;
152372277ecdSJohannes Doerfert
1524bd541b21SAlina Sbirlea auto &FAM =
1525bd541b21SAlina Sbirlea AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
152672277ecdSJohannes Doerfert Function *FnF = M->getFunction("f");
152772277ecdSJohannes Doerfert Function *FnewF =
152872277ecdSJohannes Doerfert Function::Create(FnF->getFunctionType(), FnF->getLinkage(), "newF", *M);
152972277ecdSJohannes Doerfert BasicBlock *BB = BasicBlock::Create(FnewF->getContext(), "", FnewF);
153072277ecdSJohannes Doerfert ReturnInst::Create(FnewF->getContext(), BB);
153172277ecdSJohannes Doerfert
153272277ecdSJohannes Doerfert // Use the CallGraphUpdater to update the call graph for the new
153372277ecdSJohannes Doerfert // function.
153472277ecdSJohannes Doerfert CallGraphUpdater CGU;
153572277ecdSJohannes Doerfert CGU.initialize(CG, C, AM, UR);
153672277ecdSJohannes Doerfert
153772277ecdSJohannes Doerfert // And insert a call to `newF`
153872277ecdSJohannes Doerfert Instruction *IP = &FnF->getEntryBlock().front();
153972277ecdSJohannes Doerfert (void)CallInst::Create(FnewF, {}, "", IP);
154072277ecdSJohannes Doerfert
154172277ecdSJohannes Doerfert auto &FN = *llvm::find_if(
154272277ecdSJohannes Doerfert C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; });
154372277ecdSJohannes Doerfert
15447fea561eSArthur Eubanks ASSERT_DEATH(updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR, FAM),
15457fea561eSArthur Eubanks "should already have an associated node");
154672277ecdSJohannes Doerfert }));
154772277ecdSJohannes Doerfert
154834a8a437SArthur Eubanks ModulePassManager MPM;
154972277ecdSJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
155072277ecdSJohannes Doerfert MPM.run(*M, MAM);
155172277ecdSJohannes Doerfert }
155272277ecdSJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses6)155372277ecdSJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses6) {
155434a8a437SArthur Eubanks CGSCCPassManager CGPM;
155572277ecdSJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve(
155672277ecdSJohannes Doerfert [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
155772277ecdSJohannes Doerfert CGSCCUpdateResult &UR) {
155872277ecdSJohannes Doerfert if (C.getName() != "(h3, h1, h2)")
155972277ecdSJohannes Doerfert return;
156072277ecdSJohannes Doerfert
156172277ecdSJohannes Doerfert Function *FnX = M->getFunction("x");
156272277ecdSJohannes Doerfert Function *FnH1 = M->getFunction("h1");
156372277ecdSJohannes Doerfert Function *FnH2 = M->getFunction("h2");
156472277ecdSJohannes Doerfert Function *FnH3 = M->getFunction("h3");
156572277ecdSJohannes Doerfert ASSERT_NE(FnX, nullptr);
156672277ecdSJohannes Doerfert ASSERT_NE(FnH1, nullptr);
156772277ecdSJohannes Doerfert ASSERT_NE(FnH2, nullptr);
156872277ecdSJohannes Doerfert ASSERT_NE(FnH3, nullptr);
156972277ecdSJohannes Doerfert
157072277ecdSJohannes Doerfert // And insert a call to `h1`, `h2`, and `h3`.
157172277ecdSJohannes Doerfert Instruction *IP = &FnH2->getEntryBlock().front();
157272277ecdSJohannes Doerfert (void)CallInst::Create(FnH1, {}, "", IP);
157372277ecdSJohannes Doerfert (void)CallInst::Create(FnH2, {}, "", IP);
157472277ecdSJohannes Doerfert (void)CallInst::Create(FnH3, {}, "", IP);
157572277ecdSJohannes Doerfert
157672277ecdSJohannes Doerfert // Use the CallGraphUpdater to update the call graph for the new
157772277ecdSJohannes Doerfert // function.
157872277ecdSJohannes Doerfert CallGraphUpdater CGU;
157972277ecdSJohannes Doerfert CGU.initialize(CG, C, AM, UR);
158072277ecdSJohannes Doerfert ASSERT_NO_FATAL_FAILURE(CGU.reanalyzeFunction(*FnH2));
158172277ecdSJohannes Doerfert }));
158272277ecdSJohannes Doerfert
158334a8a437SArthur Eubanks ModulePassManager MPM;
158472277ecdSJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
158572277ecdSJohannes Doerfert MPM.run(*M, MAM);
158672277ecdSJohannes Doerfert }
158772277ecdSJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses7)158872277ecdSJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses7) {
158934a8a437SArthur Eubanks CGSCCPassManager CGPM;
159072277ecdSJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve(
159172277ecdSJohannes Doerfert [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
159272277ecdSJohannes Doerfert CGSCCUpdateResult &UR) {
159372277ecdSJohannes Doerfert if (C.getName() != "(f)")
159472277ecdSJohannes Doerfert return;
159572277ecdSJohannes Doerfert
159672277ecdSJohannes Doerfert Function *FnF = M->getFunction("f");
159772277ecdSJohannes Doerfert Function *FnH2 = M->getFunction("h2");
159872277ecdSJohannes Doerfert ASSERT_NE(FnF, nullptr);
159972277ecdSJohannes Doerfert ASSERT_NE(FnH2, nullptr);
160072277ecdSJohannes Doerfert
160172277ecdSJohannes Doerfert // And insert a call to `h2`
160272277ecdSJohannes Doerfert Instruction *IP = &FnF->getEntryBlock().front();
160372277ecdSJohannes Doerfert (void)CallInst::Create(FnH2, {}, "", IP);
160472277ecdSJohannes Doerfert
160572277ecdSJohannes Doerfert // Use the CallGraphUpdater to update the call graph for the new
160672277ecdSJohannes Doerfert // function.
160772277ecdSJohannes Doerfert CallGraphUpdater CGU;
160872277ecdSJohannes Doerfert CGU.initialize(CG, C, AM, UR);
160972277ecdSJohannes Doerfert ASSERT_NO_FATAL_FAILURE(CGU.reanalyzeFunction(*FnF));
161072277ecdSJohannes Doerfert }));
161172277ecdSJohannes Doerfert
161234a8a437SArthur Eubanks ModulePassManager MPM;
161372277ecdSJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
161472277ecdSJohannes Doerfert MPM.run(*M, MAM);
161572277ecdSJohannes Doerfert }
161672277ecdSJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses8)161772277ecdSJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses8) {
161834a8a437SArthur Eubanks CGSCCPassManager CGPM;
161972277ecdSJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve(
162072277ecdSJohannes Doerfert [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
162172277ecdSJohannes Doerfert CGSCCUpdateResult &UR) {
162272277ecdSJohannes Doerfert if (C.getName() != "(f)")
162372277ecdSJohannes Doerfert return;
162472277ecdSJohannes Doerfert
162572277ecdSJohannes Doerfert Function *FnF = M->getFunction("f");
162672277ecdSJohannes Doerfert Function *FnewF = Function::Create(FnF->getFunctionType(),
162772277ecdSJohannes Doerfert FnF->getLinkage(), "newF", *M);
162872277ecdSJohannes Doerfert BasicBlock *BB = BasicBlock::Create(FnewF->getContext(), "", FnewF);
162972277ecdSJohannes Doerfert auto *RI = ReturnInst::Create(FnewF->getContext(), BB);
163072277ecdSJohannes Doerfert while (FnF->getEntryBlock().size() > 1)
163172277ecdSJohannes Doerfert FnF->getEntryBlock().front().moveBefore(RI);
163272277ecdSJohannes Doerfert ASSERT_NE(FnF, nullptr);
163372277ecdSJohannes Doerfert
1634cb0ecc5cSJohannes Doerfert // Create an unsused constant that is referencing the old (=replaced)
1635cb0ecc5cSJohannes Doerfert // function.
1636cb0ecc5cSJohannes Doerfert ConstantExpr::getBitCast(FnF, Type::getInt8PtrTy(FnF->getContext()));
1637cb0ecc5cSJohannes Doerfert
163872277ecdSJohannes Doerfert // Use the CallGraphUpdater to update the call graph.
163972277ecdSJohannes Doerfert CallGraphUpdater CGU;
164072277ecdSJohannes Doerfert CGU.initialize(CG, C, AM, UR);
164172277ecdSJohannes Doerfert ASSERT_NO_FATAL_FAILURE(CGU.replaceFunctionWith(*FnF, *FnewF));
164272277ecdSJohannes Doerfert ASSERT_TRUE(FnF->isDeclaration());
164372277ecdSJohannes Doerfert ASSERT_EQ(FnF->getNumUses(), 0U);
164472277ecdSJohannes Doerfert }));
164572277ecdSJohannes Doerfert
164634a8a437SArthur Eubanks ModulePassManager MPM;
164772277ecdSJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
164872277ecdSJohannes Doerfert MPM.run(*M, MAM);
164972277ecdSJohannes Doerfert }
165072277ecdSJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses9)165172277ecdSJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses9) {
165234a8a437SArthur Eubanks CGSCCPassManager CGPM;
165372277ecdSJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve(
165472277ecdSJohannes Doerfert [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
165572277ecdSJohannes Doerfert CGSCCUpdateResult &UR) {
165672277ecdSJohannes Doerfert if (C.getName() != "(f)")
165772277ecdSJohannes Doerfert return;
165872277ecdSJohannes Doerfert
165972277ecdSJohannes Doerfert Function *FnF = M->getFunction("f");
166072277ecdSJohannes Doerfert
166172277ecdSJohannes Doerfert // Use the CallGraphUpdater to update the call graph.
166272277ecdSJohannes Doerfert {
166372277ecdSJohannes Doerfert CallGraphUpdater CGU;
166472277ecdSJohannes Doerfert CGU.initialize(CG, C, AM, UR);
166572277ecdSJohannes Doerfert ASSERT_NO_FATAL_FAILURE(CGU.removeFunction(*FnF));
166672277ecdSJohannes Doerfert ASSERT_EQ(M->getFunctionList().size(), 6U);
166772277ecdSJohannes Doerfert }
166872277ecdSJohannes Doerfert ASSERT_EQ(M->getFunctionList().size(), 5U);
166972277ecdSJohannes Doerfert }));
167072277ecdSJohannes Doerfert
167134a8a437SArthur Eubanks ModulePassManager MPM;
167272277ecdSJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
167372277ecdSJohannes Doerfert MPM.run(*M, MAM);
167472277ecdSJohannes Doerfert }
167572277ecdSJohannes Doerfert
TEST_F(CGSCCPassManagerTest,TestUpdateCGAndAnalysisManagerForPasses10)167672277ecdSJohannes Doerfert TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses10) {
167734a8a437SArthur Eubanks CGSCCPassManager CGPM;
167872277ecdSJohannes Doerfert CGPM.addPass(LambdaSCCPassNoPreserve(
167972277ecdSJohannes Doerfert [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
168072277ecdSJohannes Doerfert CGSCCUpdateResult &UR) {
168172277ecdSJohannes Doerfert if (C.getName() != "(h3, h1, h2)")
168272277ecdSJohannes Doerfert return;
168372277ecdSJohannes Doerfert
168472277ecdSJohannes Doerfert Function *FnX = M->getFunction("x");
168572277ecdSJohannes Doerfert Function *FnH1 = M->getFunction("h1");
168672277ecdSJohannes Doerfert Function *FnH2 = M->getFunction("h2");
168772277ecdSJohannes Doerfert Function *FnH3 = M->getFunction("h3");
168872277ecdSJohannes Doerfert ASSERT_NE(FnX, nullptr);
168972277ecdSJohannes Doerfert ASSERT_NE(FnH1, nullptr);
169072277ecdSJohannes Doerfert ASSERT_NE(FnH2, nullptr);
169172277ecdSJohannes Doerfert ASSERT_NE(FnH3, nullptr);
169272277ecdSJohannes Doerfert
169372277ecdSJohannes Doerfert // And insert a call to `h1`, and `h3`.
169472277ecdSJohannes Doerfert Instruction *IP = &FnH1->getEntryBlock().front();
169572277ecdSJohannes Doerfert (void)CallInst::Create(FnH1, {}, "", IP);
169672277ecdSJohannes Doerfert (void)CallInst::Create(FnH3, {}, "", IP);
169772277ecdSJohannes Doerfert
169872277ecdSJohannes Doerfert // Remove the `h2` call.
169972277ecdSJohannes Doerfert ASSERT_TRUE(isa<CallBase>(IP));
170072277ecdSJohannes Doerfert ASSERT_EQ(cast<CallBase>(IP)->getCalledFunction(), FnH2);
170172277ecdSJohannes Doerfert IP->eraseFromParent();
170272277ecdSJohannes Doerfert
170372277ecdSJohannes Doerfert // Use the CallGraphUpdater to update the call graph.
170472277ecdSJohannes Doerfert CallGraphUpdater CGU;
170572277ecdSJohannes Doerfert CGU.initialize(CG, C, AM, UR);
170672277ecdSJohannes Doerfert ASSERT_NO_FATAL_FAILURE(CGU.reanalyzeFunction(*FnH1));
170772277ecdSJohannes Doerfert ASSERT_NO_FATAL_FAILURE(CGU.removeFunction(*FnH2));
170872277ecdSJohannes Doerfert }));
170972277ecdSJohannes Doerfert
171034a8a437SArthur Eubanks ModulePassManager MPM;
171172277ecdSJohannes Doerfert MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
171272277ecdSJohannes Doerfert MPM.run(*M, MAM);
171372277ecdSJohannes Doerfert }
171472277ecdSJohannes Doerfert
17157529fab6SArthur Eubanks // Returns a vector containing the SCC's nodes. Useful for not iterating over an
17167529fab6SArthur Eubanks // SCC while mutating it.
SCCNodes(LazyCallGraph::SCC & C)17177529fab6SArthur Eubanks static SmallVector<LazyCallGraph::Node *> SCCNodes(LazyCallGraph::SCC &C) {
17187529fab6SArthur Eubanks SmallVector<LazyCallGraph::Node *> Nodes;
17197529fab6SArthur Eubanks for (auto &N : C)
17207529fab6SArthur Eubanks Nodes.push_back(&N);
17217529fab6SArthur Eubanks
17227529fab6SArthur Eubanks return Nodes;
17237529fab6SArthur Eubanks }
17247529fab6SArthur Eubanks
17254c8c6368SArthur Eubanks // Start with call recursive f, create f -> g and ref recursive f.
TEST_F(CGSCCPassManagerTest,TestInsertionOfNewFunctions1)17264c8c6368SArthur Eubanks TEST_F(CGSCCPassManagerTest, TestInsertionOfNewFunctions1) {
172726f35635SBrian Gesiak std::unique_ptr<Module> M = parseIR("define void @f() {\n"
172826f35635SBrian Gesiak "entry:\n"
172926f35635SBrian Gesiak " call void @f()\n"
173026f35635SBrian Gesiak " ret void\n"
173126f35635SBrian Gesiak "}\n");
173226f35635SBrian Gesiak
17334c8c6368SArthur Eubanks bool Ran = false;
17344c8c6368SArthur Eubanks
173534a8a437SArthur Eubanks CGSCCPassManager CGPM;
173626f35635SBrian Gesiak CGPM.addPass(LambdaSCCPassNoPreserve(
173726f35635SBrian Gesiak [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
173826f35635SBrian Gesiak CGSCCUpdateResult &UR) {
17394c8c6368SArthur Eubanks if (Ran)
17404c8c6368SArthur Eubanks return;
17414c8c6368SArthur Eubanks
1742bd541b21SAlina Sbirlea auto &FAM =
1743bd541b21SAlina Sbirlea AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
1744bd541b21SAlina Sbirlea
17457529fab6SArthur Eubanks for (LazyCallGraph::Node *N : SCCNodes(C)) {
17464c8c6368SArthur Eubanks Function &F = N->getFunction();
174726f35635SBrian Gesiak if (F.getName() != "f")
174826f35635SBrian Gesiak continue;
174926f35635SBrian Gesiak
175026f35635SBrian Gesiak // Create a new function 'g'.
175126f35635SBrian Gesiak auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
175226f35635SBrian Gesiak F.getAddressSpace(), "g", F.getParent());
17534c8c6368SArthur Eubanks auto *GBB =
175426f35635SBrian Gesiak BasicBlock::Create(F.getParent()->getContext(), "entry", G);
17554c8c6368SArthur Eubanks (void)ReturnInst::Create(G->getContext(), GBB);
175626f35635SBrian Gesiak // Instruct the LazyCallGraph to create a new node for 'g', as the
175726f35635SBrian Gesiak // single node in a new SCC, into the call graph. As a result
175826f35635SBrian Gesiak // the call graph is composed of a single RefSCC with two SCCs:
175926f35635SBrian Gesiak // [(f), (g)].
176026f35635SBrian Gesiak
17614c8c6368SArthur Eubanks // "Demote" the 'f -> f' call edge to a ref edge.
176226f35635SBrian Gesiak // 1. Erase the call edge from 'f' to 'f'.
17634c8c6368SArthur Eubanks F.getEntryBlock().front().eraseFromParent();
176426f35635SBrian Gesiak // 2. Insert a ref edge from 'f' to 'f'.
17654c8c6368SArthur Eubanks (void)CastInst::CreatePointerCast(
17664c8c6368SArthur Eubanks &F, Type::getInt8PtrTy(F.getContext()), "f.ref",
17674c8c6368SArthur Eubanks &F.getEntryBlock().front());
17687fea561eSArthur Eubanks // 3. Insert a ref edge from 'f' to 'g'.
17697fea561eSArthur Eubanks (void)CastInst::CreatePointerCast(
17707fea561eSArthur Eubanks G, Type::getInt8PtrTy(F.getContext()), "g.ref",
17717fea561eSArthur Eubanks &F.getEntryBlock().front());
17727fea561eSArthur Eubanks
17737fea561eSArthur Eubanks CG.addSplitFunction(F, *G);
17744c8c6368SArthur Eubanks
17754c8c6368SArthur Eubanks ASSERT_FALSE(verifyModule(*F.getParent(), &errs()));
177626f35635SBrian Gesiak
177726f35635SBrian Gesiak ASSERT_NO_FATAL_FAILURE(
17784c8c6368SArthur Eubanks updateCGAndAnalysisManagerForCGSCCPass(CG, C, *N, AM, UR, FAM))
177926f35635SBrian Gesiak << "Updating the call graph with a demoted, self-referential "
178026f35635SBrian Gesiak "call edge 'f -> f', and a newly inserted ref edge 'f -> g', "
178126f35635SBrian Gesiak "caused a fatal failure";
17824c8c6368SArthur Eubanks
17834c8c6368SArthur Eubanks Ran = true;
178426f35635SBrian Gesiak }
178526f35635SBrian Gesiak }));
178626f35635SBrian Gesiak
178734a8a437SArthur Eubanks ModulePassManager MPM;
178826f35635SBrian Gesiak MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
178926f35635SBrian Gesiak MPM.run(*M, MAM);
17904c8c6368SArthur Eubanks ASSERT_TRUE(Ran);
179126f35635SBrian Gesiak }
179226f35635SBrian Gesiak
17937fea561eSArthur Eubanks // Start with f, end with f -> g1, f -> g2, and f -ref-> (h1 <-ref-> h2).
TEST_F(CGSCCPassManagerTest,TestInsertionOfNewFunctions2)17944c8c6368SArthur Eubanks TEST_F(CGSCCPassManagerTest, TestInsertionOfNewFunctions2) {
179591332c4dSArthur Eubanks std::unique_ptr<Module> M = parseIR("define void @f() {\n"
179691332c4dSArthur Eubanks "entry:\n"
179791332c4dSArthur Eubanks " ret void\n"
179891332c4dSArthur Eubanks "}\n");
179991332c4dSArthur Eubanks
18004c8c6368SArthur Eubanks bool Ran = false;
18014c8c6368SArthur Eubanks
180234a8a437SArthur Eubanks CGSCCPassManager CGPM;
180391332c4dSArthur Eubanks CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C,
180491332c4dSArthur Eubanks CGSCCAnalysisManager &AM,
180591332c4dSArthur Eubanks LazyCallGraph &CG,
180691332c4dSArthur Eubanks CGSCCUpdateResult &UR) {
18074c8c6368SArthur Eubanks if (Ran)
18084c8c6368SArthur Eubanks return;
18094c8c6368SArthur Eubanks
181091332c4dSArthur Eubanks auto &FAM =
181191332c4dSArthur Eubanks AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
181291332c4dSArthur Eubanks
18137529fab6SArthur Eubanks for (LazyCallGraph::Node *N : SCCNodes(C)) {
18144c8c6368SArthur Eubanks Function &F = N->getFunction();
181591332c4dSArthur Eubanks if (F.getName() != "f")
181691332c4dSArthur Eubanks continue;
181791332c4dSArthur Eubanks
18187fea561eSArthur Eubanks // Create g1 and g2.
18196b1ce83aSArthur Eubanks auto *G1 = Function::Create(F.getFunctionType(), F.getLinkage(),
18206b1ce83aSArthur Eubanks F.getAddressSpace(), "g1", F.getParent());
18216b1ce83aSArthur Eubanks auto *G2 = Function::Create(F.getFunctionType(), F.getLinkage(),
18226b1ce83aSArthur Eubanks F.getAddressSpace(), "g2", F.getParent());
18236b1ce83aSArthur Eubanks BasicBlock *G1BB =
18246b1ce83aSArthur Eubanks BasicBlock::Create(F.getParent()->getContext(), "entry", G1);
18256b1ce83aSArthur Eubanks BasicBlock *G2BB =
18266b1ce83aSArthur Eubanks BasicBlock::Create(F.getParent()->getContext(), "entry", G2);
18274c8c6368SArthur Eubanks (void)ReturnInst::Create(G1->getContext(), G1BB);
18286b1ce83aSArthur Eubanks (void)ReturnInst::Create(G2->getContext(), G2BB);
18296b1ce83aSArthur Eubanks
18306b1ce83aSArthur Eubanks // Add 'f -> g1' call edge.
18316b1ce83aSArthur Eubanks (void)CallInst::Create(G1, {}, "", &F.getEntryBlock().front());
18326b1ce83aSArthur Eubanks // Add 'f -> g2' call edge.
18336b1ce83aSArthur Eubanks (void)CallInst::Create(G2, {}, "", &F.getEntryBlock().front());
18346b1ce83aSArthur Eubanks
18357fea561eSArthur Eubanks CG.addSplitFunction(F, *G1);
18367fea561eSArthur Eubanks CG.addSplitFunction(F, *G2);
18377fea561eSArthur Eubanks
183891332c4dSArthur Eubanks // Create mutually recursive functions (ref only) 'h1' and 'h2'.
183991332c4dSArthur Eubanks auto *H1 = Function::Create(F.getFunctionType(), F.getLinkage(),
184091332c4dSArthur Eubanks F.getAddressSpace(), "h1", F.getParent());
184191332c4dSArthur Eubanks auto *H2 = Function::Create(F.getFunctionType(), F.getLinkage(),
184291332c4dSArthur Eubanks F.getAddressSpace(), "h2", F.getParent());
184391332c4dSArthur Eubanks BasicBlock *H1BB =
184491332c4dSArthur Eubanks BasicBlock::Create(F.getParent()->getContext(), "entry", H1);
184591332c4dSArthur Eubanks BasicBlock *H2BB =
184691332c4dSArthur Eubanks BasicBlock::Create(F.getParent()->getContext(), "entry", H2);
184791332c4dSArthur Eubanks (void)CastInst::CreatePointerCast(H2, Type::getInt8PtrTy(F.getContext()),
184891332c4dSArthur Eubanks "h2.ref", H1BB);
184991332c4dSArthur Eubanks (void)ReturnInst::Create(H1->getContext(), H1BB);
185091332c4dSArthur Eubanks (void)CastInst::CreatePointerCast(H1, Type::getInt8PtrTy(F.getContext()),
185191332c4dSArthur Eubanks "h1.ref", H2BB);
185291332c4dSArthur Eubanks (void)ReturnInst::Create(H2->getContext(), H2BB);
185391332c4dSArthur Eubanks
185491332c4dSArthur Eubanks // Add 'f -> h1' ref edge.
185591332c4dSArthur Eubanks (void)CastInst::CreatePointerCast(H1, Type::getInt8PtrTy(F.getContext()),
18566b1ce83aSArthur Eubanks "h1.ref", &F.getEntryBlock().front());
18576b1ce83aSArthur Eubanks // Add 'f -> h2' ref edge.
18586b1ce83aSArthur Eubanks (void)CastInst::CreatePointerCast(H2, Type::getInt8PtrTy(F.getContext()),
18596b1ce83aSArthur Eubanks "h2.ref", &F.getEntryBlock().front());
186091332c4dSArthur Eubanks
18617fea561eSArthur Eubanks CG.addSplitRefRecursiveFunctions(F, SmallVector<Function *, 2>({H1, H2}));
18627fea561eSArthur Eubanks
18634c8c6368SArthur Eubanks ASSERT_FALSE(verifyModule(*F.getParent(), &errs()));
18644c8c6368SArthur Eubanks
186591332c4dSArthur Eubanks ASSERT_NO_FATAL_FAILURE(
18664c8c6368SArthur Eubanks updateCGAndAnalysisManagerForCGSCCPass(CG, C, *N, AM, UR, FAM))
18676b1ce83aSArthur Eubanks << "Updating the call graph with mutually recursive g1 <-> g2, h1 "
18686b1ce83aSArthur Eubanks "<-> h2 caused a fatal failure";
18694c8c6368SArthur Eubanks
18704c8c6368SArthur Eubanks Ran = true;
187191332c4dSArthur Eubanks }
187291332c4dSArthur Eubanks }));
187391332c4dSArthur Eubanks
187434a8a437SArthur Eubanks ModulePassManager MPM;
187591332c4dSArthur Eubanks MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
187691332c4dSArthur Eubanks MPM.run(*M, MAM);
18774c8c6368SArthur Eubanks ASSERT_TRUE(Ran);
187891332c4dSArthur Eubanks }
187991332c4dSArthur Eubanks
TEST_F(CGSCCPassManagerTest,TestInsertionOfNewNonTrivialCallEdge)1880d9cbceb0SArthur Eubanks TEST_F(CGSCCPassManagerTest, TestInsertionOfNewNonTrivialCallEdge) {
1881d9cbceb0SArthur Eubanks std::unique_ptr<Module> M = parseIR("define void @f1() {\n"
1882d9cbceb0SArthur Eubanks "entry:\n"
1883d9cbceb0SArthur Eubanks " %a = bitcast void ()* @f4 to i8*\n"
1884d9cbceb0SArthur Eubanks " %b = bitcast void ()* @f2 to i8*\n"
1885d9cbceb0SArthur Eubanks " ret void\n"
1886d9cbceb0SArthur Eubanks "}\n"
1887d9cbceb0SArthur Eubanks "define void @f2() {\n"
1888d9cbceb0SArthur Eubanks "entry:\n"
1889d9cbceb0SArthur Eubanks " %a = bitcast void ()* @f1 to i8*\n"
1890d9cbceb0SArthur Eubanks " %b = bitcast void ()* @f3 to i8*\n"
1891d9cbceb0SArthur Eubanks " ret void\n"
1892d9cbceb0SArthur Eubanks "}\n"
1893d9cbceb0SArthur Eubanks "define void @f3() {\n"
1894d9cbceb0SArthur Eubanks "entry:\n"
1895d9cbceb0SArthur Eubanks " %a = bitcast void ()* @f2 to i8*\n"
1896d9cbceb0SArthur Eubanks " %b = bitcast void ()* @f4 to i8*\n"
1897d9cbceb0SArthur Eubanks " ret void\n"
1898d9cbceb0SArthur Eubanks "}\n"
1899d9cbceb0SArthur Eubanks "define void @f4() {\n"
1900d9cbceb0SArthur Eubanks "entry:\n"
1901d9cbceb0SArthur Eubanks " %a = bitcast void ()* @f3 to i8*\n"
1902d9cbceb0SArthur Eubanks " %b = bitcast void ()* @f1 to i8*\n"
1903d9cbceb0SArthur Eubanks " ret void\n"
1904d9cbceb0SArthur Eubanks "}\n");
1905d9cbceb0SArthur Eubanks
1906d9cbceb0SArthur Eubanks bool Ran = false;
190734a8a437SArthur Eubanks CGSCCPassManager CGPM;
1908d9cbceb0SArthur Eubanks CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C,
1909d9cbceb0SArthur Eubanks CGSCCAnalysisManager &AM,
1910d9cbceb0SArthur Eubanks LazyCallGraph &CG,
1911d9cbceb0SArthur Eubanks CGSCCUpdateResult &UR) {
1912d9cbceb0SArthur Eubanks if (Ran)
1913d9cbceb0SArthur Eubanks return;
1914d9cbceb0SArthur Eubanks
1915d9cbceb0SArthur Eubanks auto &FAM =
1916d9cbceb0SArthur Eubanks AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
1917d9cbceb0SArthur Eubanks
19187529fab6SArthur Eubanks for (LazyCallGraph::Node *N : SCCNodes(C)) {
19194c8c6368SArthur Eubanks Function &F = N->getFunction();
1920d9cbceb0SArthur Eubanks if (F.getName() != "f1")
1921d9cbceb0SArthur Eubanks continue;
1922d9cbceb0SArthur Eubanks
1923d9cbceb0SArthur Eubanks Function *F3 = F.getParent()->getFunction("f3");
1924d9cbceb0SArthur Eubanks ASSERT_TRUE(F3 != nullptr);
1925d9cbceb0SArthur Eubanks
1926d9cbceb0SArthur Eubanks // Create call from f1 to f3.
1927d9cbceb0SArthur Eubanks (void)CallInst::Create(F3, {}, "", F.getEntryBlock().getTerminator());
1928d9cbceb0SArthur Eubanks
1929d9cbceb0SArthur Eubanks ASSERT_NO_FATAL_FAILURE(
19304c8c6368SArthur Eubanks updateCGAndAnalysisManagerForCGSCCPass(CG, C, *N, AM, UR, FAM))
1931d9cbceb0SArthur Eubanks << "Updating the call graph with mutually recursive g1 <-> g2, h1 "
1932d9cbceb0SArthur Eubanks "<-> h2 caused a fatal failure";
1933d9cbceb0SArthur Eubanks
1934d9cbceb0SArthur Eubanks Ran = true;
1935d9cbceb0SArthur Eubanks }
1936d9cbceb0SArthur Eubanks }));
1937d9cbceb0SArthur Eubanks
193834a8a437SArthur Eubanks ModulePassManager MPM;
1939d9cbceb0SArthur Eubanks MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
1940d9cbceb0SArthur Eubanks MPM.run(*M, MAM);
1941d9cbceb0SArthur Eubanks
1942d9cbceb0SArthur Eubanks ASSERT_TRUE(Ran);
1943d9cbceb0SArthur Eubanks }
1944d9cbceb0SArthur Eubanks
TEST_F(CGSCCPassManagerTest,TestFunctionPassesAreQueriedForInvalidation)194592ccc6cbSMircea Trofin TEST_F(CGSCCPassManagerTest, TestFunctionPassesAreQueriedForInvalidation) {
194692ccc6cbSMircea Trofin std::unique_ptr<Module> M = parseIR("define void @f() { ret void }");
194792ccc6cbSMircea Trofin CGSCCPassManager CGPM;
194892ccc6cbSMircea Trofin bool SCCCalled = false;
194992ccc6cbSMircea Trofin FunctionPassManager FPM;
195092ccc6cbSMircea Trofin int ImmRuns = 0;
195192ccc6cbSMircea Trofin FAM.registerPass([&] { return TestImmutableFunctionAnalysis(ImmRuns); });
195292ccc6cbSMircea Trofin FPM.addPass(RequireAnalysisPass<TestImmutableFunctionAnalysis, Function>());
195392ccc6cbSMircea Trofin CGPM.addPass(
195492ccc6cbSMircea Trofin LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
195592ccc6cbSMircea Trofin LazyCallGraph &CG, CGSCCUpdateResult &UR) {
195692ccc6cbSMircea Trofin SCCCalled = true;
195792ccc6cbSMircea Trofin return PreservedAnalyses::none();
195892ccc6cbSMircea Trofin }));
195992ccc6cbSMircea Trofin CGPM.addPass(createCGSCCToFunctionPassAdaptor(
196092ccc6cbSMircea Trofin RequireAnalysisPass<TestImmutableFunctionAnalysis, Function>()));
196192ccc6cbSMircea Trofin ModulePassManager MPM;
196292ccc6cbSMircea Trofin
196392ccc6cbSMircea Trofin MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
196492ccc6cbSMircea Trofin MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
196592ccc6cbSMircea Trofin MPM.run(*M, MAM);
196692ccc6cbSMircea Trofin ASSERT_EQ(ImmRuns, 1);
196792ccc6cbSMircea Trofin ASSERT_TRUE(SCCCalled);
196892ccc6cbSMircea Trofin }
196992ccc6cbSMircea Trofin
197001377453SJohannes Doerfert #endif
197101377453SJohannes Doerfert } // namespace
1972