1 //===--- LastRunTrackingAnalysisTest.cpp - LastRunTrackingAnalysis 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Analysis/LastRunTrackingAnalysis.h" 10 #include "llvm/IR/LLVMContext.h" 11 #include "llvm/IR/Module.h" 12 #include "llvm/Passes/PassBuilder.h" 13 #include "gtest/gtest.h" 14 15 namespace { 16 17 using namespace llvm; 18 19 class LastRunTrackingAnalysisTest : public testing::Test { 20 protected: 21 LLVMContext C; 22 Module M; 23 PassBuilder PB; 24 25 LoopAnalysisManager LAM; 26 FunctionAnalysisManager FAM; 27 CGSCCAnalysisManager CGAM; 28 ModulePassManager MPM; 29 ModuleAnalysisManager MAM; 30 31 LastRunTrackingAnalysisTest() : M("LastRunTrackingAnalysisTest", C) { 32 PB.registerModuleAnalyses(MAM); 33 PB.registerCGSCCAnalyses(CGAM); 34 PB.registerFunctionAnalyses(FAM); 35 PB.registerLoopAnalyses(LAM); 36 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); 37 } 38 }; 39 40 struct PassOption final { 41 uint32_t Threshold; 42 43 /// Assume that this pass doesn't make changes with threshold A if we already 44 /// know it doesn't make changes with a larger threshold B. 45 bool isCompatibleWith(const PassOption &LastOpt) const { 46 return Threshold <= LastOpt.Threshold; 47 } 48 }; 49 50 class ModuleNoopPass : public PassInfoMixin<ModuleNoopPass> { 51 uint32_t &ExecutedBitMap; 52 uint32_t RunID; 53 void *PassID; 54 bool ShouldChange; 55 std::optional<PassOption> Option; 56 57 bool shouldSkip(LastRunTrackingInfo &LRT) { 58 if (Option.has_value()) 59 return LRT.shouldSkip(PassID, *Option); 60 return LRT.shouldSkip(PassID); 61 } 62 63 void update(LastRunTrackingInfo &LRT) { 64 if (Option.has_value()) 65 return LRT.update(PassID, ShouldChange, *Option); 66 return LRT.update(PassID, ShouldChange); 67 } 68 69 public: 70 explicit ModuleNoopPass(uint32_t &ExecutedBitMapRef, uint32_t RunIDVal, 71 void *PassIDVal, bool ShouldChangeVal, 72 std::optional<PassOption> OptionVal = std::nullopt) 73 : ExecutedBitMap(ExecutedBitMapRef), RunID(RunIDVal), PassID(PassIDVal), 74 ShouldChange(ShouldChangeVal), Option(OptionVal) {} 75 76 PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) { 77 auto &LRT = AM.getResult<LastRunTrackingAnalysis>(F); 78 if (shouldSkip(LRT)) { 79 EXPECT_FALSE(ShouldChange) << "This pass is incorrectly skipped."; 80 return PreservedAnalyses::all(); 81 } 82 ExecutedBitMap |= 1U << RunID; 83 update(LRT); 84 PreservedAnalyses PA; 85 PA.preserve<LastRunTrackingAnalysis>(); 86 return PA; 87 } 88 }; 89 90 static char PassA, PassB; 91 92 TEST_F(LastRunTrackingAnalysisTest, SkipTest) { 93 uint32_t BitMap = 0; 94 // Executed. This is first run of PassA. 95 MPM.addPass(ModuleNoopPass(BitMap, 0, &PassA, true)); 96 // Skipped since PassA has just been executed. 97 MPM.addPass(ModuleNoopPass(BitMap, 1, &PassA, false)); 98 // Skipped since PassA has just been executed. 99 MPM.addPass(ModuleNoopPass(BitMap, 2, &PassA, false)); 100 // Executed. This is first run of PassB. 101 MPM.addPass(ModuleNoopPass(BitMap, 3, &PassB, false, PassOption{2})); 102 // Skipped. PassB doesn't make changes with lower threshold. 103 MPM.addPass(ModuleNoopPass(BitMap, 4, &PassB, false, PassOption{1})); 104 // Executed. PassB may make changes with higher threshold. 105 MPM.addPass(ModuleNoopPass(BitMap, 5, &PassB, false, PassOption{3})); 106 // Skipped. We don't make changes since last run of PassA. 107 MPM.addPass(ModuleNoopPass(BitMap, 6, &PassA, false)); 108 // Executed. PassB may make changes with higher threshold. 109 MPM.addPass(ModuleNoopPass(BitMap, 7, &PassB, true, PassOption{4})); 110 // Executed. This module has been modified by PassB. 111 MPM.addPass(ModuleNoopPass(BitMap, 8, &PassA, false)); 112 MPM.run(M, MAM); 113 114 ASSERT_EQ(BitMap, 0b110101001U); 115 } 116 117 } // namespace 118