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
23 namespace berberis {
24
25 namespace {
26
GetInsnListDebugString(const char * indent,const MachineInsnList & insn_list)27 std::string GetInsnListDebugString(const char* indent, const MachineInsnList& insn_list) {
28 std::string out;
29 for (const auto* insn : insn_list) {
30 out += indent;
31 out += insn->GetDebugString();
32 out += "\n";
33 }
34 return out;
35 }
36
37 } // namespace
38
GetMachineRegDebugString(MachineReg r)39 std::string GetMachineRegDebugString(MachineReg r) {
40 if (r.IsHardReg()) {
41 return GetMachineHardRegDebugName(r);
42 }
43 if (r.IsVReg()) {
44 return StringPrintf("v%d", r.GetVRegIndex());
45 }
46 if (r.IsSpilledReg()) {
47 return StringPrintf("s%d", r.GetSpilledRegIndex());
48 }
49 return "?";
50 }
51
GetRegOperandDebugString(const MachineInsn * insn,int i)52 std::string GetRegOperandDebugString(const MachineInsn* insn, int i) {
53 MachineReg r = insn->RegAt(i);
54 std::string out;
55 if (r.IsVReg()) {
56 out += insn->RegKindAt(i).RegClass()->GetDebugName();
57 out += " ";
58 }
59 out += GetMachineRegDebugString(r);
60 return out;
61 }
62
GetDebugString() const63 std::string MachineBasicBlock::GetDebugString() const {
64 std::string out(StringPrintf("%2d MachineBasicBlock live_in=[", id()));
65
66 for (size_t i = 0; i < live_in().size(); ++i) {
67 if (i > 0) {
68 out += ", ";
69 }
70 out += GetMachineRegDebugString(live_in()[i]);
71 }
72 out += "] live_out=[";
73
74 for (size_t i = 0; i < live_out().size(); ++i) {
75 if (i > 0) {
76 out += ", ";
77 }
78 out += GetMachineRegDebugString(live_out()[i]);
79 }
80 out += "]\n";
81
82 for (const auto* edge : in_edges()) {
83 out += StringPrintf(" MachineEdge %d -> %d [\n", edge->src()->id(), edge->dst()->id());
84 out += GetInsnListDebugString(" ", edge->insn_list());
85 out += " ]\n";
86 }
87
88 out += GetInsnListDebugString(" ", insn_list());
89
90 return out;
91 }
92
GetDebugString() const93 std::string MachineIR::GetDebugString() const {
94 std::string out;
95 for (const auto* bb : bb_list()) {
96 out += bb->GetDebugString();
97 }
98 return out;
99 }
100
GetDebugStringForDot() const101 std::string MachineIR::GetDebugStringForDot() const {
102 std::string str;
103 str += "digraph MachineIR {\n";
104
105 for (const auto* bb : bb_list()) {
106 for (auto* in_edge : bb->in_edges()) {
107 auto* pred_bb = in_edge->src();
108
109 // Print edge.
110 str += StringPrintf("BB%d->BB%d", pred_bb->id(), bb->id());
111 str += ";\n";
112 }
113
114 // Print instructions with "\l" new-lines for left-justification.
115 str += StringPrintf("BB%d [shape=box,label=\"BB%d\\l", bb->id(), bb->id());
116 for (const auto* insn : bb->insn_list()) {
117 str += insn->GetDebugString();
118 str += "\\l";
119 }
120 str += "\"];\n";
121 }
122
123 str += "}\n";
124 return str;
125 }
126
GetDebugString() const127 std::string PseudoBranch::GetDebugString() const {
128 return StringPrintf("PSEUDO_BRANCH %d", then_bb()->id());
129 }
130
GetDebugString() const131 std::string PseudoCondBranch::GetDebugString() const {
132 std::string out("PSEUDO_COND_BRANCH ");
133 out += GetCondName(cond());
134 out += ", ";
135 out += StringPrintf("%d, ", then_bb()->id());
136 out += StringPrintf("%d, ", else_bb()->id());
137 out += StringPrintf("(%s)", GetRegOperandDebugString(this, 0).c_str());
138 return out;
139 }
140
GetDebugString() const141 std::string PseudoJump::GetDebugString() const {
142 const char* suffix;
143 switch (kind_) {
144 case Kind::kJumpWithPendingSignalsCheck:
145 suffix = "_SIG_CHECK";
146 break;
147 case Kind::kJumpWithoutPendingSignalsCheck:
148 suffix = "";
149 break;
150 case Kind::kSyscall:
151 suffix = "_TO_SYSCALL";
152 break;
153 case Kind::kExitGeneratedCode:
154 suffix = "_EXIT_GEN_CODE";
155 break;
156 }
157 return StringPrintf("PSEUDO_JUMP%s 0x%" PRIxPTR, suffix, target_);
158 }
159
GetDebugString() const160 std::string PseudoIndirectJump::GetDebugString() const {
161 std::string out("PSEUDO_INDIRECT_JUMP ");
162 out += GetMachineRegDebugString(src_);
163 return out;
164 }
165
GetDebugString() const166 std::string PseudoCopy::GetDebugString() const {
167 std::string out("PSEUDO_COPY ");
168 out += GetRegOperandDebugString(this, 0);
169 out += ", ";
170 out += GetRegOperandDebugString(this, 1);
171 return out;
172 }
173
GetDebugString() const174 std::string PseudoDefXReg::GetDebugString() const {
175 return std::string("PSEUDO_DEF ") + GetRegOperandDebugString(this, 0);
176 }
177
GetDebugString() const178 std::string PseudoDefReg::GetDebugString() const {
179 return std::string("PSEUDO_DEF ") + GetRegOperandDebugString(this, 0);
180 }
181
GetDebugString() const182 std::string PseudoReadFlags::GetDebugString() const {
183 std::string out("PSEUDO_READ_FLAGS ");
184 out += with_overflow() ? "" : "(skip overflow) ";
185 out += GetRegOperandDebugString(this, 0);
186 out += ", ";
187 out += GetRegOperandDebugString(this, 1);
188 return out;
189 }
190
GetDebugString() const191 std::string PseudoWriteFlags::GetDebugString() const {
192 std::string out("PSEUDO_WRITE_FLAGS ");
193 out += GetRegOperandDebugString(this, 0);
194 out += ", ";
195 out += GetRegOperandDebugString(this, 1);
196 return out;
197 }
198
199 } // namespace berberis
200