• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "dump.h"
25 #include "optimizer/analysis/linear_order.h"
26 #include "optimizer/analysis/rpo.h"
27 #include "optimizer/analysis/loop_analyzer.h"
28 #include "optimizer/code_generator/target_info.h"
29 
30 namespace ark::compiler {
31 
32 // indent constants for dump instructions
33 static const int INDENT_ID = 6;
34 static const int INDENT_TYPE = 5;
35 static const int INDENT_OPCODE = 27;
36 static const int HEX_PTR_SIZE = sizeof(void *);
37 
38 template <class T>
ToArenaString(T value,ArenaAllocator * allocator)39 std::enable_if_t<std::is_integral_v<T>, ArenaString> ToArenaString(T value, ArenaAllocator *allocator)
40 {
41     ArenaString res(std::to_string(value), allocator->Adapter());
42     return res;
43 }
44 
GetId(uint32_t id,ArenaAllocator * allocator)45 ArenaString GetId(uint32_t id, ArenaAllocator *allocator)
46 {
47     return (id == INVALID_ID ? ArenaString("XX", allocator->Adapter()) : ToArenaString(id, allocator));
48 }
49 
IdToString(uint32_t id,ArenaAllocator * allocator,bool vReg,bool isPhi)50 ArenaString IdToString(uint32_t id, ArenaAllocator *allocator, bool vReg, bool isPhi)
51 {
52     ArenaString reg(vReg ? "v" : "", allocator->Adapter());
53     ArenaString phi(isPhi ? "p" : "", allocator->Adapter());
54     return reg + GetId(id, allocator) + phi;
55 }
56 
57 // If print without brackets, then we print with space.
PrintIfValidLocation(Location location,Arch arch,std::ostream * out,bool withBrackets=false)58 void PrintIfValidLocation(Location location, Arch arch, std::ostream *out, bool withBrackets = false)
59 {
60     if (!location.IsInvalid() && !location.IsUnallocatedRegister()) {
61         auto string = location.ToString(arch);
62         if (withBrackets) {
63             (*out) << "(" << string << ")";
64         } else {
65             (*out) << string << " ";
66         }
67     }
68 }
69 
InstId(const Inst * inst,ArenaAllocator * allocator)70 ArenaString InstId(const Inst *inst, ArenaAllocator *allocator)
71 {
72     if (inst != nullptr) {
73         if (inst->IsSaveState() && g_options.IsCompilerDumpCompact()) {
74             return ArenaString("ss", allocator->Adapter()) +
75                    ArenaString(std::to_string(inst->GetId()), allocator->Adapter());
76         }
77         return IdToString(static_cast<uint32_t>(inst->GetId()), allocator, true, inst->IsPhi());
78     }
79     ArenaString null("null", allocator->Adapter());
80     return null;
81 }
82 
BBId(const BasicBlock * block,ArenaAllocator * allocator)83 ArenaString BBId(const BasicBlock *block, ArenaAllocator *allocator)
84 {
85     if (block != nullptr) {
86         return IdToString(static_cast<uint32_t>(block->GetId()), allocator);
87     }
88     ArenaString null("null", allocator->Adapter());
89     return null;
90 }
91 
DumpUsers(const Inst * inst,std::ostream * out)92 void DumpUsers(const Inst *inst, std::ostream *out)
93 {
94     auto allocator = inst->GetBasicBlock()->GetGraph()->GetLocalAllocator();
95     auto arch = inst->GetBasicBlock()->GetGraph()->GetArch();
96     for (size_t i = 0; i < inst->GetDstCount(); ++i) {
97         PrintIfValidLocation(inst->GetDstLocation(i), arch, out);
98     }
99     bool flFirst = true;
100     for (auto &nodeInst : inst->GetUsers()) {
101         auto user = nodeInst.GetInst();
102         (*out) << (flFirst ? "(" : ", ") << InstId(user, allocator);
103         if (flFirst) {
104             flFirst = false;
105         }
106     }
107     if (!flFirst) {
108         (*out) << ')';
109     }
110 }
111 
GetCondCodeToString(ConditionCode cc,ArenaAllocator * allocator)112 ArenaString GetCondCodeToString(ConditionCode cc, ArenaAllocator *allocator)
113 {
114     switch (cc) {
115         case ConditionCode::CC_EQ:
116             return ArenaString("EQ", allocator->Adapter());
117         case ConditionCode::CC_NE:
118             return ArenaString("NE", allocator->Adapter());
119 
120         case ConditionCode::CC_LT:
121             return ArenaString("LT", allocator->Adapter());
122         case ConditionCode::CC_LE:
123             return ArenaString("LE", allocator->Adapter());
124         case ConditionCode::CC_GT:
125             return ArenaString("GT", allocator->Adapter());
126         case ConditionCode::CC_GE:
127             return ArenaString("GE", allocator->Adapter());
128 
129         case ConditionCode::CC_B:
130             return ArenaString("B", allocator->Adapter());
131         case ConditionCode::CC_BE:
132             return ArenaString("BE", allocator->Adapter());
133         case ConditionCode::CC_A:
134             return ArenaString("A", allocator->Adapter());
135         case ConditionCode::CC_AE:
136             return ArenaString("AE", allocator->Adapter());
137 
138         case ConditionCode::CC_TST_EQ:
139             return ArenaString("TST_EQ", allocator->Adapter());
140         case ConditionCode::CC_TST_NE:
141             return ArenaString("TST_NE", allocator->Adapter());
142         default:
143             UNREACHABLE();
144     }
145 }
146 
PcToString(uint32_t pc,ArenaAllocator * allocator)147 ArenaString PcToString(uint32_t pc, ArenaAllocator *allocator)
148 {
149     std::ostringstream outString;
150     outString << "bc: 0x" << std::setfill('0') << std::setw(HEX_PTR_SIZE) << std::hex << pc;
151     return ArenaString(outString.str(), allocator->Adapter());
152 }
153 
154 template <typename T>
BBDependence(const char * type,const T & bbVector,std::ostream * out,ArenaAllocator * allocator)155 void BBDependence(const char *type, const T &bbVector, std::ostream *out, ArenaAllocator *allocator)
156 {
157     bool flFirst = true;
158     (*out) << type << ": [";
159     for (auto blockIt : bbVector) {
160         (*out) << (flFirst ? "" : ", ") << "bb " << BBId(blockIt, allocator);
161         if (flFirst) {
162             flFirst = false;
163         }
164     }
165     (*out) << ']';
166 }
167 
FieldToString(RuntimeInterface * runtime,ObjectType type,RuntimeInterface::FieldPtr field,ArenaAllocator * allocator)168 ArenaString FieldToString(RuntimeInterface *runtime, ObjectType type, RuntimeInterface::FieldPtr field,
169                           ArenaAllocator *allocator)
170 {
171     const auto &adapter = allocator->Adapter();
172     if (type != ObjectType::MEM_STATIC && type != ObjectType::MEM_OBJECT) {
173         return ArenaString(ObjectTypeToString(type), adapter);
174     }
175 
176     if (!runtime->HasFieldMetadata(field)) {
177         auto offset = runtime->GetFieldOffset(field);
178         return ArenaString("Unknown.Unknown", adapter) + ArenaString(std::to_string(offset), adapter);
179     }
180 
181     ArenaString dot(".", adapter);
182     ArenaString clsName(runtime->GetClassName(runtime->GetClassForField(field)), adapter);
183     ArenaString fieldName(runtime->GetFieldName(field), adapter);
184     return clsName + dot + fieldName;
185 }
186 
DumpTypedFieldOpcode(std::ostream * out,Opcode opcode,uint32_t typeId,const ArenaString & fieldName,ArenaAllocator * allocator)187 void DumpTypedFieldOpcode(std::ostream *out, Opcode opcode, uint32_t typeId, const ArenaString &fieldName,
188                           ArenaAllocator *allocator)
189 {
190     const auto &adapter = allocator->Adapter();
191     ArenaString space(" ", adapter);
192     ArenaString opc(GetOpcodeString(opcode), adapter);
193     ArenaString id(IdToString(typeId, allocator), adapter);
194     (*out) << std::setw(INDENT_OPCODE) << opc + space + id + space + fieldName + space;
195 }
196 
DumpTypedOpcode(std::ostream * out,Opcode opcode,uint32_t typeId,ArenaAllocator * allocator)197 void DumpTypedOpcode(std::ostream *out, Opcode opcode, uint32_t typeId, ArenaAllocator *allocator)
198 {
199     ArenaString space(" ", allocator->Adapter());
200     ArenaString opc(GetOpcodeString(opcode), allocator->Adapter());
201     ArenaString id(IdToString(typeId, allocator), allocator->Adapter());
202     (*out) << std::setw(INDENT_OPCODE) << opc + space + id + space;
203 }
204 
DumpTypedOpcode(std::ostream * out,Opcode opcode,uint32_t typeId,const ArenaString & flags,ArenaAllocator * allocator)205 void DumpTypedOpcode(std::ostream *out, Opcode opcode, uint32_t typeId, const ArenaString &flags,
206                      ArenaAllocator *allocator)
207 {
208     ArenaString space(" ", allocator->Adapter());
209     ArenaString opc(GetOpcodeString(opcode), allocator->Adapter());
210     ArenaString id(IdToString(typeId, allocator), allocator->Adapter());
211     (*out) << std::setw(INDENT_OPCODE) << opc + flags + space + id + space;
212 }
213 
DumpInputs(std::ostream * out) const214 bool Inst::DumpInputs(std::ostream *out) const
215 {
216     const auto &allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
217     auto arch = GetBasicBlock()->GetGraph()->GetArch();
218     bool flFirst = true;
219     unsigned i = 0;
220     for (auto nodeInst : GetInputs()) {
221         Inst *input = nodeInst.GetInst();
222         (*out) << (flFirst ? "" : ", ") << InstId(input, allocator);
223         PrintIfValidLocation(GetLocation(i), arch, out, true);
224         i++;
225         flFirst = false;
226     }
227 
228     if (!GetTmpLocation().IsInvalid()) {
229         (*out) << (flFirst ? "" : ", ") << "Tmp(" << GetTmpLocation().ToString(arch) << ")";
230     }
231 
232     return !flFirst;
233 }
234 
DumpInputs(std::ostream * out) const235 bool SaveStateInst::DumpInputs(std::ostream *out) const
236 {
237     const auto &allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
238     const char *sep = "";
239     for (size_t i = 0; i < GetInputsCount(); i++) {
240         (*out) << sep << std::dec << InstId(GetInput(i).GetInst(), allocator);
241         if (GetVirtualRegister(i).IsSpecialReg()) {
242             (*out) << "(" << VRegInfo::VRegTypeToString(GetVirtualRegister(i).GetVRegType()) << ")";
243         } else if (GetVirtualRegister(i).IsBridge()) {
244             (*out) << "(bridge)";
245         } else {
246             (*out) << "(vr" << GetVirtualRegister(i).Value() << ")";
247         }
248         sep = ", ";
249     }
250     if (GetImmediatesCount() > 0) {
251         for (auto imm : *GetImmediates()) {
252             (*out) << sep << std::hex << "0x" << imm.value;
253             if (imm.vregType == VRegType::VREG) {
254                 (*out) << std::dec << "(vr" << imm.vreg << ")";
255             } else {
256                 (*out) << "(" << VRegInfo::VRegTypeToString(imm.vregType) << ")";
257             }
258             sep = ", ";
259         }
260     }
261     if (GetCallerInst() != nullptr) {
262         (*out) << sep << "caller=" << GetCallerInst()->GetId();
263     }
264     (*out) << sep << "inlining_depth=" << GetInliningDepth();
265     return true;
266 }
267 
DumpInputs(std::ostream * out) const268 bool BinaryImmOperation::DumpInputs(std::ostream *out) const
269 {
270     Inst::DumpInputs(out);
271     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
272     return true;
273 }
274 
DumpInputs(std::ostream * out) const275 bool BinaryShiftedRegisterOperation::DumpInputs(std::ostream *out) const
276 {
277     Inst::DumpInputs(out);
278     (*out) << ", " << GetShiftTypeStr(GetShiftType()) << " 0x" << std::hex << GetImm() << std::dec;
279     return true;
280 }
281 
DumpInputs(std::ostream * out) const282 bool UnaryShiftedRegisterOperation::DumpInputs(std::ostream *out) const
283 {
284     Inst::DumpInputs(out);
285     (*out) << ", " << GetShiftTypeStr(GetShiftType()) << " 0x" << std::hex << GetImm() << std::dec;
286     return true;
287 }
288 
DumpInputs(std::ostream * out) const289 bool SelectImmInst::DumpInputs(std::ostream *out) const
290 {
291     Inst::DumpInputs(out);
292     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
293     return true;
294 }
295 
DumpInputs(std::ostream * out) const296 bool IfImmInst::DumpInputs(std::ostream *out) const
297 {
298     Inst::DumpInputs(out);
299     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
300     return true;
301 }
302 
DumpInputs(std::ostream * out) const303 bool PhiInst::DumpInputs(std::ostream *out) const
304 {
305     const auto &allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
306     bool flFirst = true;
307     for (size_t idx = 0; idx < GetInputsCount(); ++idx) {
308         Inst *input = GetInput(idx).GetInst();
309         auto block = GetPhiInputBb(idx);
310         (*out) << (flFirst ? "" : ", ") << InstId(input, allocator) << "(bb" << BBId(block, allocator) << ")";
311         if (flFirst) {
312             flFirst = false;
313         }
314     }
315     return !flFirst;
316 }
317 
DumpInputs(std::ostream * out) const318 bool ConstantInst::DumpInputs(std::ostream *out) const
319 {
320     switch (GetType()) {
321         case DataType::Type::REFERENCE:
322         case DataType::Type::BOOL:
323         case DataType::Type::UINT8:
324         case DataType::Type::INT8:
325         case DataType::Type::UINT16:
326         case DataType::Type::INT16:
327         case DataType::Type::UINT32:
328         case DataType::Type::INT32:
329         case DataType::Type::UINT64:
330         case DataType::Type::INT64:
331             (*out) << "0x" << std::hex << GetIntValue() << std::dec;
332             break;
333         case DataType::Type::FLOAT32:
334             (*out) << GetFloatValue();
335             break;
336         case DataType::Type::FLOAT64:
337             (*out) << GetDoubleValue();
338             break;
339         case DataType::Type::ANY:
340             (*out) << "0x" << std::hex << GetRawValue() << std::dec;
341             break;
342         default:
343             UNREACHABLE();
344     }
345     return true;
346 }
347 
DumpInputs(std::ostream * out) const348 bool SpillFillInst::DumpInputs(std::ostream *out) const
349 {
350     bool first = true;
351     for (auto spillFill : GetSpillFills()) {
352         if (!first) {
353             (*out) << ", ";
354         }
355         first = false;
356         (*out) << sf_data::ToString(spillFill, GetBasicBlock()->GetGraph()->GetArch());
357     }
358     return true;
359 }
360 
DumpInputs(std::ostream * out) const361 bool ParameterInst::DumpInputs(std::ostream *out) const
362 {
363     auto argNum = GetArgNumber();
364     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
365     ArenaString nums("nums", allocator->Adapter());
366     (*out) << "arg " << ((argNum == ParameterInst::DYNAMIC_NUM_ARGS) ? nums : IdToString(argNum, allocator));
367     return true;
368 }
369 
DumpOpcode(std::ostream * out) const370 void CompareInst::DumpOpcode(std::ostream *out) const
371 {
372     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
373     const auto &adapter = allocator->Adapter();
374     ArenaString space(" ", adapter);
375     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
376     ArenaString cc(GetCondCodeToString(GetCc(), allocator), adapter);
377     ArenaString type(DataType::ToString(GetOperandsType()), adapter);
378     (*out) << std::setw(INDENT_OPCODE) << opcode + space + cc + space + type;
379 }
380 
DumpOpcodeAnyTypeMixin(std::ostream & out,const Inst * inst)381 static void DumpOpcodeAnyTypeMixin(std::ostream &out, const Inst *inst)
382 {
383     const auto *mixinInst = static_cast<const AnyTypeMixin<FixedInputsInst1> *>(inst);
384     ASSERT(mixinInst != nullptr);
385     auto allocator = mixinInst->GetBasicBlock()->GetGraph()->GetLocalAllocator();
386     const auto &adapter = allocator->Adapter();
387     ArenaString space(" ", adapter);
388     ArenaString opcode(GetOpcodeString(mixinInst->GetOpcode()), adapter);
389     ArenaString anyBaseType(AnyTypeTypeToString(mixinInst->GetAnyType()), adapter);
390     out << std::setw(INDENT_OPCODE)
391         << opcode + space + anyBaseType + (mixinInst->IsIntegerWasSeen() ? " i" : "") +
392                (mixinInst->IsSpecialWasSeen() ? " s" : "") + (mixinInst->IsTypeWasProfiled() ? " p" : "") + space;
393 }
394 
DumpOpcode(std::ostream * out) const395 void PhiInst::DumpOpcode(std::ostream *out) const
396 {
397     if (GetBasicBlock()->GetGraph()->IsDynamicMethod()) {
398         DumpOpcodeAnyTypeMixin(*out, this);
399     } else {
400         Inst::DumpOpcode(out);
401     }
402 }
403 
DumpOpcode(std::ostream * out) const404 void CompareAnyTypeInst::DumpOpcode(std::ostream *out) const
405 {
406     DumpOpcodeAnyTypeMixin(*out, this);
407 }
408 
DumpOpcode(std::ostream * out) const409 void GetAnyTypeNameInst::DumpOpcode(std::ostream *out) const
410 {
411     DumpOpcodeAnyTypeMixin(*out, this);
412 }
413 
DumpOpcode(std::ostream * out) const414 void CastAnyTypeValueInst::DumpOpcode(std::ostream *out) const
415 {
416     DumpOpcodeAnyTypeMixin(*out, this);
417 }
418 
DumpOpcode(std::ostream * out) const419 void CastValueToAnyTypeInst::DumpOpcode(std::ostream *out) const
420 {
421     DumpOpcodeAnyTypeMixin(*out, this);
422 }
423 
DumpOpcode(std::ostream * out) const424 void AnyTypeCheckInst::DumpOpcode(std::ostream *out) const
425 {
426     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
427     const auto &adapter = allocator->Adapter();
428     ArenaString space(" ", adapter);
429     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
430     ArenaString anyBaseType(AnyTypeTypeToString(GetAnyType()), adapter);
431     (*out) << std::setw(INDENT_OPCODE)
432            << (opcode + space + anyBaseType + (IsIntegerWasSeen() ? " i" : "") + (IsSpecialWasSeen() ? " s" : "") +
433                (IsTypeWasProfiled() ? " p" : "") + space);
434 }
435 
DumpOpcode(std::ostream * out) const436 void HclassCheckInst::DumpOpcode(std::ostream *out) const
437 {
438     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
439     const auto &adapter = allocator->Adapter();
440     ArenaString space(" ", adapter);
441     ArenaString open("[", adapter);
442     ArenaString close("]", adapter);
443     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
444     bool isFirst = true;
445     ArenaString summary = opcode + space + open;
446     if (GetCheckIsFunction()) {
447         summary += ArenaString("IsFunc", adapter);
448         isFirst = false;
449     }
450     if (GetCheckFunctionIsNotClassConstructor()) {
451         if (!isFirst) {
452             summary += ArenaString(", ", adapter);
453         }
454         summary += ArenaString("IsNotClassConstr", adapter);
455     }
456     summary += close + space;
457     (*out) << std::setw(INDENT_OPCODE) << summary;
458 }
459 
DumpOpcode(std::ostream * out) const460 void LoadImmediateInst::DumpOpcode(std::ostream *out) const
461 {
462     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
463     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
464     ArenaString open("(", adapter);
465     ArenaString close(") ", adapter);
466     if (IsClass()) {
467         ArenaString type("class: ", adapter);
468         ArenaString className(GetBasicBlock()->GetGraph()->GetRuntime()->GetClassName(GetObject()), adapter);
469         (*out) << std::setw(INDENT_OPCODE) << opcode + open + type + className + close;
470     } else if (IsMethod()) {
471         ArenaString type("method: ", adapter);
472         ArenaString methodName(GetBasicBlock()->GetGraph()->GetRuntime()->GetMethodName(GetObject()), adapter);
473         (*out) << std::setw(INDENT_OPCODE) << opcode + open + type + methodName + close;
474     } else if (IsString()) {
475         ArenaString type("string: 0x", adapter);
476         (*out) << std::setw(INDENT_OPCODE) << opcode + open + type << std::hex << GetString() << close;
477     } else if (IsPandaFileOffset()) {
478         ArenaString type("PandaFileOffset: ", adapter);
479         (*out) << std::setw(INDENT_OPCODE) << opcode + open + type << std::hex << GetPandaFileOffset() << close;
480     } else if (IsConstantPool()) {
481         ArenaString type("constpool: 0x", adapter);
482         (*out) << std::setw(INDENT_OPCODE) << opcode + open + type << std::hex << GetConstantPool() << close;
483     } else if (IsObject()) {
484         ArenaString type("object: 0x", adapter);
485         (*out) << std::setw(INDENT_OPCODE) << opcode + open + type << std::hex << GetObject() << close;
486     } else if (IsTlsOffset()) {
487         ArenaString type("TlsOffset: 0x", adapter);
488         (*out) << std::setw(INDENT_OPCODE) << opcode + open + type << std::hex << GetTlsOffset() << close;
489     } else {
490         UNREACHABLE();
491     }
492 }
493 
DumpOpcode(std::ostream * out) const494 void FunctionImmediateInst::DumpOpcode(std::ostream *out) const
495 {
496     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
497     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
498     ArenaString prefix(" 0x", adapter);
499     (*out) << std::setw(INDENT_OPCODE) << opcode << prefix << std::hex << GetFunctionPtr() << " ";
500 }
501 
DumpOpcode(std::ostream * out) const502 void LoadObjFromConstInst::DumpOpcode(std::ostream *out) const
503 {
504     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
505     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
506     ArenaString prefix(" 0x", adapter);
507     (*out) << std::setw(INDENT_OPCODE) << opcode << prefix << std::hex << GetObjPtr() << " ";
508 }
509 
DumpOpcode(std::ostream * out) const510 void SelectInst::DumpOpcode(std::ostream *out) const
511 {
512     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
513     const auto &adapter = allocator->Adapter();
514     ArenaString space(" ", adapter);
515     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
516     ArenaString cc(GetCondCodeToString(GetCc(), allocator), adapter);
517     ArenaString type(DataType::ToString(GetOperandsType()), adapter);
518     (*out) << std::setw(INDENT_OPCODE) << opcode + space + cc + space + type;
519 }
520 
DumpOpcode(std::ostream * out) const521 void SelectImmInst::DumpOpcode(std::ostream *out) const
522 {
523     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
524     const auto &adapter = allocator->Adapter();
525     ArenaString space(" ", adapter);
526     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
527     ArenaString cc(GetCondCodeToString(GetCc(), allocator), adapter);
528     ArenaString type(DataType::ToString(GetOperandsType()), adapter);
529     (*out) << std::setw(INDENT_OPCODE) << opcode + space + cc + space + type;
530 }
531 
DumpOpcode(std::ostream * out) const532 void IfInst::DumpOpcode(std::ostream *out) const
533 {
534     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
535     const auto &adapter = allocator->Adapter();
536     ArenaString space(" ", adapter);
537     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
538     ArenaString cc(GetCondCodeToString(GetCc(), allocator), adapter);
539     ArenaString type(DataType::ToString(GetOperandsType()), adapter);
540     (*out) << std::setw(INDENT_OPCODE) << opcode + space + cc + space + type;
541 }
542 
DumpOpcode(std::ostream * out) const543 void IfImmInst::DumpOpcode(std::ostream *out) const
544 {
545     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
546     const auto &adapter = allocator->Adapter();
547     ArenaString space(" ", adapter);
548     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
549     ArenaString cc(GetCondCodeToString(GetCc(), allocator), adapter);
550     ArenaString type(DataType::ToString(GetOperandsType()), adapter);
551     (*out) << std::setw(INDENT_OPCODE) << opcode + space + cc + space + type;
552 }
553 
DumpOpcode(std::ostream * out) const554 void MonitorInst::DumpOpcode(std::ostream *out) const
555 {
556     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
557     ArenaString suffix(IsExit() ? ".Exit" : ".Entry", adapter);
558     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
559     (*out) << std::setw(INDENT_OPCODE) << opcode + suffix;
560 }
561 
DumpOpcode(std::ostream * out) const562 void CmpInst::DumpOpcode(std::ostream *out) const
563 {
564     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
565     auto type = GetOperandsType();
566     ArenaString suffix = ArenaString(" ", adapter) + ArenaString(DataType::ToString(type), adapter);
567     if (IsFloatType(type)) {
568         (*out) << std::setw(INDENT_OPCODE) << ArenaString(IsFcmpg() ? "Fcmpg" : "Fcmpl", adapter) + suffix;
569     } else if (IsTypeSigned(type)) {
570         (*out) << std::setw(INDENT_OPCODE) << ArenaString("Cmp", adapter) + ArenaString(" ", adapter) + suffix;
571     } else {
572         (*out) << std::setw(INDENT_OPCODE) << ArenaString("Ucmp", adapter) + suffix;
573     }
574 }
575 
DumpOpcode(std::ostream * out) const576 void CastInst::DumpOpcode(std::ostream *out) const
577 {
578     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
579     ArenaString space(" ", adapter);
580     (*out) << std::setw(INDENT_OPCODE)
581            << (ArenaString(GetOpcodeString(GetOpcode()), adapter) + space +
582                ArenaString(DataType::ToString(GetOperandsType()), adapter));
583 }
584 
DumpOpcode(std::ostream * out) const585 void NewObjectInst::DumpOpcode(std::ostream *out) const
586 {
587     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
588 }
589 
DumpOpcode(std::ostream * out) const590 void NewArrayInst::DumpOpcode(std::ostream *out) const
591 {
592     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
593     auto adapter = allocator->Adapter();
594     ArenaString space(" ", adapter);
595     ArenaString opc(GetOpcodeString(GetOpcode()), adapter);
596     ArenaString id(IdToString(GetTypeId(), allocator), adapter);
597     ArenaString size("", adapter);
598     ASSERT(GetInputsCount() > 1);
599     auto sizeInst = GetDataFlowInput(1);
600     if (sizeInst->IsConst()) {
601         auto sizeValue = sizeInst->CastToConstant()->GetIntValue();
602         size = ArenaString("(size=", adapter) + ToArenaString(sizeValue, allocator) + ")";
603     }
604     (*out) << std::setw(INDENT_OPCODE) << opc + space + size + space + id + space;
605 }
606 
DumpOpcode(std::ostream * out) const607 void LoadConstArrayInst::DumpOpcode(std::ostream *out) const
608 {
609     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
610 }
611 
DumpOpcode(std::ostream * out) const612 void FillConstArrayInst::DumpOpcode(std::ostream *out) const
613 {
614     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
615 }
616 
DumpOpcode(std::ostream * out) const617 void LoadObjectInst::DumpOpcode(std::ostream *out) const
618 {
619     auto graph = GetBasicBlock()->GetGraph();
620     auto fieldName = FieldToString(graph->GetRuntime(), GetObjectType(), GetObjField(), graph->GetLocalAllocator());
621     DumpTypedFieldOpcode(out, GetOpcode(), GetTypeId(), fieldName, graph->GetLocalAllocator());
622 }
623 
624 class ObjectPairParams {
625 public:
626     const Graph *graph;
627     Opcode opc;
628     RuntimeInterface::FieldPtr field0;
629     RuntimeInterface::FieldPtr field1;
630     uint32_t typeId0;
631     uint32_t typeId1;
632 };
633 
DumpObjectPairOpcode(std::ostream * out,ObjectPairParams & params)634 void DumpObjectPairOpcode(std::ostream *out, ObjectPairParams &params)
635 {
636     auto graph = params.graph;
637     auto runtime = graph->GetRuntime();
638     auto *allocator = graph->GetLocalAllocator();
639     const auto &adapter = allocator->Adapter();
640 
641     auto field0 = params.field0;
642     auto field1 = params.field1;
643 
644     ArenaString space(" ", adapter);
645     ArenaString dot(".", adapter);
646 
647     ArenaString clsName("", adapter);
648     ArenaString fieldName0("", adapter);
649     ArenaString fieldName1("", adapter);
650 
651     ArenaString id0(IdToString(params.typeId0, allocator), adapter);
652     auto offset0 = space + ArenaString(std::to_string(runtime->GetFieldOffset(field0)), adapter);
653     ArenaString id1(IdToString(params.typeId1, allocator), adapter);
654     auto offset1 = space + ArenaString(std::to_string(runtime->GetFieldOffset(field1)), adapter);
655     if (!runtime->HasFieldMetadata(field0)) {
656         clsName = ArenaString("Unknown ", adapter);
657         fieldName0 = id0 + space + dot + ArenaString(".Unknown", adapter) + offset0;
658         fieldName1 = id1 + space + dot + ArenaString(".Unknown", adapter) + offset1;
659     } else {
660         clsName = ArenaString(runtime->GetClassName(runtime->GetClassForField(field0)), adapter) + space;
661         fieldName0 = id0 + space + dot + ArenaString(runtime->GetFieldName(field0), adapter) + offset0;
662         fieldName1 = id1 + space + dot + ArenaString(runtime->GetFieldName(field1), adapter) + offset1;
663     }
664     ArenaString opc(GetOpcodeString(params.opc), adapter);
665     (*out) << std::setw(INDENT_OPCODE) << opc + space + clsName + space + fieldName0 + space + fieldName1 + space;
666 }
667 
DumpOpcode(std::ostream * out) const668 void LoadObjectPairInst::DumpOpcode(std::ostream *out) const
669 {
670     ObjectPairParams params {
671         GetBasicBlock()->GetGraph(), GetOpcode(), GetObjField0(), GetObjField1(), GetTypeId0(), GetTypeId1()};
672     DumpObjectPairOpcode(out, params);
673 }
674 
DumpOpcode(std::ostream * out) const675 void StoreObjectPairInst::DumpOpcode(std::ostream *out) const
676 {
677     ObjectPairParams params {
678         GetBasicBlock()->GetGraph(), GetOpcode(), GetObjField0(), GetObjField1(), GetTypeId0(), GetTypeId1()};
679     DumpObjectPairOpcode(out, params);
680 }
681 
DumpOpcode(std::ostream * out) const682 void LoadMemInst::DumpOpcode(std::ostream *out) const
683 {
684     DumpTypedOpcode(out, GetOpcode(), GetType(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
685 }
686 
DumpOpcode(std::ostream * out) const687 void ResolveObjectFieldInst::DumpOpcode(std::ostream *out) const
688 {
689     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
690 }
691 
DumpOpcode(std::ostream * out) const692 void LoadResolvedObjectFieldInst::DumpOpcode(std::ostream *out) const
693 {
694     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
695 }
696 
DumpOpcode(std::ostream * out) const697 void StoreObjectInst::DumpOpcode(std::ostream *out) const
698 {
699     auto graph = GetBasicBlock()->GetGraph();
700     auto fieldName = FieldToString(graph->GetRuntime(), GetObjectType(), GetObjField(), graph->GetLocalAllocator());
701     DumpTypedFieldOpcode(out, GetOpcode(), GetTypeId(), fieldName, graph->GetLocalAllocator());
702 }
703 
DumpOpcode(std::ostream * out) const704 void StoreResolvedObjectFieldInst::DumpOpcode(std::ostream *out) const
705 {
706     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
707 }
708 
DumpOpcode(std::ostream * out) const709 void StoreMemInst::DumpOpcode(std::ostream *out) const
710 {
711     DumpTypedOpcode(out, GetOpcode(), GetType(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
712 }
713 
DumpOpcode(std::ostream * out) const714 void LoadStaticInst::DumpOpcode(std::ostream *out) const
715 {
716     auto graph = GetBasicBlock()->GetGraph();
717     auto fieldName =
718         FieldToString(graph->GetRuntime(), ObjectType::MEM_STATIC, GetObjField(), graph->GetLocalAllocator());
719     DumpTypedFieldOpcode(out, GetOpcode(), GetTypeId(), fieldName, graph->GetLocalAllocator());
720 }
721 
DumpOpcode(std::ostream * out) const722 void ResolveObjectFieldStaticInst::DumpOpcode(std::ostream *out) const
723 {
724     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
725 }
726 
DumpOpcode(std::ostream * out) const727 void LoadResolvedObjectFieldStaticInst::DumpOpcode(std::ostream *out) const
728 {
729     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
730 }
731 
DumpOpcode(std::ostream * out) const732 void StoreStaticInst::DumpOpcode(std::ostream *out) const
733 {
734     auto graph = GetBasicBlock()->GetGraph();
735     auto fieldName =
736         FieldToString(graph->GetRuntime(), ObjectType::MEM_STATIC, GetObjField(), graph->GetLocalAllocator());
737     DumpTypedFieldOpcode(out, GetOpcode(), GetTypeId(), fieldName, graph->GetLocalAllocator());
738 }
739 
DumpOpcode(std::ostream * out) const740 void UnresolvedStoreStaticInst::DumpOpcode(std::ostream *out) const
741 {
742     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
743 }
744 
DumpOpcode(std::ostream * out) const745 void StoreResolvedObjectFieldStaticInst::DumpOpcode(std::ostream *out) const
746 {
747     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
748 }
749 
DumpOpcode(std::ostream * out) const750 void LoadFromPool::DumpOpcode(std::ostream *out) const
751 {
752     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
753 }
754 
DumpOpcode(std::ostream * out) const755 void LoadFromPoolDynamic::DumpOpcode(std::ostream *out) const
756 {
757     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
758 }
759 
DumpOpcode(std::ostream * out) const760 void ClassInst::DumpOpcode(std::ostream *out) const
761 {
762     auto graph = GetBasicBlock()->GetGraph();
763     auto allocator = graph->GetLocalAllocator();
764     const auto &adapter = allocator->Adapter();
765 
766     ArenaString opc(GetOpcodeString(GetOpcode()), adapter);
767     ArenaString space(" ", adapter);
768     ArenaString qt("'", adapter);
769     ArenaString className(GetClass() == nullptr ? ArenaString("", adapter)
770                                                 : ArenaString(graph->GetRuntime()->GetClassName(GetClass()), adapter));
771     (*out) << std::setw(INDENT_OPCODE) << opc + space + qt + className + qt << " ";
772 }
773 
DumpOpcode(std::ostream * out) const774 void RuntimeClassInst::DumpOpcode(std::ostream *out) const
775 {
776     auto graph = GetBasicBlock()->GetGraph();
777     auto allocator = graph->GetLocalAllocator();
778     const auto &adapter = allocator->Adapter();
779 
780     ArenaString space(" ", adapter);
781     ArenaString qt("'", adapter);
782     ArenaString opc(GetOpcodeString(GetOpcode()), adapter);
783     ArenaString className(GetClass() == nullptr ? ArenaString("", adapter)
784                                                 : ArenaString(graph->GetRuntime()->GetClassName(GetClass()), adapter));
785     (*out) << std::setw(INDENT_OPCODE) << opc + space + qt + className + qt << " ";
786 }
787 
DumpOpcode(std::ostream * out) const788 void GlobalVarInst::DumpOpcode(std::ostream *out) const
789 {
790     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
791 }
792 
DumpOpcode(std::ostream * out) const793 void CheckCastInst::DumpOpcode(std::ostream *out) const
794 {
795     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
796     const auto &adapter = allocator->Adapter();
797     ArenaString flags("", adapter);
798     if (CanDeoptimize()) {
799         flags = " D";
800     }
801     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), flags, allocator);
802 }
803 
DumpOpcode(std::ostream * out) const804 void IsInstanceInst::DumpOpcode(std::ostream *out) const
805 {
806     DumpTypedOpcode(out, GetOpcode(), GetTypeId(), GetBasicBlock()->GetGraph()->GetLocalAllocator());
807 }
808 
DumpOpcode(std::ostream * out) const809 void IntrinsicInst::DumpOpcode(std::ostream *out) const
810 {
811     const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
812     ArenaString intrinsic(IsBuiltin() ? ArenaString("BuiltinIntrinsic.", adapter) : ArenaString("Intrinsic.", adapter));
813     ArenaString opcode(GetIntrinsicName(intrinsicId_), adapter);
814     (*out) << std::setw(INDENT_OPCODE) << intrinsic + opcode << " ";
815 }
816 
DumpOpcode(std::ostream * out) const817 void Inst::DumpOpcode(std::ostream *out) const
818 {
819     auto graph = GetBasicBlock()->GetGraph();
820     auto allocator = graph->GetLocalAllocator();
821     const auto &adapter = allocator->Adapter();
822     ArenaString space(" ", adapter);
823     ArenaString flags("", adapter);
824     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
825     if (CanDeoptimize()) {
826         flags += "D";
827     }
828     if (GetFlag(inst_flags::MEM_BARRIER)) {
829         static constexpr auto FENCE = "F";
830         flags += FENCE;
831     }
832     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
833     (*out) << std::setw(INDENT_OPCODE) << opcode + space + flags;
834 }
835 
DumpOpcode(std::ostream * out) const836 void ResolveStaticInst::DumpOpcode(std::ostream *out) const
837 {
838     auto graph = GetBasicBlock()->GetGraph();
839     auto allocator = graph->GetLocalAllocator();
840     const auto &adapter = allocator->Adapter();
841     ArenaString methodId(ToArenaString(GetCallMethodId(), allocator));
842     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
843     if (GetCallMethod() != nullptr) {
844         ArenaString method(graph->GetRuntime()->GetMethodFullName(GetCallMethod()), adapter);
845         (*out) << std::setw(INDENT_OPCODE) << opcode + ' ' + methodId + ' ' + method << ' ';
846     } else {
847         (*out) << std::setw(INDENT_OPCODE) << opcode + ' ' + methodId << ' ';
848     }
849 }
850 
DumpOpcode(std::ostream * out) const851 void ResolveVirtualInst::DumpOpcode(std::ostream *out) const
852 {
853     auto graph = GetBasicBlock()->GetGraph();
854     auto allocator = graph->GetLocalAllocator();
855     const auto &adapter = allocator->Adapter();
856     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
857     ArenaString methodId(ToArenaString(GetCallMethodId(), allocator));
858     if (GetCallMethod() != nullptr) {
859         ArenaString method(graph->GetRuntime()->GetMethodFullName(GetCallMethod()), adapter);
860         (*out) << std::setw(INDENT_OPCODE) << opcode + ' ' + methodId + ' ' + method << ' ';
861     } else {
862         (*out) << std::setw(INDENT_OPCODE) << opcode + ' ' + methodId << ' ';
863     }
864 }
865 
DumpOpcode(std::ostream * out) const866 void InitStringInst::DumpOpcode(std::ostream *out) const
867 {
868     auto graph = GetBasicBlock()->GetGraph();
869     auto allocator = graph->GetLocalAllocator();
870     const auto &adapter = allocator->Adapter();
871     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
872     if (IsFromString()) {
873         ArenaString mode(" FromString", adapter);
874         (*out) << std::setw(INDENT_OPCODE) << opcode + mode << ' ';
875     } else {
876         ASSERT(IsFromCharArray());
877         ArenaString mode(" FromCharArray", adapter);
878         (*out) << std::setw(INDENT_OPCODE) << opcode + mode << ' ';
879     }
880 }
881 
DumpOpcode(std::ostream * out) const882 void CallInst::DumpOpcode(std::ostream *out) const
883 {
884     auto graph = GetBasicBlock()->GetGraph();
885     auto allocator = graph->GetLocalAllocator();
886     const auto &adapter = allocator->Adapter();
887     ArenaString space(" ", adapter);
888     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
889     ArenaString inlined(IsInlined() ? ".Inlined " : " ", adapter);
890     ArenaString methodId(ToArenaString(GetCallMethodId(), allocator));
891     if (!IsUnresolved() && GetCallMethod() != nullptr) {
892         ArenaString method(graph->GetRuntime()->GetMethodFullName(GetCallMethod()), adapter);
893         (*out) << std::setw(INDENT_OPCODE) << opcode + inlined + methodId + ' ' + method << ' ';
894     } else {
895         (*out) << std::setw(INDENT_OPCODE) << opcode + inlined + methodId << ' ';
896     }
897 }
898 
DumpOpcode(std::ostream * out) const899 void DeoptimizeInst::DumpOpcode(std::ostream *out) const
900 {
901     auto graph = GetBasicBlock()->GetGraph();
902     auto allocator = graph->GetLocalAllocator();
903     const auto &adapter = allocator->Adapter();
904     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
905     ArenaString type(DeoptimizeTypeToString(GetDeoptimizeType()), adapter);
906     (*out) << std::setw(INDENT_OPCODE) << opcode + ArenaString(" ", adapter) + type << ' ';
907 }
908 
DumpOpcode(std::ostream * out) const909 void DeoptimizeIfInst::DumpOpcode(std::ostream *out) const
910 {
911     auto graph = GetBasicBlock()->GetGraph();
912     auto allocator = graph->GetLocalAllocator();
913     const auto &adapter = allocator->Adapter();
914     ArenaString opcode(GetOpcodeString(GetOpcode()), adapter);
915     ArenaString type(DeoptimizeTypeToString(GetDeoptimizeType()), adapter);
916     (*out) << std::setw(INDENT_OPCODE) << opcode + ArenaString(" ", adapter) + type << ' ';
917 }
918 
DumpOpcode(std::ostream * out) const919 void DeoptimizeCompareInst::DumpOpcode(std::ostream *out) const
920 {
921     auto graph = GetBasicBlock()->GetGraph();
922     auto allocator = graph->GetLocalAllocator();
923     const auto &adapter = allocator->Adapter();
924     ArenaString opcode(ArenaString(GetOpcodeString(GetOpcode()), adapter).append(" "));
925     ArenaString cc(ArenaString(GetCondCodeToString(GetCc(), allocator), adapter).append(" "));
926     ArenaString cmpType(ArenaString(DataType::ToString(GetOperandsType()), adapter).append(" "));
927     ArenaString type(ArenaString(DeoptimizeTypeToString(GetDeoptimizeType()), adapter).append(" "));
928     (*out) << std::setw(INDENT_OPCODE) << opcode.append(cc).append(cmpType).append(type);
929 }
930 
DumpOpcode(std::ostream * out) const931 void DeoptimizeCompareImmInst::DumpOpcode(std::ostream *out) const
932 {
933     auto graph = GetBasicBlock()->GetGraph();
934     auto allocator = graph->GetLocalAllocator();
935     const auto &adapter = allocator->Adapter();
936     ArenaString opcode(ArenaString(GetOpcodeString(GetOpcode()), adapter).append(" "));
937     ArenaString cc(ArenaString(GetCondCodeToString(GetCc(), allocator), adapter).append(" "));
938     ArenaString type(ArenaString(DeoptimizeTypeToString(GetDeoptimizeType()), adapter).append(" "));
939     ArenaString cmpType(ArenaString(DataType::ToString(GetOperandsType()), adapter).append(" "));
940     (*out) << std::setw(INDENT_OPCODE) << opcode.append(cc).append(cmpType).append(type);
941 }
942 
DumpInputs(std::ostream * out) const943 bool DeoptimizeCompareImmInst::DumpInputs(std::ostream *out) const
944 {
945     Inst::DumpInputs(out);
946     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
947     return true;
948 }
949 
DumpInputs(std::ostream * out) const950 bool BoundsCheckInstI::DumpInputs(std::ostream *out) const
951 {
952     Inst *lenInput = GetInput(0).GetInst();
953     Inst *ssInput = GetInput(1).GetInst();
954     auto graph = GetBasicBlock()->GetGraph();
955     auto allocator = graph->GetLocalAllocator();
956 
957     (*out) << InstId(lenInput, allocator);
958     PrintIfValidLocation(GetLocation(0), graph->GetArch(), out, true);
959     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
960     (*out) << ", " << InstId(ssInput, allocator);
961     return true;
962 }
963 
DumpInputs(std::ostream * out) const964 bool StoreInstI::DumpInputs(std::ostream *out) const
965 {
966     Inst *arrInput = GetInput(0).GetInst();
967     Inst *ssInput = GetInput(1).GetInst();
968     auto graph = GetBasicBlock()->GetGraph();
969     auto arch = graph->GetArch();
970     const auto &allocator = graph->GetLocalAllocator();
971 
972     (*out) << InstId(arrInput, allocator);
973     PrintIfValidLocation(GetLocation(0), arch, out, true);
974     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
975     (*out) << ", " << InstId(ssInput, allocator);
976     PrintIfValidLocation(GetLocation(1), arch, out, true);
977     return true;
978 }
979 
DumpInputs(std::ostream * out) const980 bool StoreMemInstI::DumpInputs(std::ostream *out) const
981 {
982     Inst *arrInput = GetInput(0).GetInst();
983     Inst *ssInput = GetInput(1).GetInst();
984     auto graph = GetBasicBlock()->GetGraph();
985     const auto &allocator = graph->GetLocalAllocator();
986 
987     (*out) << InstId(arrInput, allocator);
988     PrintIfValidLocation(GetLocation(0), graph->GetArch(), out, true);
989     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
990     (*out) << ", " << InstId(ssInput, allocator);
991     return true;
992 }
993 
DumpInputs(std::ostream * out) const994 bool LoadInstI::DumpInputs(std::ostream *out) const
995 {
996     Inst::DumpInputs(out);
997     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
998     return true;
999 }
1000 
DumpInputs(std::ostream * out) const1001 bool LoadMemInstI::DumpInputs(std::ostream *out) const
1002 {
1003     Inst::DumpInputs(out);
1004     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
1005     return true;
1006 }
1007 
DumpInputs(std::ostream * out) const1008 bool LoadMemInst::DumpInputs(std::ostream *out) const
1009 {
1010     Inst::DumpInputs(out);
1011     if (GetScale() != 0) {
1012         (*out) << " Scale " << GetScale();
1013     }
1014     return true;
1015 }
1016 
DumpInputs(std::ostream * out) const1017 bool StoreMemInst::DumpInputs(std::ostream *out) const
1018 {
1019     Inst::DumpInputs(out);
1020     if (GetScale() != 0) {
1021         (*out) << " Scale " << GetScale();
1022     }
1023     return true;
1024 }
1025 
DumpInputs(std::ostream * out) const1026 bool LoadPairPartInst::DumpInputs(std::ostream *out) const
1027 {
1028     Inst *arrInput = GetInput(0).GetInst();
1029     auto graph = GetBasicBlock()->GetGraph();
1030     const auto &allocator = graph->GetLocalAllocator();
1031 
1032     (*out) << InstId(arrInput, allocator);
1033     PrintIfValidLocation(GetLocation(0), graph->GetArch(), out, true);
1034     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
1035     return true;
1036 }
1037 
DumpInputs(std::ostream * out) const1038 bool LoadArrayPairInst::DumpInputs(std::ostream *out) const
1039 {
1040     Inst::DumpInputs(out);
1041     if (GetImm() > 0) {
1042         (*out) << ", 0x" << std::hex << GetImm() << std::dec;
1043     }
1044     return true;
1045 }
1046 
DumpInputs(std::ostream * out) const1047 bool LoadArrayPairInstI::DumpInputs(std::ostream *out) const
1048 {
1049     Inst *arrInput = GetInput(0).GetInst();
1050     auto graph = GetBasicBlock()->GetGraph();
1051     const auto &allocator = graph->GetLocalAllocator();
1052     (*out) << InstId(arrInput, allocator);
1053     PrintIfValidLocation(GetLocation(0), graph->GetArch(), out, true);
1054     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
1055     return true;
1056 }
1057 
DumpInputs(std::ostream * out) const1058 bool StoreArrayPairInst::DumpInputs(std::ostream *out) const
1059 {
1060     Inst::DumpInputs(out);
1061     if (GetImm() > 0) {
1062         (*out) << ", 0x" << std::hex << GetImm() << std::dec;
1063     }
1064     return true;
1065 }
1066 
DumpInputs(std::ostream * out) const1067 bool StoreArrayPairInstI::DumpInputs(std::ostream *out) const
1068 {
1069     Inst *arrInput = GetInput(0).GetInst();
1070     Inst *fssInput = GetInput(1).GetInst();
1071     constexpr auto IMM_2 = 2;
1072     Inst *sssInput = GetInput(IMM_2).GetInst();
1073     auto graph = GetBasicBlock()->GetGraph();
1074     auto allocator = graph->GetLocalAllocator();
1075 
1076     (*out) << InstId(arrInput, allocator);
1077     PrintIfValidLocation(GetLocation(0), graph->GetArch(), out, true);
1078     (*out) << ", 0x" << std::hex << GetImm() << std::dec;
1079     (*out) << ", " << InstId(fssInput, allocator);
1080     (*out) << ", " << InstId(sssInput, allocator);
1081     return true;
1082 }
1083 
DumpInputs(std::ostream * out) const1084 bool ReturnInstI::DumpInputs(std::ostream *out) const
1085 {
1086     (*out) << "0x" << std::hex << GetImm() << std::dec;
1087     return true;
1088 }
1089 
DumpImms(std::ostream * out) const1090 void IntrinsicInst::DumpImms(std::ostream *out) const
1091 {
1092     if (!HasImms()) {
1093         return;
1094     }
1095 
1096     const auto &imms = GetImms();
1097     ASSERT(!imms.empty());
1098     (*out) << "0x" << std::hex << imms[0U];
1099     for (size_t i = 1U; i < imms.size(); ++i) {
1100         (*out) << ", 0x" << imms[i];
1101     }
1102     (*out) << ' ' << std::dec;
1103 }
1104 
DumpInputs(std::ostream * out) const1105 bool IntrinsicInst::DumpInputs(std::ostream *out) const
1106 {
1107     DumpImms(out);
1108     return Inst::DumpInputs(out);
1109 }
1110 
DumpBytecode(std::ostream * out) const1111 void Inst::DumpBytecode(std::ostream *out) const
1112 {
1113     if (pc_ != INVALID_PC) {
1114         auto graph = GetBasicBlock()->GetGraph();
1115         auto byteCode = graph->GetRuntime()->GetBytecodeString(graph->GetMethod(), pc_);
1116         if (!byteCode.empty()) {
1117             (*out) << byteCode << '\n';
1118         }
1119     }
1120 }
1121 
1122 #ifdef PANDA_COMPILER_DEBUG_INFO
DumpSourceLine(std::ostream * out) const1123 void Inst::DumpSourceLine(std::ostream *out) const
1124 {
1125     auto currentMethod = GetCurrentMethod();
1126     auto pc = GetPc();
1127     if (currentMethod != nullptr && pc != INVALID_PC) {
1128         auto line = GetBasicBlock()->GetGraph()->GetRuntime()->GetLineNumberAndSourceFile(currentMethod, pc);
1129         (*out) << " (" << line << " )";
1130     }
1131 }
1132 #endif  // PANDA_COMPILER_DEBUG_INFO
1133 
Dump(std::ostream * out,bool newLine) const1134 void Inst::Dump(std::ostream *out, bool newLine) const
1135 {
1136     // issue: #25677 - if GetBasicBlock() returns nullptr there will be segfault in GetBasicBlock()->GetGraph()
1137     if (g_options.IsCompilerDumpCompact() && (IsSaveState() || GetOpcode() == Opcode::NOP)) {
1138         return;
1139     }
1140     auto allocator = GetBasicBlock()->GetGraph()->GetLocalAllocator();
1141     // Id
1142     (*out) << std::setw(INDENT_ID) << std::setfill(' ') << std::right
1143            << IdToString(id_, allocator, false, IsPhi()) + '.';
1144     // Type
1145     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
1146     (*out) << std::setw(INDENT_TYPE) << std::left << DataType::ToString(GetType());
1147     // opcode
1148     DumpOpcode(out);
1149     auto operandsPos = out->tellp();
1150     // inputs
1151     bool hasInput = DumpInputs(out);
1152     // users
1153     if (hasInput && !GetUsers().Empty()) {
1154         (*out) << " -> ";
1155     }
1156     DumpUsers(this, out);
1157     // Align rest of the instruction info
1158     static constexpr auto ALIGN_BUF_SIZE = 64;
1159     if (auto posDiff = out->tellp() - operandsPos; posDiff < ALIGN_BUF_SIZE) {
1160         posDiff = ALIGN_BUF_SIZE - posDiff;
1161         static std::array<char, ALIGN_BUF_SIZE + 1> spaceBuf;
1162         if (spaceBuf[0] != ' ') {
1163             std::fill(spaceBuf.begin(), spaceBuf.end(), ' ');
1164         }
1165         spaceBuf[posDiff] = 0;
1166         (*out) << spaceBuf.data();
1167         spaceBuf[posDiff] = ' ';
1168     }
1169     // bytecode pointer
1170     if (pc_ != INVALID_PC && !g_options.IsCompilerDumpCompact()) {
1171         (*out) << ' ' << PcToString(pc_, allocator);
1172     }
1173 #ifdef PANDA_COMPILER_DEBUG_INFO
1174     if (g_options.IsCompilerDumpSourceLine()) {
1175         DumpSourceLine(out);
1176     }
1177 #endif
1178     if (newLine) {
1179         (*out) << '\n';
1180     }
1181     if (g_options.IsCompilerDumpBytecode()) {
1182         DumpBytecode(out);
1183     }
1184     if (GetOpcode() == Opcode::Parameter) {
1185         auto spillFill = static_cast<const ParameterInst *>(this)->GetLocationData();
1186         if (spillFill.DstValue() != GetInvalidReg()) {
1187             (*out) << sf_data::ToString(spillFill, GetBasicBlock()->GetGraph()->GetArch());
1188             if (newLine) {
1189                 *out << std::endl;
1190             }
1191         }
1192     }
1193 }
1194 
CheckPrintPropsFlag(std::ostream * out,bool * printPropsFlag)1195 void CheckPrintPropsFlag(std::ostream *out, bool *printPropsFlag)
1196 {
1197     if (!(*printPropsFlag)) {
1198         (*out) << "prop: ";
1199         (*printPropsFlag) = true;
1200     } else {
1201         (*out) << ", ";
1202     }
1203 }
1204 
PrintLoopInfo(std::ostream * out,Loop * loop)1205 void PrintLoopInfo(std::ostream *out, Loop *loop)
1206 {
1207     (*out) << "loop" << (loop->IsIrreducible() ? " (irreducible) " : " ") << loop->GetId();
1208     if (loop->GetDepth() > 0) {
1209         (*out) << ", depth " << loop->GetDepth();
1210     }
1211 }
1212 
CheckStartEnd(const BasicBlock * block,std::ostream * out,bool * printPropsFlag)1213 static void CheckStartEnd(const BasicBlock *block, std::ostream *out, bool *printPropsFlag)
1214 {
1215     if (block->IsStartBlock()) {
1216         CheckPrintPropsFlag(out, printPropsFlag);
1217         (*out) << "start";
1218     }
1219     if (block->IsEndBlock()) {
1220         CheckPrintPropsFlag(out, printPropsFlag);
1221         (*out) << "end";
1222     }
1223 }
1224 
CheckLoop(const BasicBlock * block,std::ostream * out,bool * printPropsFlag)1225 static void CheckLoop(const BasicBlock *block, std::ostream *out, bool *printPropsFlag)
1226 {
1227     if (block->IsLoopPreHeader()) {
1228         CheckPrintPropsFlag(out, printPropsFlag);
1229         (*out) << "prehead (loop " << block->GetNextLoop()->GetId() << ")";
1230     }
1231     if (block->IsLoopValid() && !block->GetLoop()->IsRoot()) {
1232         if (block->IsLoopHeader()) {
1233             CheckPrintPropsFlag(out, printPropsFlag);
1234             (*out) << "head";
1235         }
1236         CheckPrintPropsFlag(out, printPropsFlag);
1237         PrintLoopInfo(out, block->GetLoop());
1238     }
1239 }
1240 
CheckTryCatch(const BasicBlock * block,std::ostream * out,bool * printPropsFlag)1241 static void CheckTryCatch(const BasicBlock *block, std::ostream *out, bool *printPropsFlag)
1242 {
1243     if (block->IsTryBegin()) {
1244         CheckPrintPropsFlag(out, printPropsFlag);
1245         (*out) << "try_begin (id " << block->GetTryId() << ")";
1246     }
1247     if (block->IsTry()) {
1248         CheckPrintPropsFlag(out, printPropsFlag);
1249         (*out) << "try (id " << block->GetTryId() << ")";
1250     }
1251     if (block->IsTryEnd()) {
1252         CheckPrintPropsFlag(out, printPropsFlag);
1253         (*out) << "try_end (id " << block->GetTryId() << ")";
1254     }
1255     if (block->IsCatchBegin()) {
1256         CheckPrintPropsFlag(out, printPropsFlag);
1257         (*out) << "catch_begin";
1258     }
1259     if (block->IsCatch()) {
1260         CheckPrintPropsFlag(out, printPropsFlag);
1261         (*out) << "catch";
1262     }
1263 }
1264 
BlockProps(const BasicBlock * block,std::ostream * out)1265 void BlockProps(const BasicBlock *block, std::ostream *out)
1266 {
1267     bool printPropsFlag = false;
1268     CheckStartEnd(block, out, &printPropsFlag);
1269     CheckLoop(block, out, &printPropsFlag);
1270     CheckTryCatch(block, out, &printPropsFlag);
1271 
1272     if (block->GetGuestPc() != INVALID_PC) {
1273         CheckPrintPropsFlag(out, &printPropsFlag);
1274         (*out) << PcToString(block->GetGuestPc(), block->GetGraph()->GetLocalAllocator());
1275     }
1276     if (printPropsFlag) {
1277         (*out) << std::endl;
1278     }
1279 }
1280 
Dump(std::ostream * out) const1281 void BasicBlock::Dump(std::ostream *out) const
1282 {
1283     const auto &allocator = GetGraph()->GetLocalAllocator();
1284     (*out) << "BB " << IdToString(bbId_, allocator);
1285     // predecessors
1286     if (!preds_.empty()) {
1287         (*out) << "  ";
1288         BBDependence("preds", preds_, out, allocator);
1289     }
1290     (*out) << '\n';
1291     // properties
1292     BlockProps(this, out);
1293     (*out) << "hotness=" << GetHotness() << '\n';
1294     // instructions
1295     for (auto inst : this->AllInsts()) {
1296         inst->Dump(out);
1297     }
1298     // successors
1299     if (!succs_.empty()) {
1300         BBDependence("succs", succs_, out, allocator);
1301         (*out) << '\n';
1302     }
1303 }
1304 
Dump(std::ostream * out) const1305 void Graph::Dump(std::ostream *out) const
1306 {
1307     const auto &runtime = GetRuntime();
1308     const auto &method = GetMethod();
1309     const auto &adapter = GetLocalAllocator()->Adapter();
1310     ArenaString returnType(DataType::ToString(runtime->GetMethodReturnType(method)), adapter);
1311     (*out) << "Method: " << runtime->GetMethodFullName(method, true) << " " << method << std::endl;
1312     if (IsOsrMode()) {
1313         (*out) << "OSR mode\n";
1314     }
1315     (*out) << std::endl;
1316 
1317     auto &blocks = GetAnalysis<LinearOrder>().IsValid() ? GetBlocksLinearOrder() : GetBlocksRPO();
1318     for (const auto &blockIt : blocks) {
1319         if (!blockIt->GetPredsBlocks().empty() || !blockIt->GetSuccsBlocks().empty()) {
1320             blockIt->Dump(out);
1321             (*out) << '\n';
1322         } else {
1323             // to print the dump before cleanup, still unconnected nodes exist
1324             (*out) << "BB " << blockIt->GetId() << " is unconnected\n\n";
1325         }
1326     }
1327 }
1328 }  // namespace ark::compiler
1329