|  | //===--- LastRunTrackingAnalysisTest.cpp - LastRunTrackingAnalysis tests---===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Analysis/LastRunTrackingAnalysis.h" | 
|  | #include "llvm/IR/LLVMContext.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/Passes/PassBuilder.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | class LastRunTrackingAnalysisTest : public testing::Test { | 
|  | protected: | 
|  | LLVMContext C; | 
|  | Module M; | 
|  | PassBuilder PB; | 
|  |  | 
|  | LoopAnalysisManager LAM; | 
|  | FunctionAnalysisManager FAM; | 
|  | CGSCCAnalysisManager CGAM; | 
|  | ModulePassManager MPM; | 
|  | ModuleAnalysisManager MAM; | 
|  |  | 
|  | LastRunTrackingAnalysisTest() : M("LastRunTrackingAnalysisTest", C) { | 
|  | PB.registerModuleAnalyses(MAM); | 
|  | PB.registerCGSCCAnalyses(CGAM); | 
|  | PB.registerFunctionAnalyses(FAM); | 
|  | PB.registerLoopAnalyses(LAM); | 
|  | PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct PassOption final { | 
|  | uint32_t Threshold; | 
|  |  | 
|  | /// Assume that this pass doesn't make changes with threshold A if we already | 
|  | /// know it doesn't make changes with a larger threshold B. | 
|  | bool isCompatibleWith(const PassOption &LastOpt) const { | 
|  | return Threshold <= LastOpt.Threshold; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class ModuleNoopPass : public PassInfoMixin<ModuleNoopPass> { | 
|  | uint32_t &ExecutedBitMap; | 
|  | uint32_t RunID; | 
|  | void *PassID; | 
|  | bool ShouldChange; | 
|  | std::optional<PassOption> Option; | 
|  |  | 
|  | bool shouldSkip(LastRunTrackingInfo &LRT) { | 
|  | if (Option.has_value()) | 
|  | return LRT.shouldSkip(PassID, *Option); | 
|  | return LRT.shouldSkip(PassID); | 
|  | } | 
|  |  | 
|  | void update(LastRunTrackingInfo &LRT) { | 
|  | if (Option.has_value()) | 
|  | return LRT.update(PassID, ShouldChange, *Option); | 
|  | return LRT.update(PassID, ShouldChange); | 
|  | } | 
|  |  | 
|  | public: | 
|  | explicit ModuleNoopPass(uint32_t &ExecutedBitMapRef, uint32_t RunIDVal, | 
|  | void *PassIDVal, bool ShouldChangeVal, | 
|  | std::optional<PassOption> OptionVal = std::nullopt) | 
|  | : ExecutedBitMap(ExecutedBitMapRef), RunID(RunIDVal), PassID(PassIDVal), | 
|  | ShouldChange(ShouldChangeVal), Option(OptionVal) {} | 
|  |  | 
|  | PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) { | 
|  | auto &LRT = AM.getResult<LastRunTrackingAnalysis>(F); | 
|  | if (shouldSkip(LRT)) { | 
|  | EXPECT_FALSE(ShouldChange) << "This pass is incorrectly skipped."; | 
|  | return PreservedAnalyses::all(); | 
|  | } | 
|  | ExecutedBitMap |= 1U << RunID; | 
|  | update(LRT); | 
|  | PreservedAnalyses PA; | 
|  | PA.preserve<LastRunTrackingAnalysis>(); | 
|  | return PA; | 
|  | } | 
|  | }; | 
|  |  | 
|  | static char PassA, PassB; | 
|  |  | 
|  | TEST_F(LastRunTrackingAnalysisTest, SkipTest) { | 
|  | uint32_t BitMap = 0; | 
|  | // Executed. This is first run of PassA. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 0, &PassA, true)); | 
|  | // Skipped since PassA has just been executed. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 1, &PassA, false)); | 
|  | // Skipped since PassA has just been executed. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 2, &PassA, false)); | 
|  | // Executed. This is first run of PassB. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 3, &PassB, false, PassOption{2})); | 
|  | // Skipped. PassB doesn't make changes with lower threshold. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 4, &PassB, false, PassOption{1})); | 
|  | // Executed. PassB may make changes with higher threshold. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 5, &PassB, false, PassOption{3})); | 
|  | // Skipped. We don't make changes since last run of PassA. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 6, &PassA, false)); | 
|  | // Executed. PassB may make changes with higher threshold. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 7, &PassB, true, PassOption{4})); | 
|  | // Executed. This module has been modified by PassB. | 
|  | MPM.addPass(ModuleNoopPass(BitMap, 8, &PassA, false)); | 
|  | MPM.run(M, MAM); | 
|  |  | 
|  | ASSERT_EQ(BitMap, 0b110101001U); | 
|  | } | 
|  |  | 
|  | } // namespace |