xref: /llvm-project/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp (revision 84745da74c8aa2749510c26cf0e3a35bececfa30)
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