1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "berberis/backend/common/machine_ir.h"
18 
19 #include <string>
20 
21 #include "berberis/base/stringprintf.h"
22 #include "berberis/guest_state/guest_addr.h"
23 
24 namespace berberis {
25 
26 namespace {
27 
GetInsnListDebugString(const char * indent,const MachineInsnList & insn_list)28 std::string GetInsnListDebugString(const char* indent, const MachineInsnList& insn_list) {
29   std::string out;
30   for (const auto* insn : insn_list) {
31     out += indent;
32     out += insn->GetDebugString();
33     out += "\n";
34   }
35   return out;
36 }
37 
38 }  // namespace
39 
GetMachineRegDebugString(MachineReg r)40 std::string GetMachineRegDebugString(MachineReg r) {
41   if (r.IsHardReg()) {
42     return GetMachineHardRegDebugName(r);
43   }
44   if (r.IsVReg()) {
45     return StringPrintf("v%d", r.GetVRegIndex());
46   }
47   if (r.IsSpilledReg()) {
48     return StringPrintf("s%d", r.GetSpilledRegIndex());
49   }
50   return "?";
51 }
52 
GetRegOperandDebugString(const MachineInsn * insn,int i)53 std::string GetRegOperandDebugString(const MachineInsn* insn, int i) {
54   MachineReg r = insn->RegAt(i);
55   std::string out;
56   if (r.IsVReg()) {
57     out += insn->RegKindAt(i).RegClass()->GetDebugName();
58     out += " ";
59   }
60   out += GetMachineRegDebugString(r);
61   return out;
62 }
63 
GetDebugString() const64 std::string MachineBasicBlock::GetDebugString() const {
65   std::string out(StringPrintf("%2d MachineBasicBlock live_in=[", id()));
66 
67   for (size_t i = 0; i < live_in().size(); ++i) {
68     if (i > 0) {
69       out += ", ";
70     }
71     out += GetMachineRegDebugString(live_in()[i]);
72   }
73   out += "] live_out=[";
74 
75   for (size_t i = 0; i < live_out().size(); ++i) {
76     if (i > 0) {
77       out += ", ";
78     }
79     out += GetMachineRegDebugString(live_out()[i]);
80   }
81   out += "]\n";
82 
83   if (guest_addr() != kNullGuestAddr) {
84     // Profile counter may exist only if guest-addr is set, so we print them together.
85     out += StringPrintf("    [GuestAddr=%p ProfCounter=", ToHostAddr<void>(guest_addr()));
86     out += profile_counter().has_value() ? StringPrintf("%" PRIu32 "]", profile_counter().value())
87                                          : "unknown]";
88     out += "\n";
89   }
90 
91   for (const auto* edge : in_edges()) {
92     out += StringPrintf("    MachineEdge %d -> %d [\n", edge->src()->id(), edge->dst()->id());
93     out += GetInsnListDebugString("      ", edge->insn_list());
94     out += "    ]\n";
95   }
96 
97   out += GetInsnListDebugString("    ", insn_list());
98 
99   return out;
100 }
101 
GetDebugString() const102 std::string MachineIR::GetDebugString() const {
103   std::string out;
104   for (const auto* bb : bb_list()) {
105     out += bb->GetDebugString();
106   }
107   return out;
108 }
109 
GetDebugStringForDot() const110 std::string MachineIR::GetDebugStringForDot() const {
111   std::string str;
112   str += "digraph MachineIR {\n";
113 
114   for (const auto* bb : bb_list()) {
115     for (auto* in_edge : bb->in_edges()) {
116       auto* pred_bb = in_edge->src();
117 
118       // Print edge.
119       str += StringPrintf("BB%d->BB%d", pred_bb->id(), bb->id());
120       str += ";\n";
121     }
122 
123     // Print instructions with "\l" new-lines for left-justification.
124     str += StringPrintf("BB%d [shape=box,label=\"BB%d\\l", bb->id(), bb->id());
125     for (const auto* insn : bb->insn_list()) {
126       str += insn->GetDebugString();
127       str += "\\l";
128     }
129     str += "\"];\n";
130   }
131 
132   str += "}\n";
133   return str;
134 }
135 
GetDebugString() const136 std::string PseudoBranch::GetDebugString() const {
137   return StringPrintf("PSEUDO_BRANCH %d", then_bb()->id());
138 }
139 
GetDebugString() const140 std::string PseudoCondBranch::GetDebugString() const {
141   std::string out("PSEUDO_COND_BRANCH ");
142   out += GetCondName(cond());
143   out += ", ";
144   out += StringPrintf("%d, ", then_bb()->id());
145   out += StringPrintf("%d, ", else_bb()->id());
146   out += StringPrintf("(%s)", GetRegOperandDebugString(this, 0).c_str());
147   return out;
148 }
149 
GetDebugString() const150 std::string PseudoJump::GetDebugString() const {
151   const char* suffix;
152   switch (kind_) {
153     case Kind::kJumpWithPendingSignalsCheck:
154       suffix = "_SIG_CHECK";
155       break;
156     case Kind::kJumpWithoutPendingSignalsCheck:
157       suffix = "";
158       break;
159     case Kind::kSyscall:
160       suffix = "_TO_SYSCALL";
161       break;
162     case Kind::kExitGeneratedCode:
163       suffix = "_EXIT_GEN_CODE";
164       break;
165   }
166   return StringPrintf("PSEUDO_JUMP%s 0x%" PRIxPTR, suffix, target_);
167 }
168 
GetDebugString() const169 std::string PseudoIndirectJump::GetDebugString() const {
170   std::string out("PSEUDO_INDIRECT_JUMP ");
171   out += GetMachineRegDebugString(src_);
172   return out;
173 }
174 
GetDebugString() const175 std::string PseudoCopy::GetDebugString() const {
176   std::string out("PSEUDO_COPY ");
177   out += GetRegOperandDebugString(this, 0);
178   out += ", ";
179   out += GetRegOperandDebugString(this, 1);
180   return out;
181 }
182 
GetDebugString() const183 std::string PseudoDefXReg::GetDebugString() const {
184   return std::string("PSEUDO_DEF ") + GetRegOperandDebugString(this, 0);
185 }
186 
GetDebugString() const187 std::string PseudoDefReg::GetDebugString() const {
188   return std::string("PSEUDO_DEF ") + GetRegOperandDebugString(this, 0);
189 }
190 
GetDebugString() const191 std::string PseudoReadFlags::GetDebugString() const {
192   std::string out("PSEUDO_READ_FLAGS ");
193   out += with_overflow() ? "" : "(skip overflow) ";
194   out += GetRegOperandDebugString(this, 0);
195   out += ", ";
196   out += GetRegOperandDebugString(this, 1);
197   return out;
198 }
199 
GetDebugString() const200 std::string PseudoWriteFlags::GetDebugString() const {
201   std::string out("PSEUDO_WRITE_FLAGS ");
202   out += GetRegOperandDebugString(this, 0);
203   out += ", ";
204   out += GetRegOperandDebugString(this, 1);
205   return out;
206 }
207 
208 }  // namespace berberis
209