1075 lines · cpp
1//===- llvm/unittest/IR/PassManager.cpp - PassManager tests ---------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/IR/PassManager.h"10#include "llvm/Analysis/AssumptionCache.h"11#include "llvm/Analysis/TargetTransformInfo.h"12#include "llvm/AsmParser/Parser.h"13#include "llvm/IR/Dominators.h"14#include "llvm/IR/Function.h"15#include "llvm/IR/LLVMContext.h"16#include "llvm/IR/Module.h"17#include "llvm/IR/PassManagerImpl.h"18#include "llvm/Passes/StandardInstrumentations.h"19#include "llvm/Support/SourceMgr.h"20#include "llvm/Transforms/Scalar/SimplifyCFG.h"21#include "gtest/gtest.h"22 23using namespace llvm;24 25namespace {26 27class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> {28public:29 struct Result {30 Result(int Count) : InstructionCount(Count) {}31 int InstructionCount;32 bool invalidate(Function &, const PreservedAnalyses &PA,33 FunctionAnalysisManager::Invalidator &) {34 // Check whether the analysis or all analyses on functions have been35 // preserved.36 auto PAC = PA.getChecker<TestFunctionAnalysis>();37 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>());38 }39 };40 41 TestFunctionAnalysis(int &Runs) : Runs(Runs) {}42 43 /// Run the analysis pass over the function and return a result.44 Result run(Function &F, FunctionAnalysisManager &AM) {45 ++Runs;46 int Count = 0;47 for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI)48 for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE;49 ++II)50 ++Count;51 return Result(Count);52 }53 54private:55 friend AnalysisInfoMixin<TestFunctionAnalysis>;56 static AnalysisKey Key;57 58 int &Runs;59};60 61AnalysisKey TestFunctionAnalysis::Key;62 63class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> {64public:65 struct Result {66 Result(int Count) : FunctionCount(Count) {}67 int FunctionCount;68 bool invalidate(Module &, const PreservedAnalyses &PA,69 ModuleAnalysisManager::Invalidator &) {70 // Check whether the analysis or all analyses on modules have been71 // preserved.72 auto PAC = PA.getChecker<TestModuleAnalysis>();73 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Module>>());74 }75 };76 77 TestModuleAnalysis(int &Runs) : Runs(Runs) {}78 79 Result run(Module &M, ModuleAnalysisManager &AM) {80 ++Runs;81 int Count = 0;82 for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)83 ++Count;84 return Result(Count);85 }86 87private:88 friend AnalysisInfoMixin<TestModuleAnalysis>;89 static AnalysisKey Key;90 91 int &Runs;92};93 94AnalysisKey TestModuleAnalysis::Key;95 96struct TestModulePass : PassInfoMixin<TestModulePass> {97 TestModulePass(int &RunCount) : RunCount(RunCount) {}98 99 PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {100 ++RunCount;101 return PreservedAnalyses::none();102 }103 104 int &RunCount;105};106 107struct TestPreservingModulePass : PassInfoMixin<TestPreservingModulePass> {108 PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {109 return PreservedAnalyses::all();110 }111};112 113struct TestFunctionPass : PassInfoMixin<TestFunctionPass> {114 TestFunctionPass(int &RunCount, int &AnalyzedInstrCount,115 int &AnalyzedFunctionCount, ModuleAnalysisManager &MAM,116 bool OnlyUseCachedResults = false)117 : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),118 AnalyzedFunctionCount(AnalyzedFunctionCount), MAM(MAM),119 OnlyUseCachedResults(OnlyUseCachedResults) {}120 121 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {122 ++RunCount;123 124 // Getting a cached result that isn't stateless through the proxy will125 // trigger an assert:126 // auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);127 // Use MAM, for the purposes of this unittest.128 if (TestModuleAnalysis::Result *TMA =129 MAM.getCachedResult<TestModuleAnalysis>(*F.getParent())) {130 AnalyzedFunctionCount += TMA->FunctionCount;131 }132 133 if (OnlyUseCachedResults) {134 // Hack to force the use of the cached interface.135 if (TestFunctionAnalysis::Result *AR =136 AM.getCachedResult<TestFunctionAnalysis>(F))137 AnalyzedInstrCount += AR->InstructionCount;138 } else {139 // Typical path just runs the analysis as needed.140 TestFunctionAnalysis::Result &AR = AM.getResult<TestFunctionAnalysis>(F);141 AnalyzedInstrCount += AR.InstructionCount;142 }143 144 return PreservedAnalyses::all();145 }146 147 int &RunCount;148 int &AnalyzedInstrCount;149 int &AnalyzedFunctionCount;150 ModuleAnalysisManager &MAM;151 bool OnlyUseCachedResults;152};153 154// A test function pass that invalidates all function analyses for a function155// with a specific name.156struct TestInvalidationFunctionPass157 : PassInfoMixin<TestInvalidationFunctionPass> {158 TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {}159 160 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {161 return F.getName() == Name ? PreservedAnalyses::none()162 : PreservedAnalyses::all();163 }164 165 StringRef Name;166};167 168std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) {169 SMDiagnostic Err;170 return parseAssemblyString(IR, Err, Context);171}172 173class PassManagerTest : public ::testing::Test {174protected:175 LLVMContext Context;176 std::unique_ptr<Module> M;177 178public:179 PassManagerTest()180 : M(parseIR(Context, "define void @f() {\n"181 "entry:\n"182 " call void @g()\n"183 " call void @h()\n"184 " ret void\n"185 "}\n"186 "define void @g() {\n"187 " ret void\n"188 "}\n"189 "define void @h() {\n"190 " ret void\n"191 "}\n")) {}192};193 194TEST(PreservedAnalysesTest, Basic) {195 PreservedAnalyses PA1 = PreservedAnalyses();196 {197 auto PAC = PA1.getChecker<TestFunctionAnalysis>();198 EXPECT_FALSE(PAC.preserved());199 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());200 }201 {202 auto PAC = PA1.getChecker<TestModuleAnalysis>();203 EXPECT_FALSE(PAC.preserved());204 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>());205 }206 auto PA2 = PreservedAnalyses::none();207 {208 auto PAC = PA2.getChecker<TestFunctionAnalysis>();209 EXPECT_FALSE(PAC.preserved());210 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());211 }212 auto PA3 = PreservedAnalyses::all();213 {214 auto PAC = PA3.getChecker<TestFunctionAnalysis>();215 EXPECT_TRUE(PAC.preserved());216 EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());217 }218 PreservedAnalyses PA4 = PA1;219 {220 auto PAC = PA4.getChecker<TestFunctionAnalysis>();221 EXPECT_FALSE(PAC.preserved());222 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());223 }224 PA4 = PA3;225 {226 auto PAC = PA4.getChecker<TestFunctionAnalysis>();227 EXPECT_TRUE(PAC.preserved());228 EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());229 }230 PA4 = std::move(PA2);231 {232 auto PAC = PA4.getChecker<TestFunctionAnalysis>();233 EXPECT_FALSE(PAC.preserved());234 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());235 }236 auto PA5 = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>();237 {238 auto PAC = PA5.getChecker<TestFunctionAnalysis>();239 EXPECT_FALSE(PAC.preserved());240 EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());241 EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>());242 }243}244 245TEST(PreservedAnalysesTest, Preserve) {246 auto PA = PreservedAnalyses::none();247 PA.preserve<TestFunctionAnalysis>();248 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());249 EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());250 PA.preserve<TestModuleAnalysis>();251 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());252 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());253 254 // Redundant calls are fine.255 PA.preserve<TestFunctionAnalysis>();256 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());257 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());258}259 260TEST(PreservedAnalysesTest, PreserveSets) {261 auto PA = PreservedAnalyses::none();262 PA.preserveSet<AllAnalysesOn<Function>>();263 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()264 .preservedSet<AllAnalysesOn<Function>>());265 EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()266 .preservedSet<AllAnalysesOn<Module>>());267 PA.preserveSet<AllAnalysesOn<Module>>();268 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()269 .preservedSet<AllAnalysesOn<Function>>());270 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()271 .preservedSet<AllAnalysesOn<Module>>());272 273 // Mixing is fine.274 PA.preserve<TestFunctionAnalysis>();275 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()276 .preservedSet<AllAnalysesOn<Function>>());277 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()278 .preservedSet<AllAnalysesOn<Module>>());279 280 // Redundant calls are fine.281 PA.preserveSet<AllAnalysesOn<Module>>();282 EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()283 .preservedSet<AllAnalysesOn<Function>>());284 EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()285 .preservedSet<AllAnalysesOn<Module>>());286}287 288TEST(PreservedAnalysisTest, Intersect) {289 // Setup the initial sets.290 auto PA1 = PreservedAnalyses::none();291 PA1.preserve<TestFunctionAnalysis>();292 PA1.preserveSet<AllAnalysesOn<Module>>();293 auto PA2 = PreservedAnalyses::none();294 PA2.preserve<TestFunctionAnalysis>();295 PA2.preserveSet<AllAnalysesOn<Function>>();296 PA2.preserve<TestModuleAnalysis>();297 PA2.preserveSet<AllAnalysesOn<Module>>();298 auto PA3 = PreservedAnalyses::none();299 PA3.preserve<TestModuleAnalysis>();300 PA3.preserveSet<AllAnalysesOn<Function>>();301 302 // Self intersection is a no-op.303 auto Intersected = PA1;304 Intersected.intersect(PA1);305 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());306 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()307 .preservedSet<AllAnalysesOn<Function>>());308 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());309 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()310 .preservedSet<AllAnalysesOn<Module>>());311 312 // Intersecting with all is a no-op.313 Intersected.intersect(PreservedAnalyses::all());314 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());315 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()316 .preservedSet<AllAnalysesOn<Function>>());317 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());318 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()319 .preservedSet<AllAnalysesOn<Module>>());320 321 // Intersecting a narrow set with a more broad set is the narrow set.322 Intersected.intersect(PA2);323 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());324 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()325 .preservedSet<AllAnalysesOn<Function>>());326 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());327 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()328 .preservedSet<AllAnalysesOn<Module>>());329 330 // Intersecting a broad set with a more narrow set is the narrow set.331 Intersected = PA2;332 Intersected.intersect(PA1);333 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());334 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()335 .preservedSet<AllAnalysesOn<Function>>());336 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());337 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()338 .preservedSet<AllAnalysesOn<Module>>());339 340 // Intersecting with empty clears.341 Intersected.intersect(PreservedAnalyses::none());342 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());343 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()344 .preservedSet<AllAnalysesOn<Function>>());345 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());346 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()347 .preservedSet<AllAnalysesOn<Module>>());348 349 // Intersecting non-overlapping clears.350 Intersected = PA1;351 Intersected.intersect(PA3);352 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());353 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()354 .preservedSet<AllAnalysesOn<Function>>());355 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());356 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()357 .preservedSet<AllAnalysesOn<Module>>());358 359 // Intersecting with moves works in when there is storage on both sides.360 Intersected = PA1;361 auto Tmp = PA2;362 Intersected.intersect(std::move(Tmp));363 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());364 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()365 .preservedSet<AllAnalysesOn<Function>>());366 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());367 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()368 .preservedSet<AllAnalysesOn<Module>>());369 370 // Intersecting with move works for incoming all and existing all.371 auto Tmp2 = PreservedAnalyses::all();372 Intersected.intersect(std::move(Tmp2));373 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());374 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()375 .preservedSet<AllAnalysesOn<Function>>());376 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());377 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()378 .preservedSet<AllAnalysesOn<Module>>());379 Intersected = PreservedAnalyses::all();380 auto Tmp3 = PA1;381 Intersected.intersect(std::move(Tmp3));382 EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());383 EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()384 .preservedSet<AllAnalysesOn<Function>>());385 EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());386 EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()387 .preservedSet<AllAnalysesOn<Module>>());388}389 390TEST(PreservedAnalysisTest, Abandon) {391 auto PA = PreservedAnalyses::none();392 393 // We can abandon things after they are preserved.394 PA.preserve<TestFunctionAnalysis>();395 PA.abandon<TestFunctionAnalysis>();396 EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());397 398 // Repeated is fine, and abandoning if they were never preserved is fine.399 PA.abandon<TestFunctionAnalysis>();400 EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());401 PA.abandon<TestModuleAnalysis>();402 EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());403 404 // Even if the sets are preserved, the abandoned analyses' checker won't405 // return true for those sets.406 PA.preserveSet<AllAnalysesOn<Function>>();407 PA.preserveSet<AllAnalysesOn<Module>>();408 EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>()409 .preservedSet<AllAnalysesOn<Function>>());410 EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()411 .preservedSet<AllAnalysesOn<Module>>());412 413 // But an arbitrary (opaque) analysis will still observe the sets as414 // preserved. This also checks that we can use an explicit ID rather than415 // a type.416 AnalysisKey FakeKey, *FakeID = &FakeKey;417 EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Function>>());418 EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Module>>());419}420 421TEST_F(PassManagerTest, Basic) {422 FunctionAnalysisManager FAM;423 int FunctionAnalysisRuns = 0;424 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });425 426 ModuleAnalysisManager MAM;427 int ModuleAnalysisRuns = 0;428 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });429 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });430 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });431 432 MAM.registerPass([&] { return PassInstrumentationAnalysis(); });433 FAM.registerPass([&] { return PassInstrumentationAnalysis(); });434 435 ModulePassManager MPM;436 437 // Count the runs over a Function.438 int FunctionPassRunCount1 = 0;439 int AnalyzedInstrCount1 = 0;440 int AnalyzedFunctionCount1 = 0;441 {442 // Pointless scoped copy to test move assignment.443 ModulePassManager NestedMPM;444 FunctionPassManager FPM;445 {446 // Pointless scope to test move assignment.447 FunctionPassManager NestedFPM;448 NestedFPM.addPass(TestFunctionPass(FunctionPassRunCount1,449 AnalyzedInstrCount1,450 AnalyzedFunctionCount1, MAM));451 FPM = std::move(NestedFPM);452 }453 NestedMPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));454 MPM = std::move(NestedMPM);455 }456 457 // Count the runs over a module.458 int ModulePassRunCount = 0;459 MPM.addPass(TestModulePass(ModulePassRunCount));460 461 // Count the runs over a Function in a separate manager.462 int FunctionPassRunCount2 = 0;463 int AnalyzedInstrCount2 = 0;464 int AnalyzedFunctionCount2 = 0;465 {466 FunctionPassManager FPM;467 FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2,468 AnalyzedFunctionCount2, MAM));469 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));470 }471 472 // A third function pass manager but with only preserving intervening passes473 // and with a function pass that invalidates exactly one analysis.474 MPM.addPass(TestPreservingModulePass());475 int FunctionPassRunCount3 = 0;476 int AnalyzedInstrCount3 = 0;477 int AnalyzedFunctionCount3 = 0;478 {479 FunctionPassManager FPM;480 FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3,481 AnalyzedFunctionCount3, MAM));482 FPM.addPass(TestInvalidationFunctionPass("f"));483 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));484 }485 486 // A fourth function pass manager but with only preserving intervening487 // passes but triggering the module analysis.488 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());489 int FunctionPassRunCount4 = 0;490 int AnalyzedInstrCount4 = 0;491 int AnalyzedFunctionCount4 = 0;492 {493 FunctionPassManager FPM;494 FPM.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4,495 AnalyzedFunctionCount4, MAM));496 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));497 }498 499 // A fifth function pass manager which invalidates one function first but500 // uses only cached results.501 int FunctionPassRunCount5 = 0;502 int AnalyzedInstrCount5 = 0;503 int AnalyzedFunctionCount5 = 0;504 {505 FunctionPassManager FPM;506 FPM.addPass(TestInvalidationFunctionPass("f"));507 FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5,508 AnalyzedFunctionCount5, MAM,509 /*OnlyUseCachedResults=*/true));510 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));511 }512 513 MPM.run(*M, MAM);514 515 // Validate module pass counters.516 EXPECT_EQ(1, ModulePassRunCount);517 518 // Validate all function pass counter sets are the same.519 EXPECT_EQ(3, FunctionPassRunCount1);520 EXPECT_EQ(5, AnalyzedInstrCount1);521 EXPECT_EQ(0, AnalyzedFunctionCount1);522 EXPECT_EQ(3, FunctionPassRunCount2);523 EXPECT_EQ(5, AnalyzedInstrCount2);524 EXPECT_EQ(0, AnalyzedFunctionCount2);525 EXPECT_EQ(3, FunctionPassRunCount3);526 EXPECT_EQ(5, AnalyzedInstrCount3);527 EXPECT_EQ(0, AnalyzedFunctionCount3);528 EXPECT_EQ(3, FunctionPassRunCount4);529 EXPECT_EQ(5, AnalyzedInstrCount4);530 EXPECT_EQ(9, AnalyzedFunctionCount4);531 EXPECT_EQ(3, FunctionPassRunCount5);532 EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.533 EXPECT_EQ(9, AnalyzedFunctionCount5);534 535 // Validate the analysis counters:536 // first run over 3 functions, then module pass invalidates537 // second run over 3 functions, nothing invalidates538 // third run over 0 functions, but 1 function invalidated539 // fourth run over 1 function540 // fifth run invalidates 1 function first, but runs over 0 functions541 EXPECT_EQ(7, FunctionAnalysisRuns);542 543 EXPECT_EQ(1, ModuleAnalysisRuns);544}545 546// A customized pass manager that passes extra arguments through the547// infrastructure.548typedef AnalysisManager<Function, int> CustomizedAnalysisManager;549typedef PassManager<Function, CustomizedAnalysisManager, int, int &>550 CustomizedPassManager;551 552class CustomizedAnalysis : public AnalysisInfoMixin<CustomizedAnalysis> {553public:554 struct Result {555 Result(int I) : I(I) {}556 int I;557 };558 559 Result run(Function &F, CustomizedAnalysisManager &AM, int I) {560 return Result(I);561 }562 563private:564 friend AnalysisInfoMixin<CustomizedAnalysis>;565 static AnalysisKey Key;566};567 568AnalysisKey CustomizedAnalysis::Key;569 570struct CustomizedPass : PassInfoMixin<CustomizedPass> {571 std::function<void(CustomizedAnalysis::Result &, int &)> Callback;572 573 template <typename CallbackT>574 CustomizedPass(CallbackT Callback) : Callback(Callback) {}575 576 PreservedAnalyses run(Function &F, CustomizedAnalysisManager &AM, int I,577 int &O) {578 Callback(AM.getResult<CustomizedAnalysis>(F, I), O);579 return PreservedAnalyses::none();580 }581};582 583TEST_F(PassManagerTest, CustomizedPassManagerArgs) {584 CustomizedAnalysisManager AM;585 AM.registerPass([&] { return CustomizedAnalysis(); });586 PassInstrumentationCallbacks PIC;587 AM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });588 589 CustomizedPassManager PM;590 591 // Add an instance of the customized pass that just accumulates the input592 // after it is round-tripped through the analysis.593 int Result = 0;594 PM.addPass(595 CustomizedPass([](CustomizedAnalysis::Result &R, int &O) { O += R.I; }));596 597 // Run this over every function with the input of 42.598 for (Function &F : *M)599 PM.run(F, AM, 42, Result);600 601 // And ensure that we accumulated the correct result.602 EXPECT_EQ(42 * (int)M->size(), Result);603}604 605/// A test analysis pass which caches in its result another analysis pass and606/// uses it to serve queries. This requires the result to invalidate itself607/// when its dependency is invalidated.608struct TestIndirectFunctionAnalysis609 : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> {610 struct Result {611 Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep)612 : FDep(FDep), MDep(MDep) {}613 TestFunctionAnalysis::Result &FDep;614 TestModuleAnalysis::Result &MDep;615 616 bool invalidate(Function &F, const PreservedAnalyses &PA,617 FunctionAnalysisManager::Invalidator &Inv) {618 auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>();619 return !(PAC.preserved() ||620 PAC.preservedSet<AllAnalysesOn<Function>>()) ||621 Inv.invalidate<TestFunctionAnalysis>(F, PA);622 }623 };624 625 TestIndirectFunctionAnalysis(int &Runs, ModuleAnalysisManager &MAM)626 : Runs(Runs), MAM(MAM) {}627 628 /// Run the analysis pass over the function and return a result.629 Result run(Function &F, FunctionAnalysisManager &AM) {630 ++Runs;631 auto &FDep = AM.getResult<TestFunctionAnalysis>(F);632 auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);633 // For the test, we insist that the module analysis starts off in the634 // cache. Getting a cached result that isn't stateless trigger an assert.635 // Use MAM, for the purposes of this unittest.636 auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());637 // And register the dependency as module analysis dependencies have to be638 // pre-registered on the proxy.639 MAMProxy.registerOuterAnalysisInvalidation<TestModuleAnalysis,640 TestIndirectFunctionAnalysis>();641 return Result(FDep, MDep);642 }643 644private:645 friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>;646 static AnalysisKey Key;647 648 int &Runs;649 ModuleAnalysisManager &MAM;650};651 652AnalysisKey TestIndirectFunctionAnalysis::Key;653 654/// A test analysis pass which chaches in its result the result from the above655/// indirect analysis pass.656///657/// This allows us to ensure that whenever an analysis pass is invalidated due658/// to dependencies (especially dependencies across IR units that trigger659/// asynchronous invalidation) we correctly detect that this may in turn cause660/// other analysis to be invalidated.661struct TestDoublyIndirectFunctionAnalysis662 : public AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis> {663 struct Result {664 Result(TestIndirectFunctionAnalysis::Result &IDep) : IDep(IDep) {}665 TestIndirectFunctionAnalysis::Result &IDep;666 667 bool invalidate(Function &F, const PreservedAnalyses &PA,668 FunctionAnalysisManager::Invalidator &Inv) {669 auto PAC = PA.getChecker<TestDoublyIndirectFunctionAnalysis>();670 return !(PAC.preserved() ||671 PAC.preservedSet<AllAnalysesOn<Function>>()) ||672 Inv.invalidate<TestIndirectFunctionAnalysis>(F, PA);673 }674 };675 676 TestDoublyIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}677 678 /// Run the analysis pass over the function and return a result.679 Result run(Function &F, FunctionAnalysisManager &AM) {680 ++Runs;681 auto &IDep = AM.getResult<TestIndirectFunctionAnalysis>(F);682 return Result(IDep);683 }684 685private:686 friend AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis>;687 static AnalysisKey Key;688 689 int &Runs;690};691 692AnalysisKey TestDoublyIndirectFunctionAnalysis::Key;693 694struct LambdaPass : public PassInfoMixin<LambdaPass> {695 using FuncT = std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)>;696 697 LambdaPass(FuncT Func) : Func(std::move(Func)) {}698 699 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {700 return Func(F, AM);701 }702 703 FuncT Func;704};705 706TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {707 FunctionAnalysisManager FAM;708 ModuleAnalysisManager MAM;709 int FunctionAnalysisRuns = 0, ModuleAnalysisRuns = 0,710 IndirectAnalysisRuns = 0, DoublyIndirectAnalysisRuns = 0;711 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });712 FAM.registerPass(713 [&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns, MAM); });714 FAM.registerPass([&] {715 return TestDoublyIndirectFunctionAnalysis(DoublyIndirectAnalysisRuns);716 });717 718 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });719 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });720 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });721 722 PassInstrumentationCallbacks PIC;723 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });724 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });725 726 int InstrCount = 0, FunctionCount = 0;727 ModulePassManager MPM;728 FunctionPassManager FPM;729 // First just use the analysis to get the instruction count, and preserve730 // everything.731 FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {732 auto &DoublyIndirectResult =733 AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);734 auto &IndirectResult = DoublyIndirectResult.IDep;735 InstrCount += IndirectResult.FDep.InstructionCount;736 FunctionCount += IndirectResult.MDep.FunctionCount;737 return PreservedAnalyses::all();738 }));739 // Next, invalidate740 // - both analyses for "f",741 // - just the underlying (indirect) analysis for "g", and742 // - just the direct analysis for "h".743 FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {744 auto &DoublyIndirectResult =745 AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);746 auto &IndirectResult = DoublyIndirectResult.IDep;747 InstrCount += IndirectResult.FDep.InstructionCount;748 FunctionCount += IndirectResult.MDep.FunctionCount;749 auto PA = PreservedAnalyses::none();750 if (F.getName() == "g")751 PA.preserve<TestFunctionAnalysis>();752 else if (F.getName() == "h")753 PA.preserve<TestIndirectFunctionAnalysis>();754 return PA;755 }));756 // Finally, use the analysis again on each function, forcing re-computation757 // for all of them.758 FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {759 auto &DoublyIndirectResult =760 AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);761 auto &IndirectResult = DoublyIndirectResult.IDep;762 InstrCount += IndirectResult.FDep.InstructionCount;763 FunctionCount += IndirectResult.MDep.FunctionCount;764 return PreservedAnalyses::all();765 }));766 767 // Create a second function pass manager. This will cause the module-level768 // invalidation to occur, which will force yet another invalidation of the769 // indirect function-level analysis as the module analysis it depends on gets770 // invalidated.771 FunctionPassManager FPM2;772 FPM2.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {773 auto &DoublyIndirectResult =774 AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);775 auto &IndirectResult = DoublyIndirectResult.IDep;776 InstrCount += IndirectResult.FDep.InstructionCount;777 FunctionCount += IndirectResult.MDep.FunctionCount;778 return PreservedAnalyses::all();779 }));780 781 // Add a requires pass to populate the module analysis and then our function782 // pass pipeline.783 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());784 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));785 // Now require the module analysis again (it will have been invalidated once)786 // and then use it again from a function pass manager.787 MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());788 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM2)));789 MPM.run(*M, MAM);790 791 // There are generally two possible runs for each of the three functions. But792 // for one function, we only invalidate the indirect analysis so the base one793 // only gets run five times.794 EXPECT_EQ(5, FunctionAnalysisRuns);795 // The module analysis pass should be run twice here.796 EXPECT_EQ(2, ModuleAnalysisRuns);797 // The indirect analysis is invalidated for each function (either directly or798 // indirectly) and run twice for each.799 EXPECT_EQ(9, IndirectAnalysisRuns);800 EXPECT_EQ(9, DoublyIndirectAnalysisRuns);801 802 // There are five instructions in the module and we add the count four803 // times.804 EXPECT_EQ(5 * 4, InstrCount);805 806 // There are three functions and we count them four times for each of the807 // three functions.808 EXPECT_EQ(3 * 4 * 3, FunctionCount);809}810 811// Run SimplifyCFGPass that makes CFG changes and reports PreservedAnalyses812// without CFGAnalyses. So the CFGChecker does not complain.813TEST_F(PassManagerTest, FunctionPassCFGChecker) {814 LLVMContext Context;815 // SimplifyCFG changes this function to816 // define void @foo {next: ret void}817 auto M = parseIR(Context, "define void @foo() {\n"818 " br label %next\n"819 "next:\n"820 " br label %exit\n"821 "exit:\n"822 " ret void\n"823 "}\n");824 825 auto *F = M->getFunction("foo");826 FunctionAnalysisManager FAM;827 ModuleAnalysisManager MAM;828 FunctionPassManager FPM;829 PassInstrumentationCallbacks PIC;830 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);831 SI.registerCallbacks(PIC, &MAM);832 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });833 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });834 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });835 FAM.registerPass([&] { return DominatorTreeAnalysis(); });836 FAM.registerPass([&] { return AssumptionAnalysis(); });837 FAM.registerPass([&] { return TargetIRAnalysis(); });838 839 FPM.addPass(SimplifyCFGPass());840 FPM.run(*F, FAM);841}842 843// FunctionPass that manually invalidates analyses and always returns844// PreservedAnalyses::all().845struct TestSimplifyCFGInvalidatingAnalysisPass846 : PassInfoMixin<TestSimplifyCFGInvalidatingAnalysisPass> {847 PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {848 // Run SimplifyCFG and if it changes CFG then invalidate the CFG analysis.849 // This allows to return PreserveAnalysis::all().850 PreservedAnalyses PA = CFGSimplifier.run(F, FAM);851 FAM.invalidate(F, PA);852 return PreservedAnalyses::all();853 }854 855 SimplifyCFGPass CFGSimplifier;856};857 858// Run TestSimplifyCFGInvalidatingAnalysisPass which changes CFG by running859// SimplifyCFGPass then manually invalidates analyses and always returns860// PreservedAnalyses::all(). CFGChecker does not complain because it resets861// its saved CFG snapshot when the analyses are invalidated manually.862TEST_F(PassManagerTest, FunctionPassCFGCheckerInvalidateAnalysis) {863 LLVMContext Context;864 // SimplifyCFG changes this function to865 // define void @foo {next: ret void}866 auto M = parseIR(Context, "define void @foo() {\n"867 " br label %next\n"868 "next:\n"869 " br label %exit\n"870 "exit:\n"871 " ret void\n"872 "}\n");873 874 auto *F = M->getFunction("foo");875 FunctionAnalysisManager FAM;876 ModuleAnalysisManager MAM;877 FunctionPassManager FPM;878 PassInstrumentationCallbacks PIC;879 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);880 SI.registerCallbacks(PIC, &MAM);881 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });882 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });883 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });884 FAM.registerPass([&] { return DominatorTreeAnalysis(); });885 FAM.registerPass([&] { return AssumptionAnalysis(); });886 FAM.registerPass([&] { return TargetIRAnalysis(); });887 888 FPM.addPass(TestSimplifyCFGInvalidatingAnalysisPass());889 FPM.run(*F, FAM);890}891 892// Wrap a FunctionPassManager running SimplifyCFG pass with another893// FunctionPassManager.894struct TestSimplifyCFGWrapperPass : PassInfoMixin<TestSimplifyCFGWrapperPass> {895 TestSimplifyCFGWrapperPass(FunctionPassManager &InnerPM) : InnerPM(InnerPM) {}896 897 PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {898 // Here we simulate exactly what FunctionPassManager::run() does but899 // instead of running all passes from InnerPM.Passes we run them in bulk900 // by calling InnerPM.run().901 PreservedAnalyses PA = PreservedAnalyses::all();902 PassInstrumentation PI = FAM.getResult<PassInstrumentationAnalysis>(F);903 904 if (!PI.runBeforePass<Function>(InnerPM, F))905 return PreservedAnalyses::all();906 907 PreservedAnalyses PassPA = InnerPM.run(F, FAM);908 PI.runAfterPass(InnerPM, F, PassPA);909 FAM.invalidate(F, PassPA);910 PA.intersect(PassPA);911 PA.preserveSet<AllAnalysesOn<Function>>();912 return PA;913 }914 915 FunctionPassManager &InnerPM;916};917 918// Run TestSimplifyCFGWrapperPass which simulates behavior of919// FunctionPassManager::run() except that it runs all passes at once by calling920// an inner pass manager's passes with PassManager::run(). This is how one pass921// manager is expected to wrap another pass manager.922// SimplifyCFGPass, which is called by the inner pass manager, changes the CFG.923// The CFGChecker's AfterPassCallback, run right after SimplifyCFGPass, does not924// complain because CFGAnalyses is not in the PreservedAnalises set returned by925// SimplifyCFGPass. Then the CFG analysis is invalidated by the analysis manager926// according to the PreservedAnalises set. Further calls to CFGChecker's927// AfterPassCallback see that all analyses for the current function are928// preserved but there is no CFG snapshot available (i.e.929// AM.getCachedResult<PreservedCFGCheckerAnalysis>(F) returns nullptr).930TEST_F(PassManagerTest, FunctionPassCFGCheckerWrapped) {931 LLVMContext Context;932 // SimplifyCFG changes this function to933 // define void @foo {next: ret void}934 auto M = parseIR(Context, "define void @foo() {\n"935 " br label %next\n"936 "next:\n"937 " br label %exit\n"938 "exit:\n"939 " ret void\n"940 "}\n");941 942 auto *F = M->getFunction("foo");943 FunctionAnalysisManager FAM;944 ModuleAnalysisManager MAM;945 FunctionPassManager FPM;946 PassInstrumentationCallbacks PIC;947 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);948 SI.registerCallbacks(PIC, &MAM);949 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });950 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });951 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });952 FAM.registerPass([&] { return DominatorTreeAnalysis(); });953 FAM.registerPass([&] { return AssumptionAnalysis(); });954 FAM.registerPass([&] { return TargetIRAnalysis(); });955 956 FunctionPassManager InnerFPM;957 InnerFPM.addPass(SimplifyCFGPass());958 959 FPM.addPass(TestSimplifyCFGWrapperPass(InnerFPM));960 FPM.run(*F, FAM);961}962 963#ifdef EXPENSIVE_CHECKS964 965struct WrongFunctionPass : PassInfoMixin<WrongFunctionPass> {966 PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {967 F.getEntryBlock().begin()->eraseFromParent();968 return PreservedAnalyses::all();969 }970 static StringRef name() { return "WrongFunctionPass"; }971};972 973TEST_F(PassManagerTest, FunctionPassMissedFunctionAnalysisInvalidation) {974 LLVMContext Context;975 auto M = parseIR(Context, "define void @foo() {\n"976 " %a = add i32 0, 0\n"977 " ret void\n"978 "}\n");979 980 FunctionAnalysisManager FAM;981 ModuleAnalysisManager MAM;982 PassInstrumentationCallbacks PIC;983 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);984 SI.registerCallbacks(PIC, &MAM);985 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });986 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });987 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });988 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });989 990 FunctionPassManager FPM;991 FPM.addPass(WrongFunctionPass());992 993 auto *F = M->getFunction("foo");994 EXPECT_DEATH(FPM.run(*F, FAM), "Function @foo changed by WrongFunctionPass without invalidating analyses");995}996 997struct WrongModulePass : PassInfoMixin<WrongModulePass> {998 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {999 for (Function &F : M)1000 F.getEntryBlock().begin()->eraseFromParent();1001 1002 PreservedAnalyses PA;1003 PA.preserveSet<AllAnalysesOn<Function>>();1004 PA.preserve<FunctionAnalysisManagerModuleProxy>();1005 return PA;1006 }1007 static StringRef name() { return "WrongModulePass"; }1008};1009 1010TEST_F(PassManagerTest, ModulePassMissedFunctionAnalysisInvalidation) {1011 LLVMContext Context;1012 auto M = parseIR(Context, "define void @foo() {\n"1013 " %a = add i32 0, 0\n"1014 " ret void\n"1015 "}\n");1016 1017 FunctionAnalysisManager FAM;1018 ModuleAnalysisManager MAM;1019 PassInstrumentationCallbacks PIC;1020 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);1021 SI.registerCallbacks(PIC, &MAM);1022 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });1023 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });1024 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });1025 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });1026 1027 ModulePassManager MPM;1028 MPM.addPass(WrongModulePass());1029 1030 EXPECT_DEATH(1031 MPM.run(*M, MAM),1032 "Function @foo changed by WrongModulePass without invalidating analyses");1033}1034 1035struct WrongModulePass2 : PassInfoMixin<WrongModulePass2> {1036 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {1037 for (Function &F : M)1038 F.getEntryBlock().begin()->eraseFromParent();1039 1040 PreservedAnalyses PA;1041 PA.preserveSet<AllAnalysesOn<Module>>();1042 PA.abandon<FunctionAnalysisManagerModuleProxy>();1043 return PA;1044 }1045 static StringRef name() { return "WrongModulePass2"; }1046};1047 1048TEST_F(PassManagerTest, ModulePassMissedModuleAnalysisInvalidation) {1049 LLVMContext Context;1050 auto M = parseIR(Context, "define void @foo() {\n"1051 " %a = add i32 0, 0\n"1052 " ret void\n"1053 "}\n");1054 1055 FunctionAnalysisManager FAM;1056 ModuleAnalysisManager MAM;1057 PassInstrumentationCallbacks PIC;1058 StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);1059 SI.registerCallbacks(PIC, &MAM);1060 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });1061 MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });1062 FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });1063 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });1064 1065 ModulePassManager MPM;1066 MPM.addPass(WrongModulePass2());1067 1068 EXPECT_DEATH(1069 MPM.run(*M, MAM),1070 "Module changed by WrongModulePass2 without invalidating analyses");1071}1072 1073#endif1074}1075