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