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(P: new llvm::Pass1()); |
78 | PM1.add(P: new llvm::Pass2()); |
79 | |
80 | // Enable time-passes and run passes. |
81 | TimePassesIsEnabled = true; |
82 | PM1.run(M); |
83 | |
84 | // Generating report. |
85 | reportAndResetTimings(OutStream: &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(OutStream: &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(P: new llvm::Pass2()); |
103 | PM2.run(M); |
104 | |
105 | // Generate report again. |
106 | reportAndResetTimings(OutStream: &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 | // Reset flag to not affect other tests. |
115 | TimePassesIsEnabled = false; |
116 | } |
117 | |
118 | class MyPass1 : public PassInfoMixin<MyPass1> {}; |
119 | class MyPass2 : public PassInfoMixin<MyPass2> {}; |
120 | |
121 | TEST(TimePassesTest, CustomOut) { |
122 | PassInstrumentationCallbacks PIC; |
123 | PassInstrumentation PI(&PIC); |
124 | |
125 | LLVMContext Context; |
126 | Module M("TestModule" , Context); |
127 | MyPass1 Pass1; |
128 | MyPass2 Pass2; |
129 | |
130 | SmallString<0> TimePassesStr; |
131 | raw_svector_ostream ReportStream(TimePassesStr); |
132 | |
133 | // Setup time-passes handler and redirect output to the stream. |
134 | std::unique_ptr<TimePassesHandler> TimePasses = |
135 | std::make_unique<TimePassesHandler>(args: true); |
136 | TimePasses->setOutStream(ReportStream); |
137 | TimePasses->registerCallbacks(PIC); |
138 | |
139 | // Pretending that passes are running to trigger the timers. |
140 | PI.runBeforePass(Pass: Pass1, IR: M); |
141 | PI.runAfterPass(Pass: Pass1, IR: M, PA: PreservedAnalyses::all()); |
142 | PI.runBeforePass(Pass: Pass2, IR: M); |
143 | PI.runAfterPass(Pass: Pass2, IR: M, PA: PreservedAnalyses::all()); |
144 | |
145 | // Generating report. |
146 | TimePasses->print(); |
147 | |
148 | // There should be Pass1 and Pass2 in the report |
149 | EXPECT_FALSE(TimePassesStr.empty()); |
150 | EXPECT_TRUE(TimePassesStr.str().contains("report" )); |
151 | EXPECT_TRUE(TimePassesStr.str().contains("Pass1" )); |
152 | EXPECT_TRUE(TimePassesStr.str().contains("Pass2" )); |
153 | |
154 | // Clear and generate report again. |
155 | TimePassesStr.clear(); |
156 | TimePasses->print(); |
157 | // Since we did not run any passes since last print, report should be empty. |
158 | EXPECT_TRUE(TimePassesStr.empty()); |
159 | |
160 | // Now trigger just a single pass to populate timers again. |
161 | PI.runBeforePass(Pass: Pass2, IR: M); |
162 | PI.runAfterPass(Pass: Pass2, IR: M, PA: PreservedAnalyses::all()); |
163 | |
164 | // Generate report by deleting the handler. |
165 | TimePasses.reset(); |
166 | |
167 | // There should be Pass2 in this report and no Pass1. |
168 | EXPECT_FALSE(TimePassesStr.str().empty()); |
169 | EXPECT_TRUE(TimePassesStr.str().contains("report" )); |
170 | EXPECT_FALSE(TimePassesStr.str().contains("Pass1" )); |
171 | EXPECT_TRUE(TimePassesStr.str().contains("Pass2" )); |
172 | } |
173 | |
174 | } // end anonymous namespace |
175 | |