• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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/graph_cloner.h"
24 #include "optimizer/ir/visualizer_printer.h"
25 
26 #include "optimizer/analysis/alias_analysis.h"
27 #include "optimizer/analysis/bounds_analysis.h"
28 #include "optimizer/analysis/catch_inputs.h"
29 #include "optimizer/analysis/dominators_tree.h"
30 #include "optimizer/analysis/linear_order.h"
31 #include "optimizer/analysis/liveness_analyzer.h"
32 #include "optimizer/analysis/live_registers.h"
33 #include "optimizer/analysis/loop_analyzer.h"
34 #include "optimizer/analysis/monitor_analysis.h"
35 #include "optimizer/analysis/object_type_propagation.h"
36 #include "optimizer/analysis/reg_alloc_verifier.h"
37 #include "optimizer/analysis/rpo.h"
38 #include "optimizer/analysis/types_analysis.h"
39 #include "optimizer/optimizations/cleanup.h"
40 
41 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
42 #define ENABLE_IR_DUMP
43 
44 #ifdef ENABLE_IR_DUMP
45 
46 #include <fstream>
47 #include <ctime>
48 #include "os/filesystem.h"
49 #endif  // ENABLE_IR_DUMP
50 
51 namespace ark::compiler {
PassManager(Graph * graph,PassManager * parentPm)52 PassManager::PassManager(Graph *graph, PassManager *parentPm)
53     : graph_(graph),
54       optimizations_(graph->GetAllocator()->Adapter()),
55       analyses_(details::PredefinedAnalyses::Instantiate<Analysis *>(graph_->GetAllocator(), graph_)),
56       stats_((parentPm == nullptr) ? graph->GetAllocator()->New<PassManagerStatistics>(graph)
57                                    : parentPm->GetStatistics())
58 {
59 }
60 
61 #ifdef ENABLE_IR_DUMP
ClearFileName(std::string str,std::string_view suffix)62 static std::string ClearFileName(std::string str, std::string_view suffix)
63 {
64     std::string delimiters = "~`@#$%^&*()-+=\\|/\"<>;,.[]";
65     for (const char &c : delimiters) {
66         std::replace(str.begin(), str.end(), c, '_');
67     }
68     return str.substr(0, NAME_MAX - suffix.size());
69 }
70 #endif
71 
GetFileName(const char * passName,const std::string & suffix)72 std::string PassManager::GetFileName([[maybe_unused]] const char *passName, [[maybe_unused]] const std::string &suffix)
73 {
74 #ifdef ENABLE_IR_DUMP
75     std::stringstream ssFilename;
76     std::stringstream ssFullpath;
77     ASSERT(GetGraph()->GetRuntime() != nullptr);
78 
79     const auto &folderName(g_options.GetCompilerDumpFolder());
80 
81     os::CreateDirectories(folderName);
82     constexpr auto IMM_3 = 3;
83     constexpr auto IMM_4 = 4;
84     ssFilename << std::setw(IMM_3) << std::setfill('0') << executionCounter_ << "_";
85     if (passName != nullptr) {
86         ssFilename << "pass_" << std::setw(IMM_4) << std::setfill('0') << stats_->GetCurrentPassIndex() << "_";
87     }
88     if (GetGraph()->GetParentGraph() != nullptr) {
89         ssFilename << "inlined_";
90     }
91     ssFilename << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
92                << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod());
93     if (GetGraph()->IsOsrMode()) {
94         ssFilename << "_OSR";
95     }
96     if (passName != nullptr) {
97         ssFilename << "_" << passName;
98     }
99     ssFullpath << folderName.c_str() << "/" << ClearFileName(ssFilename.str(), suffix) << suffix;
100     return ssFullpath.str();
101 #else
102     return "";
103 #endif  // ENABLE_IR_DUMP
104 }
105 
CleanupChecksForDump(Graph * graph)106 static void CleanupChecksForDump(Graph *graph)
107 {
108     for (auto *block : graph->GetVectorBlocks()) {
109         if (block == nullptr) {
110             continue;
111         }
112         for (auto inst : block->InstsSafe()) {
113             if (inst->IsCheck()) {
114                 inst->ReplaceUsers(Inst::GetDataFlowInput(inst));
115                 block->RemoveInst(inst);
116             }
117         }
118     }
119 }
120 
DumpGraph(const char * passName)121 void PassManager::DumpGraph([[maybe_unused]] const char *passName)
122 {
123 #ifdef ENABLE_IR_DUMP
124     std::string fileName = GetFileName(passName, ".ir");
125     std::ofstream strm(fileName);
126     if (!strm.is_open()) {
127         std::cerr << errno << " ERROR: " << strerror(errno) << "\n" << fileName << std::endl;
128     }
129     ASSERT(strm.is_open());
130     if (g_options.IsCompilerDumpNoChecks()) {
131         auto clone = GraphCloner(GetGraph(), GetAllocator(), GetLocalAllocator()).CloneGraph();
132         ASSERT(clone != nullptr);
133         clone->GetPassManager()->SetCheckMode(true);
134         CleanupChecksForDump(clone);
135         clone->Dump(&strm);
136     } else {
137         GetGraph()->Dump(&strm);
138     }
139 #endif  // ENABLE_IR_DUMP
140 }
DumpLifeIntervals(const char * passName)141 void PassManager::DumpLifeIntervals([[maybe_unused]] const char *passName)
142 {
143 #ifdef ENABLE_IR_DUMP
144     if (!GetGraph()->IsAnalysisValid<LivenessAnalyzer>()) {
145         return;
146     }
147     std::ofstream strm(GetFileName(passName, ".li"));
148     if (!strm.is_open()) {
149         std::cerr << errno << " ERROR: " << strerror(errno) << "\n" << GetFileName(passName, ".li") << std::endl;
150     }
151 
152     ASSERT(strm.is_open());
153     GetGraph()->GetAnalysis<LivenessAnalyzer>().DumpLifeIntervals(strm);
154 #endif  // ENABLE_IR_DUMP
155 }
InitialDumpVisualizerGraph()156 void PassManager::InitialDumpVisualizerGraph()
157 {
158 #ifdef ENABLE_IR_DUMP
159     std::ofstream strm(GetFileName());
160     strm << "begin_compilation\n";
161     strm << "  name \"" << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
162          << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod()) << "\"\n";
163     strm << "  method \"" << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
164          << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod()) << "\"\n";
165     strm << "  date " << std::time(nullptr) << "\n";
166     strm << "end_compilation\n";
167     strm.close();
168 #endif  // ENABLE_IR_DUMP
169 }
170 
DumpVisualizerGraph(const char * passName)171 void PassManager::DumpVisualizerGraph([[maybe_unused]] const char *passName)
172 {
173 #ifdef ENABLE_IR_DUMP
174     std::ofstream strm(GetFileName(), std::ios::app);
175     VisualizerPrinter(GetGraph(), &strm, passName).Print();
176     strm.close();
177 #endif  // ENABLE_IR_DUMP
178 }
179 
RunPass(Pass * pass,size_t localMemSizeBeforePass)180 bool PassManager::RunPass(Pass *pass, size_t localMemSizeBeforePass)
181 {
182     if (pass->IsAnalysis() && pass->IsValid()) {
183         return true;
184     }
185 
186     if (!pass->IsAnalysis() && !static_cast<Optimization *>(pass)->IsEnable()) {
187         return false;
188     }
189 
190     if (!IsCheckMode()) {
191         stats_->ProcessBeforeRun(*pass);
192         if (firstExecution_ && GetGraph()->GetParentGraph() == nullptr) {
193             StartExecution();
194             firstExecution_ = false;
195         }
196     }
197 
198 #ifndef NDEBUG
199     if (g_options.IsCompilerEnableTracing()) {
200         trace::BeginTracePoint(pass->GetPassName());
201     }
202 #endif  // NDEBUG
203 
204     bool result = pass->Run();
205 
206 #ifndef NDEBUG
207     if (g_options.IsCompilerEnableTracing()) {
208         trace::EndTracePoint();
209     }
210 #endif  // NDEBUG
211 
212     if (!IsCheckMode()) {
213         ASSERT(graph_->GetLocalAllocator()->GetAllocatedSize() >= localMemSizeBeforePass);
214         stats_->ProcessAfterRun(graph_->GetLocalAllocator()->GetAllocatedSize() - localMemSizeBeforePass);
215     }
216 
217     if (pass->IsAnalysis()) {
218         pass->SetValid(result);
219     }
220     bool isCodegen = std::string("Codegen") == pass->GetPassName();
221     if (g_options.IsCompilerDump() && pass->ShouldDump() && !IsCheckMode()) {
222         if (!g_options.IsCompilerDumpFinal() || isCodegen) {
223             DumpGraph(pass->GetPassName());
224         }
225     }
226 
227     if (g_options.IsCompilerVisualizerDump() && pass->ShouldDump()) {
228         DumpVisualizerGraph(pass->GetPassName());
229     }
230 
231     result &= RunPassChecker(pass, result, isCodegen);
232 
233     return result;
234 }
235 
RunPassChecker(Pass * pass,bool result,bool isCodegen)236 bool PassManager::RunPassChecker(Pass *pass, bool result, bool isCodegen)
237 {
238     if (graph_->IsAbcKit()) {
239         return RunPassChecker<true>(pass, result, isCodegen);
240     }
241 #ifndef NDEBUG
242     RunPassChecker<false>(pass, result, isCodegen);
243 #endif
244     return true;
245 }
246 
247 template <bool FORCE_RUN>
RunPassChecker(Pass * pass,bool result,bool isCodegen)248 bool PassManager::RunPassChecker(Pass *pass, bool result, bool isCodegen)
249 {
250     bool checkerEnabled = g_options.IsCompilerCheckGraph();
251     if (g_options.IsCompilerCheckFinal()) {
252         checkerEnabled = isCodegen;
253     }
254     if constexpr (FORCE_RUN) {
255         checkerEnabled = true;
256     }
257     if (result && !pass->IsAnalysis() && checkerEnabled) {
258         result &= GraphChecker(graph_, pass->GetPassName()).Check();
259     }
260     return result;
261 }
262 
GetAllocator()263 ArenaAllocator *PassManager::GetAllocator()
264 {
265     return graph_->GetAllocator();
266 }
267 
GetLocalAllocator()268 ArenaAllocator *PassManager::GetLocalAllocator()
269 {
270     return graph_->GetLocalAllocator();
271 }
272 
Finalize() const273 void PassManager::Finalize() const
274 {
275     if (g_options.IsCompilerPrintStats()) {
276         stats_->PrintStatistics();
277     }
278     if (g_options.WasSetCompilerDumpStatsCsv()) {
279         stats_->DumpStatisticsCsv();
280     }
281 }
282 }  // namespace ark::compiler
283