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 "disassembly.h"
17 #include "codegen.h"
18 #include <mutex>
19
20 namespace ark::compiler {
21
22 // clang-format off
23 static constexpr std::array INDENT_STRINGS = {
24 " ",
25 " ",
26 " ",
27 " ",
28 " ",
29 " ",
30 " ",
31 " ",
32 " ",
33 };
34 // clang-format on
35
GetIndent(uint32_t depth)36 std::string_view Disassembly::GetIndent(uint32_t depth)
37 {
38 return INDENT_STRINGS[depth];
39 }
40
__anond1ab6aaa0102(std::ostream *stream) 41 static constexpr auto STREAM_DELETER = [](std::ostream *stream) {
42 if (!g_options.IsCompilerDisasmDumpStdout()) {
43 delete stream;
44 }
45 };
46
Disassembly(const Codegen * codegen)47 Disassembly::Disassembly(const Codegen *codegen)
48 : codegen_(codegen),
49 encoder_(codegen->GetEncoder()),
50 stream_(nullptr, STREAM_DELETER),
51 isEnabled_(g_options.IsCompilerDisasmDump()),
52 isCodeEnabled_(isEnabled_ && g_options.IsCompilerDisasmDumpCode())
53 {
54 }
55
Init()56 void Disassembly::Init()
57 {
58 if (!IsEnabled()) {
59 return;
60 }
61 if (g_options.IsCompilerDisasmDumpStdout()) {
62 stream_.reset(&std::cout);
63 } else if (g_options.IsCompilerDisasmDumpSingleFile()) {
64 auto os = new std::ofstream;
65 if (os == nullptr) {
66 UNREACHABLE();
67 }
68 static std::once_flag flag;
69 auto fileName = g_options.GetCompilerDisasmDumpFileName();
70 std::call_once(flag, [&fileName]() { std::remove(fileName.c_str()); });
71 os->open(fileName, std::ios_base::app);
72 if (!os->is_open()) {
73 LOG(FATAL, COMPILER) << "Cannot open 'disasm.txt'";
74 }
75 stream_.reset(os);
76 } else {
77 auto os = new std::ofstream;
78 if (os == nullptr) {
79 UNREACHABLE();
80 }
81 std::stringstream ss;
82 auto graph = codegen_->GetGraph();
83 auto execNum = graph->GetPassManager()->GetExecutionCounter();
84 ss << "disasm_" << execNum << '_' << codegen_->GetRuntime()->GetClassNameFromMethod(graph->GetMethod()) << '_'
85 << codegen_->GetRuntime()->GetMethodName(graph->GetMethod()) << (graph->IsOsrMode() ? "_osr" : "") << ".txt";
86 os->open(ss.str());
87 if (!os->is_open()) {
88 LOG(FATAL, COMPILER) << "Cannot open '" << ss.str() << "'";
89 }
90 stream_.reset(os);
91 }
92 }
93
PrintChapter(std::string_view name)94 void Disassembly::PrintChapter(std::string_view name)
95 {
96 ItemAppender item(this);
97 item.GetStream() << name << ":\n";
98 }
99
IncreaseDepth()100 void Disassembly::IncreaseDepth()
101 {
102 if ((depth_ + 1) < INDENT_STRINGS.size()) {
103 depth_++;
104 }
105 }
106
PrintMethodEntry(const Codegen * codegen)107 void Disassembly::PrintMethodEntry(const Codegen *codegen)
108 {
109 constexpr const char *INDENT = " ";
110 auto graph = codegen->GetGraph();
111 {
112 ItemAppender item(this);
113 item.GetStream() << "#======================================================================\n";
114 }
115 PrintChapter("METHOD_INFO");
116 {
117 ItemAppender item(this);
118 item.GetStream() << INDENT << "name: " << codegen->GetRuntime()->GetMethodFullName(graph->GetMethod(), true)
119 << "\n";
120 item.GetStream() << INDENT << "mode: ";
121 graph->GetMode().Dump(item.GetStream());
122 item.GetStream() << "\n";
123 }
124 {
125 ItemAppender item(this);
126 item.GetStream() << INDENT << "id: " << codegen->GetRuntime()->GetMethodId(graph->GetMethod()) << "\n";
127 }
128 if (graph->IsAotMode()) {
129 ItemAppender item = ItemAppender(this);
130 item.GetStream() << INDENT << "code_offset: " << reinterpret_cast<void *>(graph->GetAotData()->GetCodeOffset())
131 << "\n";
132 }
133
134 {
135 auto arch = codegen->GetArch();
136 auto frame = codegen->GetFrameInfo();
137 ItemAppender item(this);
138 item.GetStream() << INDENT << "frame_size: " << frame->GetFrameSize() << "\n";
139 item.GetStream() << INDENT << "spills_count: " << frame->GetSpillsCount() << "\n";
140 item.GetStream() << INDENT << "Callees: " << (frame->GetCalleesRelativeFp() ? "fp" : "sp") << std::showpos
141 << frame->GetCalleesOffset() << std::noshowpos << " (" << GetCalleeRegsCount(arch, false)
142 << ")\n";
143 item.GetStream() << INDENT << "FpCallees: " << (frame->GetCalleesRelativeFp() ? "fp" : "sp") << std::showpos
144 << frame->GetFpCalleesOffset() << std::noshowpos << " (" << GetCalleeRegsCount(arch, true)
145 << ")\n";
146 item.GetStream() << INDENT << "Callers: " << (frame->GetCallersRelativeFp() ? "fp" : "sp") << std::showpos
147 << frame->GetCallersOffset() << std::noshowpos << " (" << GetCallerRegsCount(arch, false)
148 << ")\n";
149 item.GetStream() << INDENT << "FpCallers: " << (frame->GetCallersRelativeFp() ? "fp" : "sp") << std::showpos
150 << frame->GetFpCallersOffset() << std::noshowpos << " (" << GetCallerRegsCount(arch, true)
151 << ")\n";
152 }
153 if (IsCodeEnabled()) {
154 PrintChapter("DISASSEMBLY");
155 }
156 }
157
PrintCodeInfo(const Codegen * codegen)158 void Disassembly::PrintCodeInfo(const Codegen *codegen)
159 {
160 auto graph = codegen->GetGraph();
161
162 CodeInfo codeInfo;
163 ASSERT(!graph->GetCodeInfoData().empty());
164 codeInfo.Decode(graph->GetCodeInfoData());
165 PrintChapter("CODE_INFO");
166 ItemAppender item(this);
167 codeInfo.Dump(item.GetStream());
168 }
169
PrintCodeStatistics(const Codegen * codegen)170 void Disassembly::PrintCodeStatistics(const Codegen *codegen)
171 {
172 auto graph = codegen->GetGraph();
173
174 PrintChapter("CODE_STATS");
175 ItemAppender item(this);
176 item.GetStream() << " code_size: " << std::dec << graph->GetCode().Size() << "\n";
177 }
178
FlushDisasm()179 void Disassembly::FlushDisasm()
180 {
181 auto encoder = GetEncoder();
182 AddCode(GetPosition(), encoder->GetCursorOffset(), GetDepth());
183 SetPosition(encoder->GetCursorOffset());
184 }
185
PrintStackMap(const Codegen * codegen)186 void Disassembly::PrintStackMap(const Codegen *codegen)
187 {
188 FlushDisasm();
189 ItemAppender item(this);
190 item.GetStream() << GetIndent(GetDepth());
191 codegen->GetCodeBuilder()->DumpCurrentStackMap(item.GetStream());
192 item.GetStream() << "\n";
193 }
194
ScopedDisasmPrinter(Codegen * codegen,const Inst * inst)195 ScopedDisasmPrinter::ScopedDisasmPrinter(Codegen *codegen, const Inst *inst) : disasm_(codegen->GetDisasm())
196 {
197 if (disasm_->IsCodeEnabled()) {
198 disasm_->FlushDisasm();
199 ItemAppender item(disasm_);
200 item.GetStream() << disasm_->GetIndent(disasm_->GetDepth()) << "# [inst] " << *inst << "\n";
201 disasm_->IncreaseDepth();
202 }
203 }
204
ScopedDisasmPrinter(Codegen * codegen,const std::string & msg)205 ScopedDisasmPrinter::ScopedDisasmPrinter(Codegen *codegen, const std::string &msg) : disasm_(codegen->GetDisasm())
206 {
207 if (disasm_->IsCodeEnabled()) {
208 disasm_->FlushDisasm();
209 ItemAppender item(disasm_);
210 item.GetStream() << disasm_->GetIndent(disasm_->GetDepth()) << "# " << msg << "\n";
211 disasm_->IncreaseDepth();
212 }
213 }
214
~ScopedDisasmPrinter()215 ScopedDisasmPrinter::~ScopedDisasmPrinter()
216 {
217 if (disasm_->IsCodeEnabled()) {
218 disasm_->FlushDisasm();
219 disasm_->DecreaseDepth();
220 }
221 }
222
223 } // namespace ark::compiler
224