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