aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests/Analysis/LastRunTrackingAnalysisTest.cpp
blob: 13ca0bc161a0f469a9d0c187cacaa85a896e80cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//===--- 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