1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <iomanip>
17 #include "pass_manager.h"
18 #include "compiler_logger.h"
19 #include "trace/trace.h"
20
21 #include "optimizer/ir/graph.h"
22 #include "optimizer/ir/graph_checker.h"
23 #include "optimizer/ir/visualizer_printer.h"
24
25 #include "optimizer/analysis/alias_analysis.h"
26 #include "optimizer/analysis/bounds_analysis.h"
27 #include "optimizer/analysis/catch_inputs.h"
28 #include "optimizer/analysis/dominators_tree.h"
29 #include "optimizer/analysis/linear_order.h"
30 #include "optimizer/analysis/liveness_analyzer.h"
31 #include "optimizer/analysis/live_registers.h"
32 #include "optimizer/analysis/loop_analyzer.h"
33 #include "optimizer/analysis/monitor_analysis.h"
34 #include "optimizer/analysis/object_type_propagation.h"
35 #include "optimizer/analysis/reg_alloc_verifier.h"
36 #include "optimizer/analysis/rpo.h"
37 #include "optimizer/analysis/types_analysis.h"
38 #include "optimizer/optimizations/cleanup.h"
39
40 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
41 #define ENABLE_IR_DUMP
42
43 #ifdef ENABLE_IR_DUMP
44
45 #include <fstream>
46 #include <ctime>
47 #include "os/filesystem.h"
48 #endif // ENABLE_IR_DUMP
49
50 namespace ark::compiler {
PassManager(Graph * graph,PassManager * parentPm)51 PassManager::PassManager(Graph *graph, PassManager *parentPm)
52 : graph_(graph),
53 optimizations_(graph->GetAllocator()->Adapter()),
54 analyses_(details::PredefinedAnalyses::Instantiate<Analysis *>(graph_->GetAllocator(), graph_)),
55 stats_((parentPm == nullptr) ? graph->GetAllocator()->New<PassManagerStatistics>(graph)
56 : parentPm->GetStatistics())
57 {
58 }
59
60 #ifdef ENABLE_IR_DUMP
ClearFileName(std::string str,std::string_view suffix)61 static std::string ClearFileName(std::string str, std::string_view suffix)
62 {
63 std::string delimiters = "~`@#$%^&*()-+=\\|/\"<>;,.[]";
64 for (const char &c : delimiters) {
65 std::replace(str.begin(), str.end(), c, '_');
66 }
67 return str.substr(0, NAME_MAX - suffix.size());
68 }
69 #endif
70
GetFileName(const char * passName,const std::string & suffix)71 std::string PassManager::GetFileName([[maybe_unused]] const char *passName, [[maybe_unused]] const std::string &suffix)
72 {
73 #ifdef ENABLE_IR_DUMP
74 std::stringstream ssFilename;
75 std::stringstream ssFullpath;
76 ASSERT(GetGraph()->GetRuntime() != nullptr);
77
78 std::string folderName(g_options.GetCompilerDumpFolder());
79
80 os::CreateDirectories(folderName);
81 constexpr auto IMM_3 = 3;
82 constexpr auto IMM_4 = 4;
83 ssFilename << std::setw(IMM_3) << std::setfill('0') << executionCounter_ << "_";
84 if (passName != nullptr) {
85 ssFilename << "pass_" << std::setw(IMM_4) << std::setfill('0') << stats_->GetCurrentPassIndex() << "_";
86 }
87 if (GetGraph()->GetParentGraph() != nullptr) {
88 ssFilename << "inlined_";
89 }
90 ssFilename << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
91 << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod());
92 if (GetGraph()->IsOsrMode()) {
93 ssFilename << "_OSR";
94 }
95 if (passName != nullptr) {
96 ssFilename << "_" << passName;
97 }
98 ssFullpath << folderName.c_str() << "/" << ClearFileName(ssFilename.str(), suffix) << suffix;
99 return ssFullpath.str();
100 #else
101 return "";
102 #endif // ENABLE_IR_DUMP
103 }
DumpGraph(const char * passName)104 void PassManager::DumpGraph([[maybe_unused]] const char *passName)
105 {
106 #ifdef ENABLE_IR_DUMP
107 std::string fileName = GetFileName(passName, ".ir");
108 std::ofstream strm(fileName);
109 if (!strm.is_open()) {
110 std::cerr << errno << " ERROR: " << strerror(errno) << "\n" << fileName << std::endl;
111 }
112 ASSERT(strm.is_open());
113 GetGraph()->Dump(&strm);
114 LOG(DEBUG, COMPILER) << "Dump IR to " << fileName;
115 #endif // ENABLE_IR_DUMP
116 }
DumpLifeIntervals(const char * passName)117 void PassManager::DumpLifeIntervals([[maybe_unused]] const char *passName)
118 {
119 #ifdef ENABLE_IR_DUMP
120 if (!GetGraph()->IsAnalysisValid<LivenessAnalyzer>()) {
121 return;
122 }
123 std::ofstream strm(GetFileName(passName, ".li"));
124 if (!strm.is_open()) {
125 std::cerr << errno << " ERROR: " << strerror(errno) << "\n" << GetFileName(passName, ".li") << std::endl;
126 }
127
128 ASSERT(strm.is_open());
129 GetGraph()->GetAnalysis<LivenessAnalyzer>().DumpLifeIntervals(strm);
130 #endif // ENABLE_IR_DUMP
131 }
InitialDumpVisualizerGraph()132 void PassManager::InitialDumpVisualizerGraph()
133 {
134 #ifdef ENABLE_IR_DUMP
135 std::ofstream strm(GetFileName());
136 strm << "begin_compilation\n";
137 strm << " name \"" << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
138 << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod()) << "\"\n";
139 strm << " method \"" << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
140 << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod()) << "\"\n";
141 strm << " date " << std::time(nullptr) << "\n";
142 strm << "end_compilation\n";
143 strm.close();
144 #endif // ENABLE_IR_DUMP
145 }
146
DumpVisualizerGraph(const char * passName)147 void PassManager::DumpVisualizerGraph([[maybe_unused]] const char *passName)
148 {
149 #ifdef ENABLE_IR_DUMP
150 std::ofstream strm(GetFileName(), std::ios::app);
151 VisualizerPrinter(GetGraph(), &strm, passName).Print();
152 strm.close();
153 #endif // ENABLE_IR_DUMP
154 }
155
RunPass(Pass * pass,size_t localMemSizeBeforePass)156 bool PassManager::RunPass(Pass *pass, size_t localMemSizeBeforePass)
157 {
158 if (pass->IsAnalysis() && pass->IsValid()) {
159 return true;
160 }
161
162 if (!pass->IsAnalysis() && !static_cast<Optimization *>(pass)->IsEnable()) {
163 return false;
164 }
165
166 if (!IsCheckMode()) {
167 stats_->ProcessBeforeRun(*pass);
168 if (firstExecution_ && GetGraph()->GetParentGraph() == nullptr) {
169 StartExecution();
170 firstExecution_ = false;
171 }
172 }
173
174 #ifndef NDEBUG
175 if (g_options.IsCompilerEnableTracing()) {
176 trace::BeginTracePoint(pass->GetPassName());
177 }
178 #endif // NDEBUG
179
180 bool result = pass->Run();
181
182 #ifndef NDEBUG
183 if (g_options.IsCompilerEnableTracing()) {
184 trace::EndTracePoint();
185 }
186 #endif // NDEBUG
187
188 if (!IsCheckMode()) {
189 ASSERT(graph_->GetLocalAllocator()->GetAllocatedSize() >= localMemSizeBeforePass);
190 stats_->ProcessAfterRun(graph_->GetLocalAllocator()->GetAllocatedSize() - localMemSizeBeforePass);
191 }
192
193 if (pass->IsAnalysis()) {
194 pass->SetValid(result);
195 }
196 bool isCodegen = std::string("Codegen") == pass->GetPassName();
197 if (g_options.IsCompilerDump() && pass->ShouldDump() && !IsCheckMode()) {
198 if (!g_options.IsCompilerDumpFinal() || isCodegen) {
199 DumpGraph(pass->GetPassName());
200 }
201 }
202
203 if (g_options.IsCompilerVisualizerDump() && pass->ShouldDump()) {
204 DumpVisualizerGraph(pass->GetPassName());
205 }
206
207 #ifndef NDEBUG
208 RunPassChecker(pass, result, isCodegen);
209 #endif
210 return result;
211 }
212
RunPassChecker(Pass * pass,bool result,bool isCodegen)213 void PassManager::RunPassChecker(Pass *pass, bool result, bool isCodegen)
214 {
215 bool checkerEnabled = g_options.IsCompilerCheckGraph();
216 if (g_options.IsCompilerCheckFinal()) {
217 checkerEnabled = isCodegen;
218 }
219 if (result && !pass->IsAnalysis() && checkerEnabled) {
220 GraphChecker(graph_, pass->GetPassName()).Check();
221 }
222 }
223
GetAllocator()224 ArenaAllocator *PassManager::GetAllocator()
225 {
226 return graph_->GetAllocator();
227 }
228
GetLocalAllocator()229 ArenaAllocator *PassManager::GetLocalAllocator()
230 {
231 return graph_->GetLocalAllocator();
232 }
233
Finalize() const234 void PassManager::Finalize() const
235 {
236 if (g_options.IsCompilerPrintStats()) {
237 stats_->PrintStatistics();
238 }
239 if (g_options.WasSetCompilerDumpStatsCsv()) {
240 stats_->DumpStatisticsCsv();
241 }
242 }
243 } // namespace ark::compiler
244