1 /**
2 * Copyright (c) 2021-2022 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 "compiler_logger.h"
18 #include "trace/trace.h"
19 #include "pass_manager.h"
20
21 #include "optimizer/ir/graph.h"
22 #include "optimizer/ir/graph_checker.h"
23
24 #include "optimizer/analysis/dominators_tree.h"
25 #include "optimizer/analysis/linear_order.h"
26 #include "optimizer/analysis/liveness_analyzer.h"
27 #include "optimizer/analysis/loop_analyzer.h"
28 #include "optimizer/analysis/rpo.h"
29 #include "optimizer/optimizations/cleanup.h"
30
31 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
32 #define ENABLE_IR_DUMP
33
34 #ifdef ENABLE_IR_DUMP
35
36 #include <fstream>
37 #include <ctime>
38 #include "os/filesystem.h"
39 #endif // ENABLE_IR_DUMP
40
41 namespace panda::compiler {
PassManager(Graph * graph,PassManager * parent_pm)42 PassManager::PassManager(Graph *graph, PassManager *parent_pm)
43 : graph_(graph),
44 optimizations_(graph->GetAllocator()->Adapter()),
45 ANALYSES(details::PredefinedAnalyses::Instantiate<Analysis *>(graph_->GetAllocator(), graph_)),
46 stats_((parent_pm == nullptr) ? graph->GetAllocator()->New<PassManagerStatistics>(graph)
47 : parent_pm->GetStatistics())
48 {
49 }
50
51 #if defined(ENABLE_IR_DUMP) && !defined(PANDA_TARGET_MACOS)
ClearFileName(std::string str,std::string_view suffix)52 static std::string ClearFileName(std::string str, std::string_view suffix)
53 {
54 std::string delimiters = "~`@#$%^&*()-+=\\|/\"<>;,.[]";
55 for (const char &c : delimiters) {
56 std::replace(str.begin(), str.end(), c, '_');
57 }
58 return str.substr(0, NAME_MAX - suffix.size());
59 }
60 #endif // ENABLE_IR_DUMP && !PANDA_TARGET_MACOS
61
GetFileName(const char * pass_name,const std::string & suffix)62 std::string PassManager::GetFileName([[maybe_unused]] const char *pass_name, [[maybe_unused]] const std::string &suffix)
63 {
64 #if defined(ENABLE_IR_DUMP) && !defined(PANDA_TARGET_MACOS)
65 std::stringstream ss_filename;
66 std::stringstream ss_fullpath;
67 ASSERT(GetGraph()->GetRuntime() != nullptr);
68
69 std::string folder_name(options.GetCompilerDumpFolder());
70
71 os::CreateDirectories(folder_name);
72 constexpr auto IMM_3 = 3;
73 constexpr auto IMM_4 = 4;
74 ss_filename << std::setw(IMM_3) << std::setfill('0') << execution_counter << "_";
75 if (pass_name != nullptr) {
76 ss_filename << "pass_" << std::setw(IMM_4) << std::setfill('0') << stats_->GetCurrentPassIndex() << "_";
77 }
78 if (GetGraph()->GetParentGraph() != nullptr) {
79 ss_filename << "inlined_";
80 }
81 ss_filename << GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()) << "_"
82 << GetGraph()->GetRuntime()->GetMethodName(GetGraph()->GetMethod());
83 if (GetGraph()->IsOsrMode()) {
84 ss_filename << "_OSR";
85 }
86 if (pass_name != nullptr) {
87 ss_filename << "_" << pass_name;
88 }
89 ss_fullpath << folder_name.c_str() << "/" << ClearFileName(ss_filename.str(), suffix) << suffix;
90 return ss_fullpath.str();
91 #else
92 return "";
93 #endif // ENABLE_IR_DUMP && !PANDA_TARGET_MACOS
94 }
DumpGraph(const char * pass_name)95 void PassManager::DumpGraph([[maybe_unused]] const char *pass_name)
96 {
97 #if defined(ENABLE_IR_DUMP) && !defined(PANDA_TARGET_MACOS)
98 std::ofstream strm(GetFileName(pass_name, ".ir"));
99 if (!strm.is_open()) {
100 std::cerr << errno << " ERROR: " << strerror(errno) << "\n" << GetFileName(pass_name, ".ir") << std::endl;
101 }
102 ASSERT(strm.is_open());
103 GetGraph()->Dump(&strm);
104 #endif // ENABLE_IR_DUMP && !PANDA_TARGET_MACOS
105 }
DumpLifeIntervals(const char * pass_name)106 void PassManager::DumpLifeIntervals([[maybe_unused]] const char *pass_name)
107 {
108 #if defined(ENABLE_IR_DUMP) && !defined(PANDA_TARGET_MACOS)
109 if (!GetGraph()->IsAnalysisValid<LivenessAnalyzer>()) {
110 return;
111 }
112 std::ofstream strm(GetFileName(pass_name, ".li"));
113 if (!strm.is_open()) {
114 std::cerr << errno << " ERROR: " << strerror(errno) << "\n" << GetFileName(pass_name, ".li") << std::endl;
115 }
116
117 ASSERT(strm.is_open());
118 GetGraph()->GetAnalysis<LivenessAnalyzer>().DumpLifeIntervals(strm);
119 #endif // ENABLE_IR_DUMP && !PANDA_TARGET_MACOS
120 }
121
RunPass(Pass * pass,size_t local_mem_size_before_pass)122 bool PassManager::RunPass(Pass *pass, size_t local_mem_size_before_pass)
123 {
124 if (pass->IsAnalysis() && pass->IsValid()) {
125 return true;
126 }
127
128 if (!pass->IsAnalysis() && !static_cast<Optimization *>(pass)->IsEnable()) {
129 return false;
130 }
131
132 if (!IsCheckMode()) {
133 stats_->ProcessBeforeRun(*pass);
134 if (first_execution_ && GetGraph()->GetParentGraph() == nullptr) {
135 StartExecution();
136 first_execution_ = false;
137 }
138 }
139
140 #ifndef NDEBUG
141 if (options.IsCompilerEnableTracing()) {
142 trace::BeginTracePoint(pass->GetPassName());
143 }
144 #endif // NDEBUG
145
146 bool result = pass->Run();
147
148 #ifndef NDEBUG
149 if (options.IsCompilerEnableTracing()) {
150 trace::EndTracePoint();
151 }
152 #endif // NDEBUG
153
154 if (!IsCheckMode()) {
155 ASSERT(graph_->GetLocalAllocator()->GetAllocatedSize() >= local_mem_size_before_pass);
156 stats_->ProcessAfterRun(graph_->GetLocalAllocator()->GetAllocatedSize() - local_mem_size_before_pass);
157 }
158
159 if (pass->IsAnalysis()) {
160 pass->SetValid(result);
161 }
162 if (options.IsCompilerDump() && pass->ShouldDump() && !IsCheckMode()) {
163 if (!options.IsCompilerDumpFinal()) {
164 DumpGraph(pass->GetPassName());
165 }
166 }
167
168 #ifndef NDEBUG
169 bool checker_enabled = options.IsCompilerCheckGraph();
170 if (options.IsCompilerCheckFinal()) {
171 checker_enabled = false;
172 }
173 if (result && !pass->IsAnalysis() && checker_enabled) {
174 GraphChecker(graph_).Check();
175 }
176 #endif
177 return result;
178 }
179
GetAllocator()180 ArenaAllocator *PassManager::GetAllocator()
181 {
182 return graph_->GetAllocator();
183 }
184
GetLocalAllocator()185 ArenaAllocator *PassManager::GetLocalAllocator()
186 {
187 return graph_->GetLocalAllocator();
188 }
189
Finalize() const190 void PassManager::Finalize() const
191 {
192 if (options.IsCompilerPrintStats()) {
193 stats_->PrintStatistics();
194 }
195 if (options.WasSetCompilerDumpStatsCsv()) {
196 stats_->DumpStatisticsCsv();
197 }
198 }
199 } // namespace panda::compiler
200