• 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 <iomanip>
17 #include <iostream>
18 #include <sstream>
19 #include <string>
20 #include "basicblock.h"
21 #include "compiler_options.h"
22 #include "inst.h"
23 #include "graph.h"
24 #include "optimizer/analysis/linear_order.h"
25 #include "optimizer/analysis/rpo.h"
26 #include "optimizer/analysis/loop_analyzer.h"
27 #include "dump.h"
28 
29 namespace panda::compiler {
30 
31 // indent constants for dump instructions
32 static const int INDENT_ID = 6;
33 static const int INDENT_TYPE = 5;
34 static const int INDENT_OPCODE = 27;
35 static const int HEX_PTR_SIZE = sizeof(void *);
36 
37 template <class T>
ToArenaString(T value,ArenaAllocator * allocator)38 std::enable_if_t<std::is_integral_v<T>, ArenaString> ToArenaString(T value, ArenaAllocator *allocator)
39 {
40     ArenaString res(std::to_string(value), allocator->Adapter());
41     return res;
42 }
43 
GetId(uint32_t id,ArenaAllocator * allocator)44 ArenaString GetId(uint32_t id, ArenaAllocator *allocator)
45 {
46     return (id == INVALID_ID ? ArenaString("XX", allocator->Adapter()) : ToArenaString(id, allocator));
47 }
48 
IdToString(uint32_t id,ArenaAllocator * allocator,bool v_reg,bool is_phi)49 ArenaString IdToString(uint32_t id, ArenaAllocator *allocator, bool v_reg, bool is_phi)
50 {
51     ArenaString reg(v_reg ? "v" : "", allocator->Adapter());
52     ArenaString phi(is_phi ? "p" : "", allocator->Adapter());
53     return reg + GetId(id, allocator) + phi;
54 }
55 
56 // If print without brackets, then we print with space.
PrintIfValidLocation(Location location,Arch arch,std::ostream * out,bool with_brackets=false)57 void PrintIfValidLocation(Location location, Arch arch, std::ostream *out, bool with_brackets = false)
58 {
59     if (!location.IsInvalid() && !location.IsUnallocatedRegister()) {
60         auto string = location.ToString(arch);
61         if (with_brackets) {
62             (*out) << "(" << string << ")";
63         } else {
64             (*out) << string << " ";
65         }
66     }
67 }
68 
InstId(const Inst * inst,ArenaAllocator * allocator)69 ArenaString InstId(const Inst *inst, ArenaAllocator *allocator)
70 {
71     if (inst != nullptr) {
72         if (inst->IsSaveState() && options.IsCompilerDumpCompact()) {
73             return ArenaString("ss", allocator->Adapter()) +
74                    ArenaString(std::to_string(inst->GetId()), allocator->Adapter());
75         }
76         return IdToString(static_cast<uint32_t>(inst->GetId()), allocator, true, inst->IsPhi());
77     }
78     ArenaString null("null", allocator->Adapter());
79     return null;
80 }
81 
BBId(const BasicBlock * block,ArenaAllocator * allocator)82 ArenaString BBId(const BasicBlock *block, ArenaAllocator *allocator)
83 {
84     if (block != nullptr) {
85         return IdToString(static_cast<uint32_t>(block->GetId()), allocator);
86     }
87     ArenaString null("null", allocator->Adapter());
88     return null;
89 }
90 
DumpUsers(const Inst * inst,std::ostream * out)91 void DumpUsers(const Inst *inst, std::ostream *out)
92 {
93     auto allocator = inst->GetBasicBlock()->GetGraph()->GetLocalAllocator();
94     auto arch = inst->GetBasicBlock()->GetGraph()->GetArch();
95     for (size_t i = 0; i < inst->GetDstCount(); ++i) {
96         PrintIfValidLocation(inst->GetDstLocation(), arch, out);
97     }
98     bool fl_first = true;
99     for (auto &node_inst : inst->GetUsers()) {
100         auto user = node_inst.GetInst();
101         (*out) << (fl_first ? "(" : ", ") << InstId(user, allocator);
102         if (fl_first) {
103             fl_first = false;
104         }
105     }
106     if (!fl_first) {
107         (*out) << ')';
108     }
109 }
110 
GetCondCodeToString(ConditionCode cc,ArenaAllocator * allocator)111 ArenaString GetCondCodeToString(ConditionCode cc, ArenaAllocator *allocator)
112 {
113     switch (cc) {
114         case ConditionCode::CC_EQ:
115             return ArenaString("EQ", allocator->Adapter());
116         case ConditionCode::CC_NE:
117             return ArenaString("NE", allocator->Adapter());
118 
119         case ConditionCode::CC_LT:
120             return ArenaString("LT", allocator->Adapter());
121         case ConditionCode::CC_LE:
122             return ArenaString("LE", allocator->Adapter());
123         case ConditionCode::CC_GT:
124             return ArenaString("GT", allocator->Adapter());
125         case ConditionCode::CC_GE:
126             return ArenaString("GE", allocator->Adapter());
127 
128         case ConditionCode::CC_B:
129             return ArenaString("B", allocator->Adapter());
130         case ConditionCode::CC_BE:
131             return ArenaString("BE", allocator->Adapter());
132         case ConditionCode::CC_A:
133             return ArenaString("A", allocator->Adapter());
134         case ConditionCode::CC_AE:
135             return ArenaString("AE", allocator->Adapter());
136 
137         case ConditionCode::CC_TST_EQ:
138             return ArenaString("TST_EQ", allocator->Adapter());
139         case ConditionCode::CC_TST_NE:
140             return ArenaString("TST_NE", allocator->Adapter());
141         default:
142             UNREACHABLE();
143     }
144 }
145 
PcToString(uint32_t pc,ArenaAllocator * allocator)146 ArenaString PcToString(uint32_t pc, ArenaAllocator *allocator)
147 {
148     std::ostringstream out_string;
149     out_string << "bc: 0x" << std::setfill('0') << std::setw(HEX_PTR_SIZE) << std::hex << pc;
150     return ArenaString(out_string.str(), allocator->Adapter());
151 }
152 
BBDependence(const char * type,const ArenaVector<BasicBlock * > & bb_vector,std::ostream * out,ArenaAllocator * allocator)153 void BBDependence(const char *type, const ArenaVector<BasicBlock *> &bb_vector, std::ostream *out,
154                   ArenaAllocator *allocator)
155 {
156     bool fl_first = true;
157     (*out) << type << ": [";
158     for (auto block_it : bb_vector) {
159         (*out) << (fl_first ? "" : ", ") << "bb " << BBId(block_it, allocator);
160         if (fl_first) {
161             fl_first = false;
162         }
163     }
164     (*out) << ']';
165 }
166 
DumpTypedFieldOpcode(std::ostream * out,Opcode opcode,uint32_t type_id,const ArenaString & field_name,ArenaAllocator * allocator)167 void DumpTypedFieldOpcode(std::ostream *out, Opcode opcode, uint32_t type_id, const ArenaString &field_name,
168                           ArenaAllocator *allocator)
169 {
170     const auto &adapter = allocator->Adapter();
171     ArenaString space(" ", adapter);
172     ArenaString opc(GetOpcodeString(opcode), adapter);
173     ArenaString id(IdToString(type_id, allocator), adapter);
174     (*out) << std::setw(INDENT_OPCODE) << opc + space + id + space + field_name + space;
175 }
176 
DumpTypedOpcode(std::ostream * out,Opcode opcode,uint32_t type_id,ArenaAllocator * allocator)177 void DumpTypedOpcode(std::ostream *out, Opcode opcode, uint32_t type_id, ArenaAllocator *allocator)
178 {
179     ArenaString space(" ", allocator->Adapter());
180     ArenaString opc(GetOpcodeString(opcode), allocator->Adapter());
181     ArenaString id(IdToString(type_id, allocator), allocator->Adapter());
182     (*out) << std::setw(INDENT_OPCODE) << opc + space + id;
183 }
184 
DumpInputs(std::ostream * out) const185 bool Inst::DumpInputs(std::ostream *out) const
186 {
187     const auto &allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
188     auto arch = GetBasicBlock()->GetGraph()->GetArch();
189     bool fl_first = true;
190     unsigned i = 0;
191     for (auto node_inst : GetInputs()) {
192         Inst *input = node_inst.GetInst();
193         (*out) << (fl_first ? "" : ", ") << InstId(input, allocator);
194         PrintIfValidLocation(GetLocation(i), arch, out, true);
195         i++;
196         fl_first = false;
197     }
198     return !fl_first;
199 }
200 
DumpInputs(std::ostream * out) const201 bool SaveStateInst::DumpInputs(std::ostream *out) const
202 {
203     const auto &allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
204     const char *sep = "";
205     for (size_t i = 0; i < GetInputsCount(); i++) {
206         (*out) << sep << std::dec << InstId(GetInput(i).GetInst(), allocator);
207         if (GetVirtualRegister(i).IsAccumulator()) {
208             (*out) << "(acc)";
209         } else {
210             (*out) << "(vr" << GetVirtualRegister(i).Value() << ")";
211         }
212         sep = ", ";
213     }
214     if (GetImmediatesCount() > 0) {
215         for (auto imm : *GetImmediates()) {
216             (*out) << sep << std::hex << "0x" << imm.value;
217             if (imm.is_acc) {
218                 (*out) << "(acc)";
219             } else {
220                 (*out) << std::dec << "(vr" << imm.vreg << ")";
221             }
222             sep = ", ";
223         }
224     }
225     return true;
226 }
227 
DumpInputs(std::ostream * out) const228 bool IfImmInst::DumpInputs(std::ostream *out) const
229 {
230     Inst::DumpInputs(out);
231     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
232     return true;
233 }
234 
DumpInputs(std::ostream * out) const235 bool PhiInst::DumpInputs(std::ostream *out) const
236 {
237     const auto &allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
238     bool fl_first = true;
239     for (size_t idx = 0; idx < GetInputsCount(); ++idx) {
240         Inst *input = GetInput(idx).GetInst();
241         auto block = GetPhiInputBb(idx);
242         (*out) << (fl_first ? "" : ", ") << InstId(input, allocator) << "(bb" << BBId(block, allocator) << ")";
243         if (fl_first) {
244             fl_first = false;
245         }
246     }
247     return !fl_first;
248 }
249 
DumpInputs(std::ostream * out) const250 bool ConstantInst::DumpInputs(std::ostream *out) const
251 {
252     switch (GetType()) {
253         case DataType::Type::REFERENCE:
254         case DataType::Type::BOOL:
255         case DataType::Type::UINT8:
256         case DataType::Type::INT8:
257         case DataType::Type::UINT16:
258         case DataType::Type::INT16:
259         case DataType::Type::UINT32:
260         case DataType::Type::INT32:
261         case DataType::Type::UINT64:
262         case DataType::Type::INT64:
263             (*out) << "0x" << std::hex << GetIntValue() << std::dec;
264             break;
265         case DataType::Type::FLOAT32:
266             (*out) << GetFloatValue();
267             break;
268         case DataType::Type::FLOAT64:
269             (*out) << GetDoubleValue();
270             break;
271         case DataType::Type::ANY:
272             (*out) << "0x" << std::hex << GetRawValue();
273             break;
274         default:
275             UNREACHABLE();
276     }
277     return true;
278 }
279 
DumpInputs(std::ostream * out) const280 bool SpillFillInst::DumpInputs(std::ostream *out) const
281 {
282     bool first = true;
283     for (auto spill_fill : GetSpillFills()) {
284         if (!first) {
285             (*out) << ", ";
286         }
287         first = false;
288         (*out) << sf_data::ToString(spill_fill, GetBasicBlock()->GetGraph()->GetArch());
289     }
290     return true;
291 }
292 
DumpInputs(std::ostream * out) const293 bool ParameterInst::DumpInputs(std::ostream *out) const
294 {
295     (*out) << "arg " << IdToString(GetArgNumber(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
296     return true;
297 }
298 
DumpOpcode(std::ostream * out) const299 void CompareInst::DumpOpcode(std::ostream *out) const
300 {
301     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
302     const auto &adapter = allocator->Adapter();
303     ArenaString space(" ", adapter);
304     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
305     ArenaString cc(GetCondCodeToString(GetCc(), allocator), adapter);
306     ArenaString type(DataType::ToString(GetOperandsType()), adapter);
307     (*out) << std::setw(INDENT_OPCODE) << opcode + space + cc + space + type;
308 }
309 
DumpOpcodeAnyTypeMixin(std::ostream & out,const Inst * inst)310 static void DumpOpcodeAnyTypeMixin(std::ostream &out, const Inst *inst)
311 {
312     const auto *mixin_inst = static_cast<const AnyTypeMixin<FixedInputsInst1> *>(inst);
313     ASSERT(mixin_inst != nullptr);
314     auto allocator = mixin_inst->GetBasicBlock()->GetGraph()->GetLocalAllocator();
315     const auto &adapter = allocator->Adapter();
316     ArenaString space(" ", adapter);
317     ArenaString opcode(GetOpcodeString(mixin_inst->GetOpcode()), adapter);
318     ArenaString any_base_type(AnyTypeTypeToString(mixin_inst->GetAnyType()), adapter);
319     out << std::setw(INDENT_OPCODE) << opcode + space + any_base_type + space;
320 }
321 
DumpOpcode(std::ostream * out) const322 void CompareAnyTypeInst::DumpOpcode(std::ostream *out) const
323 {
324     DumpOpcodeAnyTypeMixin(*out, this);
325 }
326 
DumpOpcode(std::ostream * out) const327 void CastAnyTypeValueInst::DumpOpcode(std::ostream *out) const
328 {
329     DumpOpcodeAnyTypeMixin(*out, this);
330 }
331 
DumpOpcode(std::ostream * out) const332 void CastValueToAnyTypeInst::DumpOpcode(std::ostream *out) const
333 {
334     DumpOpcodeAnyTypeMixin(*out, this);
335 }
336 
DumpOpcode(std::ostream * out) const337 void IfInst::DumpOpcode(std::ostream *out) const
338 {
339     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
340     const auto &adapter = allocator->Adapter();
341     ArenaString space(" ", adapter);
342     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
343     ArenaString cc(GetCondCodeToString(GetCc(), allocator), adapter);
344     ArenaString type(DataType::ToString(GetOperandsType()), adapter);
345     (*out) << std::setw(INDENT_OPCODE) << opcode + space + cc + space + type;
346 }
347 
DumpOpcode(std::ostream * out) const348 void IfImmInst::DumpOpcode(std::ostream *out) const
349 {
350     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
351     const auto &adapter = allocator->Adapter();
352     ArenaString space(" ", adapter);
353     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
354     ArenaString cc(GetCondCodeToString(GetCc(), allocator), adapter);
355     ArenaString type(DataType::ToString(GetOperandsType()), adapter);
356     (*out) << std::setw(INDENT_OPCODE) << opcode + space + cc + space + type;
357 }
358 
DumpOpcode(std::ostream * out) const359 void CmpInst::DumpOpcode(std::ostream *out) const
360 {
361     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
362     auto type = GetOperandsType();
363     ArenaString suffix = ArenaString(" ", adapter) + ArenaString(DataType::ToString(type), adapter);
364     if (IsFloatType(type)) {
365         (*out) << std::setw(INDENT_OPCODE) << ArenaString(IsFcmpg() ? "Fcmpg" : "Fcmpl", adapter) + suffix;
366     } else if (IsTypeSigned(type)) {
367         (*out) << std::setw(INDENT_OPCODE) << ArenaString("Cmp", adapter) + ArenaString(" ", adapter) + suffix;
368     } else {
369         (*out) << std::setw(INDENT_OPCODE) << ArenaString("Ucmp", adapter) + suffix;
370     }
371 }
372 
DumpOpcode(std::ostream * out) const373 void LoadFromPool::DumpOpcode(std::ostream *out) const
374 {
375     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
376 }
377 
DumpOpcode(std::ostream * out) const378 void IntrinsicInst::DumpOpcode(std::ostream *out) const
379 {
380     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
381     ArenaString intrinsic(ArenaString("Intrinsic.", adapter));
382     ArenaString opcode(GetIntrinsicOpcodeName(), adapter);
383     (*out) << std::setw(INDENT_OPCODE) << intrinsic + opcode << " ";
384 }
385 
DumpOpcode(std::ostream * out) const386 void Inst::DumpOpcode(std::ostream *out) const
387 {
388     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
389     (*out) << std::setw(INDENT_OPCODE) << GetOpcodeString(opcode_);
390 }
391 
Dump(std::ostream * out,bool new_line) const392 void Inst::Dump(std::ostream *out, bool new_line) const
393 {
394     if (options.IsCompilerDumpCompact() && IsSaveState()) {
395         return;
396     }
397     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
398     // Id
399     (*out) << std::setw(INDENT_ID) << std::setfill(' ') << std::right
400            << IdToString(id_, allocator, false, IsPhi()) + '.';
401     // Type
402     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
403     (*out) << std::setw(INDENT_TYPE) << std::left << DataType::ToString(GetType());
404     // opcode
405     DumpOpcode(out);
406     auto operands_pos = out->tellp();
407     // inputs
408     bool has_input = DumpInputs(out);
409     // users
410     if (has_input && !GetUsers().Empty()) {
411         (*out) << " -> ";
412     }
413     DumpUsers(this, out);
414     // Align rest of the instruction info
415     static constexpr auto ALIGN_BUF_SIZE = 64;
416     if (auto pos_diff = out->tellp() - operands_pos; pos_diff < ALIGN_BUF_SIZE) {
417         pos_diff = ALIGN_BUF_SIZE - pos_diff;
418         static std::array<char, ALIGN_BUF_SIZE + 1> space_buf;
419         if (space_buf[0] != ' ') {
420             std::fill(space_buf.begin(), space_buf.end(), ' ');
421         }
422         space_buf[pos_diff] = 0;
423         (*out) << space_buf.data();
424         space_buf[pos_diff] = ' ';
425     }
426     // bytecode pointer
427     if (pc_ != INVALID_PC && !options.IsCompilerDumpCompact()) {
428         (*out) << ' ' << PcToString(pc_, allocator);
429     }
430     if (new_line) {
431         (*out) << '\n';
432     }
433     if (GetOpcode() == Opcode::Parameter) {
434         auto spill_fill = static_cast<const ParameterInst *>(this)->GetLocationData();
435         if (spill_fill.DstValue() != INVALID_REG) {
436             (*out) << sf_data::ToString(spill_fill, GetBasicBlock()->GetGraph()->GetArch());
437             if (new_line) {
438                 *out << std::endl;
439             }
440         }
441     }
442 }
443 
CheckPrintPropsFlag(std::ostream * out,bool * print_props_flag)444 void CheckPrintPropsFlag(std::ostream *out, bool *print_props_flag)
445 {
446     if (!(*print_props_flag)) {
447         (*out) << "prop: ";
448         (*print_props_flag) = true;
449     } else {
450         (*out) << ", ";
451     }
452 }
453 
BlockProps(const BasicBlock * block,std::ostream * out)454 void BlockProps(const BasicBlock *block, std::ostream *out)
455 {
456     bool print_props_flag = false;
457     if (block->IsStartBlock()) {
458         CheckPrintPropsFlag(out, &print_props_flag);
459         (*out) << "start";
460     }
461     if (block->IsEndBlock()) {
462         CheckPrintPropsFlag(out, &print_props_flag);
463         (*out) << "end";
464     }
465     if (block->IsLoopValid() && !block->GetLoop()->IsRoot()) {
466         if (block->IsLoopHeader()) {
467             CheckPrintPropsFlag(out, &print_props_flag);
468             (*out) << "head";
469         }
470         CheckPrintPropsFlag(out, &print_props_flag);
471         (*out) << "loop" << (block->GetLoop()->IsIrreducible() ? " (irreducible) " : " ") << block->GetLoop()->GetId();
472     }
473     if (block->IsTryBegin()) {
474         CheckPrintPropsFlag(out, &print_props_flag);
475         (*out) << "try_begin (id " << block->GetTryId() << ")";
476     }
477     if (block->IsTry()) {
478         CheckPrintPropsFlag(out, &print_props_flag);
479         (*out) << "try (id " << block->GetTryId() << ")";
480     }
481     if (block->IsTryEnd()) {
482         CheckPrintPropsFlag(out, &print_props_flag);
483         (*out) << "try_end (id " << block->GetTryId() << ")";
484     }
485     if (block->IsCatchBegin()) {
486         CheckPrintPropsFlag(out, &print_props_flag);
487         (*out) << "catch_begin";
488     }
489     if (block->IsCatch()) {
490         CheckPrintPropsFlag(out, &print_props_flag);
491         (*out) << "catch";
492     }
493     if (block->IsCatchEnd()) {
494         CheckPrintPropsFlag(out, &print_props_flag);
495         (*out) << "catch_end";
496     }
497 
498     if (block->GetGuestPc() != INVALID_PC) {
499         CheckPrintPropsFlag(out, &print_props_flag);
500         (*out) << PcToString(block->GetGuestPc(), block->GetGraph()->GetLocalAllocator());
501     }
502     if (print_props_flag) {
503         (*out) << std::endl;
504     }
505 }
506 
Dump(std::ostream * out) const507 void BasicBlock::Dump(std::ostream *out) const
508 {
509     const auto &allocator = GetGraph()->GetLocalAllocator();
510     (*out) << "BB " << IdToString(bb_id_, allocator);
511     // predecessors
512     if (!preds_.empty()) {
513         (*out) << "  ";
514         BBDependence("preds", preds_, out, allocator);
515     }
516     (*out) << '\n';
517     // properties
518     BlockProps(this, out);
519     // instructions
520     for (auto inst : this->AllInsts()) {
521         inst->Dump(out);
522     }
523     // successors
524     if (!succs_.empty()) {
525         BBDependence("succs", succs_, out, allocator);
526         (*out) << '\n';
527     }
528 }
529 
Dump(std::ostream * out) const530 void Graph::Dump(std::ostream *out) const
531 {
532     const auto &runtime = GetRuntime();
533     const auto &method = GetMethod();
534     const auto &adapter = GetLocalAllocator()->Adapter();
535     ArenaString return_type(DataType::ToString(DataType::Type::ANY), adapter);
536     (*out) << "Method: " << runtime->GetMethodFullName(method, true) << std::endl;
537     if (IsOsrMode()) {
538         (*out) << "OSR mode\n";
539     }
540     (*out) << std::endl;
541 
542     auto &blocks = GetAnalysis<LinearOrder>().IsValid() ? GetBlocksLinearOrder() : GetBlocksRPO();
543     for (const auto &block_it : blocks) {
544         block_it->Dump(out);
545         (*out) << '\n';
546     }
547 }
548 }  // namespace panda::compiler
549