diff options
Diffstat (limited to 'unittests/Analysis')
-rw-r--r-- | unittests/Analysis/AliasAnalysisTest.cpp | 5 | ||||
-rw-r--r-- | unittests/Analysis/CGSCCPassManagerTest.cpp | 198 | ||||
-rw-r--r-- | unittests/Analysis/LazyCallGraphTest.cpp | 33 |
3 files changed, 212 insertions, 24 deletions
diff --git a/unittests/Analysis/AliasAnalysisTest.cpp b/unittests/Analysis/AliasAnalysisTest.cpp index 84a04257bc27..9a864b77a9d8 100644 --- a/unittests/Analysis/AliasAnalysisTest.cpp +++ b/unittests/Analysis/AliasAnalysisTest.cpp @@ -180,10 +180,11 @@ TEST_F(AliasAnalysisTest, getModRefInfo) { auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB); auto *CmpXChg1 = new AtomicCmpXchgInst( Addr, ConstantInt::get(IntType, 0), ConstantInt::get(IntType, 1), - AtomicOrdering::Monotonic, AtomicOrdering::Monotonic, CrossThread, BB); + AtomicOrdering::Monotonic, AtomicOrdering::Monotonic, + SyncScope::System, BB); auto *AtomicRMW = new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1), - AtomicOrdering::Monotonic, CrossThread, BB); + AtomicOrdering::Monotonic, SyncScope::System, BB); ReturnInst::Create(C, nullptr, BB); diff --git a/unittests/Analysis/CGSCCPassManagerTest.cpp b/unittests/Analysis/CGSCCPassManagerTest.cpp index ab5d1862c23e..d46d9535fa4b 100644 --- a/unittests/Analysis/CGSCCPassManagerTest.cpp +++ b/unittests/Analysis/CGSCCPassManagerTest.cpp @@ -680,6 +680,7 @@ TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunctionAnalysis) { LazyCallGraph &, CGSCCUpdateResult &) { PreservedAnalyses PA; PA.preserve<LazyCallGraphAnalysis>(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); PA.preserve<TestFunctionAnalysis>(); return PA; })); @@ -719,12 +720,14 @@ TEST_F(CGSCCPassManagerTest, CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); - // Now run a module pass that preserves the LazyCallGraph and proxy but not + // Now run a module pass that preserves the LazyCallGraph and proxies but not // the Function analysis. MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) { PreservedAnalyses PA; PA.preserve<LazyCallGraphAnalysis>(); PA.preserve<CGSCCAnalysisManagerModuleProxy>(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); + PA.preserve<FunctionAnalysisManagerModuleProxy>(); return PA; })); @@ -741,7 +744,7 @@ TEST_F(CGSCCPassManagerTest, EXPECT_EQ(2 * 6, FunctionAnalysisRuns); } -// Check that by marking the function pass and FAM proxy as preserved, this +// Check that by marking the function pass and proxies as preserved, this // propagates all the way through. TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC) { @@ -765,6 +768,7 @@ TEST_F(CGSCCPassManagerTest, PreservedAnalyses PA; PA.preserve<LazyCallGraphAnalysis>(); PA.preserve<CGSCCAnalysisManagerModuleProxy>(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); PA.preserve<FunctionAnalysisManagerModuleProxy>(); PA.preserve<TestFunctionAnalysis>(); return PA; @@ -1014,6 +1018,9 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { FunctionCount += IndirectResult.SCCDep.FunctionCount; return PreservedAnalyses::all(); })); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); + // Next, invalidate // - both analyses for the (f) and (x) SCCs, // - just the underlying (indirect) analysis for (g) SCC, and @@ -1026,14 +1033,16 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { auto &IndirectResult = DoublyIndirectResult.IDep; FunctionCount += IndirectResult.SCCDep.FunctionCount; auto PA = PreservedAnalyses::none(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); + PA.preserveSet<AllAnalysesOn<Function>>(); if (C.getName() == "(g)") PA.preserve<TestSCCAnalysis>(); else if (C.getName() == "(h3, h1, h2)") PA.preserve<TestIndirectSCCAnalysis>(); return PA; })); - // Finally, use the analysis again on each function, forcing re-computation - // for all of them. + // Finally, use the analysis again on each SCC (and function), forcing + // re-computation for all of them. CGPM.addPass( LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &) { @@ -1043,6 +1052,8 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { FunctionCount += IndirectResult.SCCDep.FunctionCount; return PreservedAnalyses::all(); })); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); // Create a second CGSCC pass manager. This will cause the module-level // invalidation to occur, which will force yet another invalidation of the @@ -1058,13 +1069,15 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { FunctionCount += IndirectResult.SCCDep.FunctionCount; return PreservedAnalyses::all(); })); + CGPM2.addPass(createCGSCCToFunctionPassAdaptor( + RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>())); - // Add a requires pass to populate the module analysis and then our function + // Add a requires pass to populate the module analysis and then our CGSCC // pass pipeline. MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); // Now require the module analysis again (it will have been invalidated once) - // and then use it again from a function pass manager. + // and then use it again from our second CGSCC pipeline.. MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); MPM.run(*M, MAM); @@ -1080,7 +1093,180 @@ TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) { EXPECT_EQ(3 * 4, IndirectSCCAnalysisRuns); EXPECT_EQ(3 * 4, DoublyIndirectSCCAnalysisRuns); + // We run the indirect function analysis once per function the first time. + // Then we re-run it for every SCC but "(g)". Then we re-run it for every + // function again. + EXPECT_EQ(6 + 5 + 6, IndirectFunctionAnalysisRuns); + // Four passes count each of six functions once (via SCCs). EXPECT_EQ(4 * 6, FunctionCount); } + +TEST_F(CGSCCPassManagerTest, TestAnalysisInvalidationCGSCCUpdate) { + int ModuleAnalysisRuns = 0; + MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); + + int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0, + DoublyIndirectSCCAnalysisRuns = 0; + CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); + CGAM.registerPass( + [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); }); + CGAM.registerPass([&] { + return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); + }); + + int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0; + FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); + FAM.registerPass([&] { + return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns); + }); + + ModulePassManager MPM(/*DebugLogging*/ true); + + CGSCCPassManager CGPM(/*DebugLogging*/ true); + // First just use the analysis to get the function count and preserve + // everything. + using RequireTestIndirectFunctionAnalysisPass = + RequireAnalysisPass<TestIndirectFunctionAnalysis, Function>; + using RequireTestDoublyIndirectSCCAnalysisPass = + RequireAnalysisPass<TestDoublyIndirectSCCAnalysis, LazyCallGraph::SCC, + CGSCCAnalysisManager, LazyCallGraph &, + CGSCCUpdateResult &>; + CGPM.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Next, we inject an SCC pass that invalidates everything for the `(h3, h1, + // h2)` SCC but also deletes the call edge from `h2` to `h3` and updates the + // CG. This should successfully invalidate (and force to be re-run) all the + // analyses for that SCC and for the functions. + CGPM.addPass( + LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, + LazyCallGraph &CG, CGSCCUpdateResult &UR) { + (void)AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); + if (C.getName() != "(h3, h1, h2)") + return PreservedAnalyses::all(); + + // Build the preserved set. + auto PA = PreservedAnalyses::none(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); + PA.preserve<TestIndirectSCCAnalysis>(); + PA.preserve<TestDoublyIndirectSCCAnalysis>(); + + // Delete the call from `h2` to `h3`. + auto &H2N = *llvm::find_if( + C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; }); + auto &H2F = H2N.getFunction(); + auto &H3F = *cast<CallInst>(H2F.begin()->begin())->getCalledFunction(); + assert(H3F.getName() == "h3" && "Wrong called function!"); + H2F.begin()->begin()->eraseFromParent(); + // Insert a bitcast of `h3` so that we retain a ref edge to it. + (void)CastInst::CreatePointerCast(&H3F, + Type::getInt8PtrTy(H2F.getContext()), + "dummy", &*H2F.begin()->begin()); + + // Now update the call graph. + auto &NewC = updateCGAndAnalysisManagerForFunctionPass( + CG, C, H2N, AM, UR, /*DebugLogging*/ true); + assert(&NewC != &C && "Should get a new SCC due to update!"); + (void)&NewC; + + return PA; + })); + // Now use the analysis again on each SCC and function, forcing + // re-computation for all of them. + CGPM.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Create another CGSCC pipeline that requires all the analyses again. + CGSCCPassManager CGPM2(/*DebugLogging*/ true); + CGPM2.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM2.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Next we inject an SCC pass that finds the `(h2)` SCC, adds a call to `h3` + // back to `h2`, and then invalidates everything for what will then be the + // `(h3, h1, h2)` SCC again. + CGSCCPassManager CGPM3(/*DebugLogging*/ true); + CGPM3.addPass( + LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, + LazyCallGraph &CG, CGSCCUpdateResult &UR) { + (void)AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG); + if (C.getName() != "(h2)") + return PreservedAnalyses::all(); + + // Build the preserved set. + auto PA = PreservedAnalyses::none(); + PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); + PA.preserve<TestIndirectSCCAnalysis>(); + PA.preserve<TestDoublyIndirectSCCAnalysis>(); + + // Delete the bitcast of `h3` that we added earlier. + auto &H2N = *C.begin(); + auto &H2F = H2N.getFunction(); + auto &H3F = *cast<Function>(cast<BitCastInst>(H2F.begin()->begin())->getOperand(0)); + assert(H3F.getName() == "h3" && "Wrong called function!"); + H2F.begin()->begin()->eraseFromParent(); + // And insert a call to `h3`. + (void)CallInst::Create(&H3F, {}, "", &*H2F.begin()->begin()); + + // Now update the call graph. + auto &NewC = updateCGAndAnalysisManagerForFunctionPass( + CG, C, H2N, AM, UR, /*DebugLogging*/ true); + assert(&NewC != &C && "Should get a new SCC due to update!"); + (void)&NewC; + + return PA; + })); + // Now use the analysis again on each SCC and function, forcing + // re-computation for all of them. + CGPM3.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM3.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Create a second CGSCC pass manager. This will cause the module-level + // invalidation to occur, which will force yet another invalidation of the + // indirect SCC-level analysis as the module analysis it depends on gets + // invalidated. + CGSCCPassManager CGPM4(/*DebugLogging*/ true); + CGPM4.addPass(RequireTestDoublyIndirectSCCAnalysisPass()); + CGPM4.addPass(createCGSCCToFunctionPassAdaptor( + RequireTestIndirectFunctionAnalysisPass())); + + // Add a requires pass to populate the module analysis and then one of our + // CGSCC pipelines. Repeat for all four CGSCC pipelines. + MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); + MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); + MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); + MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM4))); + MPM.run(*M, MAM); + + // We run over four SCCs the first time. But then we split an SCC into three. + // And then we merge those three back into one. + EXPECT_EQ(4 + 3 + 1, SCCAnalysisRuns); + // The module analysis pass should be run three times. + EXPECT_EQ(3, ModuleAnalysisRuns); + // We run over four SCCs the first time. Then over the two new ones. Then the + // entire module is invalidated causing a full run over all seven. Then we + // fold three SCCs back to one, and then run over the whole module again. + EXPECT_EQ(4 + 2 + 7 + 1 + 4, IndirectSCCAnalysisRuns); + EXPECT_EQ(4 + 2 + 7 + 1 + 4, DoublyIndirectSCCAnalysisRuns); + + // First we run over all six functions. Then we re-run it over three when we + // split their SCCs. Then we re-run over the whole module. Then we re-run + // over three functions merged back into a single SCC, and then over the + // whole module again. + EXPECT_EQ(6 + 3 + 6 + 3 + 6, FunctionAnalysisRuns); + + // Re run the function analysis over the entire module, and then re-run it + // over the `(h3, h1, h2)` SCC due to invalidation. Then we re-run it over + // the entire module, then the three functions merged back into a single SCC, + // and then over the whole module. + EXPECT_EQ(6 + 3 + 6 + 3 + 6, IndirectFunctionAnalysisRuns); +} } diff --git a/unittests/Analysis/LazyCallGraphTest.cpp b/unittests/Analysis/LazyCallGraphTest.cpp index 8c251cf043b8..65730486cd75 100644 --- a/unittests/Analysis/LazyCallGraphTest.cpp +++ b/unittests/Analysis/LazyCallGraphTest.cpp @@ -1277,9 +1277,10 @@ TEST(LazyCallGraphTest, InternalEdgeMutation) { // be invalidated. LazyCallGraph::SCC &AC = *CG.lookupSCC(A); LazyCallGraph::SCC &CC = *CG.lookupSCC(C); - auto InvalidatedSCCs = RC.switchInternalEdgeToCall(A, C); - ASSERT_EQ(1u, InvalidatedSCCs.size()); - EXPECT_EQ(&AC, InvalidatedSCCs[0]); + EXPECT_TRUE(RC.switchInternalEdgeToCall(A, C, [&](ArrayRef<LazyCallGraph::SCC *> MergedCs) { + ASSERT_EQ(1u, MergedCs.size()); + EXPECT_EQ(&AC, MergedCs[0]); + })); EXPECT_EQ(2, CC.size()); EXPECT_EQ(&CC, CG.lookupSCC(A)); EXPECT_EQ(&CC, CG.lookupSCC(C)); @@ -1586,8 +1587,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) { // Switch the ref edge from A -> D to a call edge. This should have no // effect as it is already in postorder and no new cycles are formed. - auto MergedCs = RC.switchInternalEdgeToCall(A, D); - EXPECT_EQ(0u, MergedCs.size()); + EXPECT_FALSE(RC.switchInternalEdgeToCall(A, D)); ASSERT_EQ(4, RC.size()); EXPECT_EQ(&DC, &RC[0]); EXPECT_EQ(&BC, &RC[1]); @@ -1596,8 +1596,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) { // Switch B -> C to a call edge. This doesn't form any new cycles but does // require reordering the SCCs. - MergedCs = RC.switchInternalEdgeToCall(B, C); - EXPECT_EQ(0u, MergedCs.size()); + EXPECT_FALSE(RC.switchInternalEdgeToCall(B, C)); ASSERT_EQ(4, RC.size()); EXPECT_EQ(&DC, &RC[0]); EXPECT_EQ(&CC, &RC[1]); @@ -1605,9 +1604,10 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) { EXPECT_EQ(&AC, &RC[3]); // Switch C -> B to a call edge. This forms a cycle and forces merging SCCs. - MergedCs = RC.switchInternalEdgeToCall(C, B); - ASSERT_EQ(1u, MergedCs.size()); - EXPECT_EQ(&CC, MergedCs[0]); + EXPECT_TRUE(RC.switchInternalEdgeToCall(C, B, [&](ArrayRef<LazyCallGraph::SCC *> MergedCs) { + ASSERT_EQ(1u, MergedCs.size()); + EXPECT_EQ(&CC, MergedCs[0]); + })); ASSERT_EQ(3, RC.size()); EXPECT_EQ(&DC, &RC[0]); EXPECT_EQ(&BC, &RC[1]); @@ -1720,8 +1720,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallNoCycleInterleaved) { // Switch C3 -> B1 to a call edge. This doesn't form any new cycles but does // require reordering the SCCs in the face of tricky internal node // structures. - auto MergedCs = RC.switchInternalEdgeToCall(C3, B1); - EXPECT_EQ(0u, MergedCs.size()); + EXPECT_FALSE(RC.switchInternalEdgeToCall(C3, B1)); ASSERT_EQ(8, RC.size()); EXPECT_EQ(&DC, &RC[0]); EXPECT_EQ(&B3C, &RC[1]); @@ -1852,10 +1851,12 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallBothPartitionAndMerge) { // C F C | | // \ / \ / | // G G | - auto MergedCs = RC.switchInternalEdgeToCall(F, B); - ASSERT_EQ(2u, MergedCs.size()); - EXPECT_EQ(&FC, MergedCs[0]); - EXPECT_EQ(&DC, MergedCs[1]); + EXPECT_TRUE(RC.switchInternalEdgeToCall( + F, B, [&](ArrayRef<LazyCallGraph::SCC *> MergedCs) { + ASSERT_EQ(2u, MergedCs.size()); + EXPECT_EQ(&FC, MergedCs[0]); + EXPECT_EQ(&DC, MergedCs[1]); + })); EXPECT_EQ(3, BC.size()); // And make sure the postorder was updated. |