summaryrefslogtreecommitdiffstats
path: root/llvm/unittests/IR/PassManagerTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests/IR/PassManagerTest.cpp')
-rw-r--r--llvm/unittests/IR/PassManagerTest.cpp370
1 files changed, 327 insertions, 43 deletions
diff --git a/llvm/unittests/IR/PassManagerTest.cpp b/llvm/unittests/IR/PassManagerTest.cpp
index d7515ba6b7d..b3a039a364f 100644
--- a/llvm/unittests/IR/PassManagerTest.cpp
+++ b/llvm/unittests/IR/PassManagerTest.cpp
@@ -168,37 +168,224 @@ public:
"}\n")) {}
};
-TEST_F(PassManagerTest, BasicPreservedAnalyses) {
+TEST(PreservedAnalysesTest, Basic) {
PreservedAnalyses PA1 = PreservedAnalyses();
- EXPECT_FALSE(PA1.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA1.preserved<TestModuleAnalysis>());
- PreservedAnalyses PA2 = PreservedAnalyses::none();
- EXPECT_FALSE(PA2.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA2.preserved<TestModuleAnalysis>());
- PreservedAnalyses PA3 = PreservedAnalyses::all();
- EXPECT_TRUE(PA3.preserved<TestFunctionAnalysis>());
- EXPECT_TRUE(PA3.preserved<TestModuleAnalysis>());
+ {
+ auto PAC = PA1.getChecker<TestFunctionAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
+ {
+ auto PAC = PA1.getChecker<TestModuleAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>());
+ }
+ auto PA2 = PreservedAnalyses::none();
+ {
+ auto PAC = PA2.getChecker<TestFunctionAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
+ auto PA3 = PreservedAnalyses::all();
+ {
+ auto PAC = PA3.getChecker<TestFunctionAnalysis>();
+ EXPECT_TRUE(PAC.preserved());
+ EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
PreservedAnalyses PA4 = PA1;
- EXPECT_FALSE(PA4.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
+ {
+ auto PAC = PA4.getChecker<TestFunctionAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
PA4 = PA3;
- EXPECT_TRUE(PA4.preserved<TestFunctionAnalysis>());
- EXPECT_TRUE(PA4.preserved<TestModuleAnalysis>());
+ {
+ auto PAC = PA4.getChecker<TestFunctionAnalysis>();
+ EXPECT_TRUE(PAC.preserved());
+ EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
PA4 = std::move(PA2);
- EXPECT_FALSE(PA4.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
- PA4.preserve<TestFunctionAnalysis>();
- EXPECT_TRUE(PA4.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
- PA1.preserve<TestModuleAnalysis>();
- EXPECT_FALSE(PA1.preserved<TestFunctionAnalysis>());
- EXPECT_TRUE(PA1.preserved<TestModuleAnalysis>());
+ {
+ auto PAC = PA4.getChecker<TestFunctionAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
+}
+
+TEST(PreservedAnalysesTest, Preserve) {
+ auto PA = PreservedAnalyses::none();
+ PA.preserve<TestFunctionAnalysis>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());
+ PA.preserve<TestModuleAnalysis>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());
+
+ // Redundant calls are fine.
+ PA.preserve<TestFunctionAnalysis>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());
+}
+
+TEST(PreservedAnalysesTest, PreserveSets) {
+ auto PA = PreservedAnalyses::none();
+ PA.preserveSet<AllAnalysesOn<Function>>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+ PA.preserveSet<AllAnalysesOn<Module>>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Mixing is fine.
+ PA.preserve<TestFunctionAnalysis>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Redundant calls are fine.
+ PA.preserveSet<AllAnalysesOn<Module>>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+}
+
+TEST(PreservedAnalysisTest, Intersect) {
+ // Setup the initial sets.
+ auto PA1 = PreservedAnalyses::none();
PA1.preserve<TestFunctionAnalysis>();
- EXPECT_TRUE(PA1.preserved<TestFunctionAnalysis>());
- EXPECT_TRUE(PA1.preserved<TestModuleAnalysis>());
- PA1.intersect(PA4);
- EXPECT_TRUE(PA1.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA1.preserved<TestModuleAnalysis>());
+ PA1.preserveSet<AllAnalysesOn<Module>>();
+ auto PA2 = PreservedAnalyses::none();
+ PA2.preserve<TestFunctionAnalysis>();
+ PA2.preserveSet<AllAnalysesOn<Function>>();
+ PA2.preserve<TestModuleAnalysis>();
+ PA2.preserveSet<AllAnalysesOn<Module>>();
+ auto PA3 = PreservedAnalyses::none();
+ PA3.preserve<TestModuleAnalysis>();
+ PA3.preserveSet<AllAnalysesOn<Function>>();
+
+ // Self intersection is a no-op.
+ auto Intersected = PA1;
+ Intersected.intersect(PA1);
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting with all is a no-op.
+ Intersected.intersect(PreservedAnalyses::all());
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting a narrow set with a more broad set is the narrow set.
+ Intersected.intersect(PA2);
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting a broad set with a more narrow set is the narrow set.
+ Intersected = PA2;
+ Intersected.intersect(PA1);
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting with empty clears.
+ Intersected.intersect(PreservedAnalyses::none());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting non-overlapping clears.
+ Intersected = PA1;
+ Intersected.intersect(PA3);
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting with moves works in when there is storage on both sides.
+ Intersected = PA1;
+ auto Tmp = PA2;
+ Intersected.intersect(std::move(Tmp));
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting with move works for incoming all and existing all.
+ auto Tmp2 = PreservedAnalyses::all();
+ Intersected.intersect(std::move(Tmp2));
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+ Intersected = PreservedAnalyses::all();
+ auto Tmp3 = PA1;
+ Intersected.intersect(std::move(Tmp3));
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+}
+
+TEST(PreservedAnalysisTest, Abandon) {
+ auto PA = PreservedAnalyses::none();
+
+ // We can abandon things after they are preserved.
+ PA.preserve<TestFunctionAnalysis>();
+ PA.abandon<TestFunctionAnalysis>();
+ EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());
+
+ // Repeated is fine, and abandoning if they were never preserved is fine.
+ PA.abandon<TestFunctionAnalysis>();
+ EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());
+ PA.abandon<TestModuleAnalysis>();
+ EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());
+
+ // Even if the sets are preserved, the abandoned analyses' checker won't
+ // return true for those sets.
+ PA.preserveSet<AllAnalysesOn<Function>>();
+ PA.preserveSet<AllAnalysesOn<Module>>();
+ EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // But an arbitrary (opaque) analysis will still observe the sets as
+ // preserved. This also checks that we can use an explicit ID rather than
+ // a type.
+ AnalysisKey FakeKey, *FakeID = &FakeKey;
+ EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Module>>());
}
TEST_F(PassManagerTest, Basic) {
@@ -385,12 +572,16 @@ TEST_F(PassManagerTest, CustomizedPassManagerArgs) {
struct TestIndirectFunctionAnalysis
: public AnalysisInfoMixin<TestIndirectFunctionAnalysis> {
struct Result {
- Result(TestFunctionAnalysis::Result &Dep) : Dep(Dep) {}
- TestFunctionAnalysis::Result &Dep;
+ Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep)
+ : FDep(FDep), MDep(MDep) {}
+ TestFunctionAnalysis::Result &FDep;
+ TestModuleAnalysis::Result &MDep;
bool invalidate(Function &F, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &Inv) {
- return !PA.preserved<TestIndirectFunctionAnalysis>() ||
+ auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>();
+ return !(PAC.preserved() ||
+ PAC.preservedSet<AllAnalysesOn<Function>>()) ||
Inv.invalidate<TestFunctionAnalysis>(F, PA);
}
};
@@ -400,7 +591,17 @@ struct TestIndirectFunctionAnalysis
/// Run the analysis pass over the function and return a result.
Result run(Function &F, FunctionAnalysisManager &AM) {
++Runs;
- return Result(AM.getResult<TestFunctionAnalysis>(F));
+ auto &FDep = AM.getResult<TestFunctionAnalysis>(F);
+ auto &Proxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
+ const ModuleAnalysisManager &MAM = Proxy.getManager();
+ // For the test, we insist that the module analysis starts off in the
+ // cache.
+ auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());
+ // And register the dependency as module analysis dependencies have to be
+ // pre-registered on the proxy.
+ Proxy.registerOuterAnalysisInvalidation<TestModuleAnalysis,
+ TestIndirectFunctionAnalysis>();
+ return Result(FDep, MDep);
}
private:
@@ -412,6 +613,46 @@ private:
AnalysisKey TestIndirectFunctionAnalysis::Key;
+/// A test analysis pass which chaches in its result the result from the above
+/// indirect analysis pass.
+///
+/// This allows us to ensure that whenever an analysis pass is invalidated due
+/// to dependencies (especially dependencies across IR units that trigger
+/// asynchronous invalidation) we correctly detect that this may in turn cause
+/// other analysis to be invalidated.
+struct TestDoublyIndirectFunctionAnalysis
+ : public AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis> {
+ struct Result {
+ Result(TestIndirectFunctionAnalysis::Result &IDep) : IDep(IDep) {}
+ TestIndirectFunctionAnalysis::Result &IDep;
+
+ bool invalidate(Function &F, const PreservedAnalyses &PA,
+ FunctionAnalysisManager::Invalidator &Inv) {
+ auto PAC = PA.getChecker<TestDoublyIndirectFunctionAnalysis>();
+ return !(PAC.preserved() ||
+ PAC.preservedSet<AllAnalysesOn<Function>>()) ||
+ Inv.invalidate<TestIndirectFunctionAnalysis>(F, PA);
+ }
+ };
+
+ TestDoublyIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}
+
+ /// Run the analysis pass over the function and return a result.
+ Result run(Function &F, FunctionAnalysisManager &AM) {
+ ++Runs;
+ auto &IDep = AM.getResult<TestIndirectFunctionAnalysis>(F);
+ return Result(IDep);
+ }
+
+private:
+ friend AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis>;
+ static AnalysisKey Key;
+
+ int &Runs;
+};
+
+AnalysisKey TestDoublyIndirectFunctionAnalysis::Key;
+
struct LambdaPass : public PassInfoMixin<LambdaPass> {
using FuncT = std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)>;
@@ -426,23 +667,31 @@ struct LambdaPass : public PassInfoMixin<LambdaPass> {
TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {
FunctionAnalysisManager FAM(/*DebugLogging*/ true);
- int AnalysisRuns = 0, IndirectAnalysisRuns = 0;
- FAM.registerPass([&] { return TestFunctionAnalysis(AnalysisRuns); });
+ int FunctionAnalysisRuns = 0, ModuleAnalysisRuns = 0,
+ IndirectAnalysisRuns = 0, DoublyIndirectAnalysisRuns = 0;
+ FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
FAM.registerPass(
[&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns); });
+ FAM.registerPass([&] {
+ return TestDoublyIndirectFunctionAnalysis(DoublyIndirectAnalysisRuns);
+ });
ModuleAnalysisManager MAM(/*DebugLogging*/ true);
+ MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
- int InstrCount = 0;
+ int InstrCount = 0, FunctionCount = 0;
ModulePassManager MPM(/*DebugLogging*/ true);
FunctionPassManager FPM(/*DebugLogging*/ true);
// First just use the analysis to get the instruction count, and preserve
// everything.
FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
- InstrCount +=
- AM.getResult<TestIndirectFunctionAnalysis>(F).Dep.InstructionCount;
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ InstrCount += IndirectResult.FDep.InstructionCount;
+ FunctionCount += IndirectResult.MDep.FunctionCount;
return PreservedAnalyses::all();
}));
// Next, invalidate
@@ -450,8 +699,11 @@ TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {
// - just the underlying (indirect) analysis for "g", and
// - just the direct analysis for "h".
FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
- InstrCount +=
- AM.getResult<TestIndirectFunctionAnalysis>(F).Dep.InstructionCount;
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ InstrCount += IndirectResult.FDep.InstructionCount;
+ FunctionCount += IndirectResult.MDep.FunctionCount;
auto PA = PreservedAnalyses::none();
if (F.getName() == "g")
PA.preserve<TestFunctionAnalysis>();
@@ -462,23 +714,55 @@ TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {
// Finally, use the analysis again on each function, forcing re-computation
// for all of them.
FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
- InstrCount +=
- AM.getResult<TestIndirectFunctionAnalysis>(F).Dep.InstructionCount;
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ InstrCount += IndirectResult.FDep.InstructionCount;
+ FunctionCount += IndirectResult.MDep.FunctionCount;
+ return PreservedAnalyses::all();
+ }));
+
+ // Create a second function pass manager. This will cause the module-level
+ // invalidation to occur, which will force yet another invalidation of the
+ // indirect function-level analysis as the module analysis it depends on gets
+ // invalidated.
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ FPM2.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ InstrCount += IndirectResult.FDep.InstructionCount;
+ FunctionCount += IndirectResult.MDep.FunctionCount;
return PreservedAnalyses::all();
}));
+
+ // Add a requires pass to populate the module analysis and then our function
+ // pass pipeline.
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
+ // Now require the module analysis again (it will have been invalidated once)
+ // and then use it again from a function pass manager.
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
+ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM2)));
MPM.run(*M, MAM);
// There are generally two possible runs for each of the three functions. But
// for one function, we only invalidate the indirect analysis so the base one
// only gets run five times.
- EXPECT_EQ(5, AnalysisRuns);
+ EXPECT_EQ(5, FunctionAnalysisRuns);
+ // The module analysis pass should be run twice here.
+ EXPECT_EQ(2, ModuleAnalysisRuns);
// The indirect analysis is invalidated for each function (either directly or
// indirectly) and run twice for each.
- EXPECT_EQ(6, IndirectAnalysisRuns);
+ EXPECT_EQ(9, IndirectAnalysisRuns);
+ EXPECT_EQ(9, DoublyIndirectAnalysisRuns);
- // There are five instructions in the module and we add the count three
+ // There are five instructions in the module and we add the count four
// times.
- EXPECT_EQ(5 * 3, InstrCount);
+ EXPECT_EQ(5 * 4, InstrCount);
+
+ // There are three functions and we count them four times for each of the
+ // three functions.
+ EXPECT_EQ(3 * 4 * 3, FunctionCount);
}
}
OpenPOWER on IntegriCloud