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
21using namespace llvm;
22
23//===----------------------------------------------------------------------===//
24// Define dummy passes for legacy pass manager run.
25
26namespace llvm {
27
28void initializePass1Pass(PassRegistry &);
29void initializePass2Pass(PassRegistry &);
30
31namespace {
32struct Pass1 : public ModulePass {
33 static char ID;
34
35public:
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};
43char Pass1::ID;
44
45struct Pass2 : public ModulePass {
46 static char ID;
47
48public:
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};
56char Pass2::ID;
57} // namespace
58} // namespace llvm
59
60INITIALIZE_PASS(Pass1, "Pass1", "Pass1", false, false)
61INITIALIZE_PASS(Pass2, "Pass2", "Pass2", false, false)
62
63namespace {
64
65TEST(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
118class MyPass1 : public PassInfoMixin<MyPass1> {};
119class MyPass2 : public PassInfoMixin<MyPass2> {};
120
121TEST(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

source code of llvm/unittests/IR/TimePassesTest.cpp