• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #endif  // ENABLE_IR_DUMP
115 }
DumpLifeIntervals(const char * passName)116 void PassManager::DumpLifeIntervals([[maybe_unused]] const char *passName)
117 {
118 #ifdef ENABLE_IR_DUMP
119     if (!GetGraph()->IsAnalysisValid<LivenessAnalyzer>()) {
120         return;
121     }
122     std::ofstream strm(GetFileName(passName, ".li"));
123     if (!strm.is_open()) {
124         std::cerr << errno << " ERROR: " << strerror(errno) << "\n" << GetFileName(passName, ".li") << std::endl;
125     }
126 
127     ASSERT(strm.is_open());
128     GetGraph()->GetAnalysis<LivenessAnalyzer>().DumpLifeIntervals(strm);
129 #endif  // ENABLE_IR_DUMP
130 }
InitialDumpVisualizerGraph()131 void PassManager::InitialDumpVisualizerGraph()
132 {
133 #ifdef ENABLE_IR_DUMP
134     std::ofstream strm(GetFileName());
135     strm << "begin_compilation\n";
136     strm << "  name \"" << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
137          << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod()) << "\"\n";
138     strm << "  method \"" << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
139          << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod()) << "\"\n";
140     strm << "  date " << std::time(nullptr) << "\n";
141     strm << "end_compilation\n";
142     strm.close();
143 #endif  // ENABLE_IR_DUMP
144 }
145 
DumpVisualizerGraph(const char * passName)146 void PassManager::DumpVisualizerGraph([[maybe_unused]] const char *passName)
147 {
148 #ifdef ENABLE_IR_DUMP
149     std::ofstream strm(GetFileName(), std::ios::app);
150     VisualizerPrinter(GetGraph(), &strm, passName).Print();
151     strm.close();
152 #endif  // ENABLE_IR_DUMP
153 }
154 
RunPass(Pass * pass,size_t localMemSizeBeforePass)155 bool PassManager::RunPass(Pass *pass, size_t localMemSizeBeforePass)
156 {
157     if (pass->IsAnalysis() && pass->IsValid()) {
158         return true;
159     }
160 
161     if (!pass->IsAnalysis() && !static_cast<Optimization *>(pass)->IsEnable()) {
162         return false;
163     }
164 
165     if (!IsCheckMode()) {
166         stats_->ProcessBeforeRun(*pass);
167         if (firstExecution_ && GetGraph()->GetParentGraph() == nullptr) {
168             StartExecution();
169             firstExecution_ = false;
170         }
171     }
172 
173 #ifndef NDEBUG
174     if (g_options.IsCompilerEnableTracing()) {
175         trace::BeginTracePoint(pass->GetPassName());
176     }
177 #endif  // NDEBUG
178 
179     bool result = pass->Run();
180 
181 #ifndef NDEBUG
182     if (g_options.IsCompilerEnableTracing()) {
183         trace::EndTracePoint();
184     }
185 #endif  // NDEBUG
186 
187     if (!IsCheckMode()) {
188         ASSERT(graph_->GetLocalAllocator()->GetAllocatedSize() >= localMemSizeBeforePass);
189         stats_->ProcessAfterRun(graph_->GetLocalAllocator()->GetAllocatedSize() - localMemSizeBeforePass);
190     }
191 
192     if (pass->IsAnalysis()) {
193         pass->SetValid(result);
194     }
195     bool isCodegen = std::string("Codegen") == pass->GetPassName();
196     if (g_options.IsCompilerDump() && pass->ShouldDump() && !IsCheckMode()) {
197         if (!g_options.IsCompilerDumpFinal() || isCodegen) {
198             DumpGraph(pass->GetPassName());
199         }
200     }
201 
202     if (g_options.IsCompilerVisualizerDump() && pass->ShouldDump()) {
203         DumpVisualizerGraph(pass->GetPassName());
204     }
205 
206     result &= RunPassChecker(pass, result, isCodegen);
207 
208     return result;
209 }
210 
RunPassChecker(Pass * pass,bool result,bool isCodegen)211 bool PassManager::RunPassChecker(Pass *pass, bool result, bool isCodegen)
212 {
213     if (graph_->IsAbcKit()) {
214         return RunPassChecker<true>(pass, result, isCodegen);
215     }
216 #ifndef NDEBUG
217     RunPassChecker<false>(pass, result, isCodegen);
218 #endif
219     return true;
220 }
221 
222 template <bool FORCE_RUN>
RunPassChecker(Pass * pass,bool result,bool isCodegen)223 bool PassManager::RunPassChecker(Pass *pass, bool result, bool isCodegen)
224 {
225     bool checkerEnabled = g_options.IsCompilerCheckGraph();
226     if (g_options.IsCompilerCheckFinal()) {
227         checkerEnabled = isCodegen;
228     }
229     if constexpr (FORCE_RUN) {
230         checkerEnabled = true;
231     }
232     if (result && !pass->IsAnalysis() && checkerEnabled) {
233         result &= GraphChecker(graph_, pass->GetPassName()).Check();
234     }
235     return result;
236 }
237 
GetAllocator()238 ArenaAllocator *PassManager::GetAllocator()
239 {
240     return graph_->GetAllocator();
241 }
242 
GetLocalAllocator()243 ArenaAllocator *PassManager::GetLocalAllocator()
244 {
245     return graph_->GetLocalAllocator();
246 }
247 
Finalize() const248 void PassManager::Finalize() const
249 {
250     if (g_options.IsCompilerPrintStats()) {
251         stats_->PrintStatistics();
252     }
253     if (g_options.WasSetCompilerDumpStatsCsv()) {
254         stats_->DumpStatisticsCsv();
255     }
256 }
257 }  // namespace ark::compiler
258