xref: /llvm-project/llvm/unittests/IR/TimePassesTest.cpp (revision e188aae406f3fecaed65a1f7e6562205f0de937e)
1 //===- unittests/IR/TimePassesTest.cpp - TimePassesHandler 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/IR/LegacyPassManager.h"
10 #include "llvm/Pass.h"
11 #include "llvm/PassRegistry.h"
12 #include <gtest/gtest.h>
13 #include <llvm/ADT/SmallString.h>
14 #include <llvm/IR/LLVMContext.h>
15 #include <llvm/IR/Module.h>
16 #include <llvm/IR/PassInstrumentation.h>
17 #include <llvm/IR/PassManager.h>
18 #include <llvm/IR/PassTimingInfo.h>
19 #include <llvm/Support/raw_ostream.h>
20 
21 using namespace llvm;
22 
23 //===----------------------------------------------------------------------===//
24 // Define dummy passes for legacy pass manager run.
25 
26 namespace llvm {
27 
28 void initializePass1Pass(PassRegistry &);
29 void initializePass2Pass(PassRegistry &);
30 
31 namespace {
32 struct Pass1 : public ModulePass {
33   static char ID;
34 
35 public:
36   Pass1() : ModulePass(ID) {}
37   bool runOnModule(Module &M) override { return false; }
38   void getAnalysisUsage(AnalysisUsage &AU) const override {
39     AU.setPreservesAll();
40   }
41   StringRef getPassName() const override { return "Pass1"; }
42 };
43 char Pass1::ID;
44 
45 struct Pass2 : public ModulePass {
46   static char ID;
47 
48 public:
49   Pass2() : ModulePass(ID) {}
50   bool runOnModule(Module &M) override { return false; }
51   void getAnalysisUsage(AnalysisUsage &AU) const override {
52     AU.setPreservesAll();
53   }
54   StringRef getPassName() const override { return "Pass2"; }
55 };
56 char Pass2::ID;
57 } // namespace
58 } // namespace llvm
59 
60 INITIALIZE_PASS(Pass1, "Pass1", "Pass1", false, false)
61 INITIALIZE_PASS(Pass2, "Pass2", "Pass2", false, false)
62 
63 namespace {
64 
65 TEST(TimePassesTest, LegacyCustomOut) {
66   PassInstrumentationCallbacks PIC;
67   PassInstrumentation PI(&PIC);
68 
69   LLVMContext Context;
70   Module M("TestModule", Context);
71 
72   SmallString<0> TimePassesStr;
73   raw_svector_ostream ReportStream(TimePassesStr);
74 
75   // Setup pass manager
76   legacy::PassManager PM1;
77   PM1.add(new llvm::Pass1());
78   PM1.add(new llvm::Pass2());
79 
80   // Enable time-passes and run passes.
81   TimePassesIsEnabled = true;
82   PM1.run(M);
83 
84   // Generating report.
85   reportAndResetTimings(&ReportStream);
86 
87   // There should be Pass1 and Pass2 in the report
88   EXPECT_FALSE(TimePassesStr.empty());
89   EXPECT_TRUE(TimePassesStr.str().contains("report"));
90   EXPECT_TRUE(TimePassesStr.str().contains("Pass1"));
91   EXPECT_TRUE(TimePassesStr.str().contains("Pass2"));
92 
93   // Clear and generate report again.
94   TimePassesStr.clear();
95   reportAndResetTimings(&ReportStream);
96 
97   // Since we did not run any passes since last print, report should be empty.
98   EXPECT_TRUE(TimePassesStr.empty());
99 
100   // Now run just a single pass to populate timers again.
101   legacy::PassManager PM2;
102   PM2.add(new llvm::Pass2());
103   PM2.run(M);
104 
105   // Generate report again.
106   reportAndResetTimings(&ReportStream);
107 
108   // There should be Pass2 in this report and no Pass1.
109   EXPECT_FALSE(TimePassesStr.str().empty());
110   EXPECT_TRUE(TimePassesStr.str().contains("report"));
111   EXPECT_FALSE(TimePassesStr.str().contains("Pass1"));
112   EXPECT_TRUE(TimePassesStr.str().contains("Pass2"));
113 }
114 
115 class MyPass1 : public PassInfoMixin<MyPass1> {};
116 class MyPass2 : public PassInfoMixin<MyPass2> {};
117 
118 TEST(TimePassesTest, CustomOut) {
119   PassInstrumentationCallbacks PIC;
120   PassInstrumentation PI(&PIC);
121 
122   LLVMContext Context;
123   Module M("TestModule", Context);
124   MyPass1 Pass1;
125   MyPass2 Pass2;
126 
127   SmallString<0> TimePassesStr;
128   raw_svector_ostream ReportStream(TimePassesStr);
129 
130   // Setup time-passes handler and redirect output to the stream.
131   std::unique_ptr<TimePassesHandler> TimePasses =
132       std::make_unique<TimePassesHandler>(true);
133   TimePasses->setOutStream(ReportStream);
134   TimePasses->registerCallbacks(PIC);
135 
136   // Pretending that passes are running to trigger the timers.
137   PI.runBeforePass(Pass1, M);
138   PI.runBeforePass(Pass2, M);
139   PI.runAfterPass(Pass2, M, PreservedAnalyses::all());
140   PI.runAfterPass(Pass1, M, PreservedAnalyses::all());
141 
142   // Generating report.
143   TimePasses->print();
144 
145   // There should be Pass1 and Pass2 in the report
146   EXPECT_FALSE(TimePassesStr.empty());
147   EXPECT_TRUE(TimePassesStr.str().contains("report"));
148   EXPECT_TRUE(TimePassesStr.str().contains("Pass1"));
149   EXPECT_TRUE(TimePassesStr.str().contains("Pass2"));
150 
151   // Clear and generate report again.
152   TimePassesStr.clear();
153   TimePasses->print();
154   // Since we did not run any passes since last print, report should be empty.
155   EXPECT_TRUE(TimePassesStr.empty());
156 
157   // Now trigger just a single pass to populate timers again.
158   PI.runBeforePass(Pass2, M);
159   PI.runAfterPass(Pass2, M, PreservedAnalyses::all());
160 
161   // Generate report by deleting the handler.
162   TimePasses.reset();
163 
164   // There should be Pass2 in this report and no Pass1.
165   EXPECT_FALSE(TimePassesStr.str().empty());
166   EXPECT_TRUE(TimePassesStr.str().contains("report"));
167   EXPECT_FALSE(TimePassesStr.str().contains("Pass1"));
168   EXPECT_TRUE(TimePassesStr.str().contains("Pass2"));
169 }
170 
171 } // end anonymous namespace
172