• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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