Skip to content

Commit 578ca5e

Browse files
authored
[clang][bytecode] Print jump lines in Function::dump() (#135482)
E.g. for ```c++ constexpr int foo(int b) { int a = 1+1; for (int i = 0; i < b; ++i) { ++a; } return a; } ``` we now print: ``` foo 0x7cc8d4bf0580 frame size: 128 arg size: 8 rvo: 0 this arg: 0 0 InitScope 0 16 ConstSint32 1 32 ConstSint32 1 48 AddSint32 56 SetLocalSint32 40 72 ConstSint32 0 88 SetLocalSint32 104 104 GetPtrLocal 104 <-+ 120 LoadPopSint32 | 128 GetPtrParam 0 | 144 LoadPopSint32 | 152 LTSint32 | 160 Jf 80 --+ | 176 GetPtrLocal 40 | | 192 IncPopSint32 1 | | 208 GetPtrLocal 104 | | 224 IncPopSint32 1 | | 240 Jmp -152 | --+ 256 GetPtrLocal 40 <-+ 272 LoadPopSint32 280 Destroy 0 296 RetSint32 304 Destroy 0 320 NoRet ```
1 parent 1264d7a commit 578ca5e

File tree

2 files changed

+157
-34
lines changed

2 files changed

+157
-34
lines changed

clang/lib/AST/ByteCode/Disasm.cpp

Lines changed: 152 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,39 +33,74 @@
3333
using namespace clang;
3434
using namespace clang::interp;
3535

36-
template <typename T> inline static T ReadArg(Program &P, CodePtr &OpPC) {
36+
template <typename T>
37+
inline static std::string printArg(Program &P, CodePtr &OpPC) {
3738
if constexpr (std::is_pointer_v<T>) {
3839
uint32_t ID = OpPC.read<uint32_t>();
39-
return reinterpret_cast<T>(P.getNativePointer(ID));
40+
std::string Result;
41+
llvm::raw_string_ostream SS(Result);
42+
SS << reinterpret_cast<T>(P.getNativePointer(ID));
43+
return Result;
4044
} else {
41-
return OpPC.read<T>();
45+
std::string Result;
46+
llvm::raw_string_ostream SS(Result);
47+
auto Arg = OpPC.read<T>();
48+
SS << Arg;
49+
return Result;
4250
}
4351
}
4452

45-
template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
46-
Floating F = Floating::deserialize(*OpPC);
53+
template <> inline std::string printArg<Floating>(Program &P, CodePtr &OpPC) {
54+
auto F = Floating::deserialize(*OpPC);
4755
OpPC += align(F.bytesToSerialize());
48-
return F;
56+
57+
std::string Result;
58+
llvm::raw_string_ostream SS(Result);
59+
SS << F;
60+
return Result;
4961
}
5062

5163
template <>
52-
inline IntegralAP<false> ReadArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
53-
IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
54-
OpPC += align(I.bytesToSerialize());
55-
return I;
56-
}
64+
inline std::string printArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
65+
auto F = IntegralAP<false>::deserialize(*OpPC);
66+
OpPC += align(F.bytesToSerialize());
5767

68+
std::string Result;
69+
llvm::raw_string_ostream SS(Result);
70+
SS << F;
71+
return Result;
72+
}
5873
template <>
59-
inline IntegralAP<true> ReadArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
60-
IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
61-
OpPC += align(I.bytesToSerialize());
62-
return I;
74+
inline std::string printArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
75+
auto F = IntegralAP<true>::deserialize(*OpPC);
76+
OpPC += align(F.bytesToSerialize());
77+
78+
std::string Result;
79+
llvm::raw_string_ostream SS(Result);
80+
SS << F;
81+
return Result;
6382
}
6483

65-
template <> inline FixedPoint ReadArg<FixedPoint>(Program &P, CodePtr &OpPC) {
66-
FixedPoint I = FixedPoint::deserialize(*OpPC);
67-
OpPC += align(I.bytesToSerialize());
68-
return I;
84+
template <> inline std::string printArg<FixedPoint>(Program &P, CodePtr &OpPC) {
85+
auto F = FixedPoint::deserialize(*OpPC);
86+
OpPC += align(F.bytesToSerialize());
87+
88+
std::string Result;
89+
llvm::raw_string_ostream SS(Result);
90+
SS << F;
91+
return Result;
92+
}
93+
94+
static bool isJumpOpcode(Opcode Op) {
95+
return Op == OP_Jmp || Op == OP_Jf || Op == OP_Jt;
96+
}
97+
98+
static size_t getNumDisplayWidth(size_t N) {
99+
unsigned L = 1u, M = 10u;
100+
while (M <= N && ++L != std::numeric_limits<size_t>::digits10 + 1)
101+
M *= 10u;
102+
103+
return L;
69104
}
70105

71106
LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
@@ -80,23 +115,115 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
80115
OS << "rvo: " << hasRVO() << "\n";
81116
OS << "this arg: " << hasThisPointer() << "\n";
82117

83-
auto PrintName = [&OS](const char *Name) {
84-
OS << Name;
85-
long N = 30 - strlen(Name);
86-
if (N > 0)
87-
OS.indent(N);
118+
struct OpText {
119+
size_t Addr;
120+
std::string Op;
121+
bool IsJump;
122+
llvm::SmallVector<std::string> Args;
88123
};
89124

125+
auto PrintName = [](const char *Name) -> std::string {
126+
return std::string(Name);
127+
};
128+
129+
llvm::SmallVector<OpText> Code;
130+
size_t LongestAddr = 0;
131+
size_t LongestOp = 0;
132+
90133
for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
91134
size_t Addr = PC - Start;
135+
OpText Text;
92136
auto Op = PC.read<Opcode>();
93-
OS << llvm::format("%8d", Addr) << " ";
137+
Text.Addr = Addr;
138+
Text.IsJump = isJumpOpcode(Op);
94139
switch (Op) {
95140
#define GET_DISASM
96141
#include "Opcodes.inc"
97142
#undef GET_DISASM
98143
}
144+
Code.push_back(Text);
145+
LongestOp = std::max(Text.Op.size(), LongestOp);
146+
LongestAddr = std::max(getNumDisplayWidth(Addr), LongestAddr);
99147
}
148+
149+
// Record jumps and their targets.
150+
struct JmpData {
151+
size_t From;
152+
size_t To;
153+
};
154+
llvm::SmallVector<JmpData> Jumps;
155+
for (auto &Text : Code) {
156+
if (Text.IsJump)
157+
Jumps.push_back({Text.Addr, Text.Addr + std::stoi(Text.Args[0]) +
158+
align(sizeof(Opcode)) +
159+
align(sizeof(int32_t))});
160+
}
161+
162+
llvm::SmallVector<std::string> Text;
163+
Text.reserve(Code.size());
164+
size_t LongestLine = 0;
165+
// Print code to a string, one at a time.
166+
for (auto C : Code) {
167+
std::string Line;
168+
llvm::raw_string_ostream LS(Line);
169+
LS << C.Addr;
170+
LS.indent(LongestAddr - getNumDisplayWidth(C.Addr) + 4);
171+
LS << C.Op;
172+
LS.indent(LongestOp - C.Op.size() + 4);
173+
for (auto &Arg : C.Args) {
174+
LS << Arg << ' ';
175+
}
176+
Text.push_back(Line);
177+
LongestLine = std::max(Line.size(), LongestLine);
178+
}
179+
180+
assert(Code.size() == Text.size());
181+
182+
auto spaces = [](unsigned N) -> std::string {
183+
std::string S;
184+
for (unsigned I = 0; I != N; ++I)
185+
S += ' ';
186+
return S;
187+
};
188+
189+
// Now, draw the jump lines.
190+
for (auto &J : Jumps) {
191+
if (J.To > J.From) {
192+
bool FoundStart = false;
193+
for (size_t LineIndex = 0; LineIndex != Text.size(); ++LineIndex) {
194+
Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());
195+
196+
if (Code[LineIndex].Addr == J.From) {
197+
Text[LineIndex] += " --+";
198+
FoundStart = true;
199+
} else if (Code[LineIndex].Addr == J.To) {
200+
Text[LineIndex] += " <-+";
201+
break;
202+
} else if (FoundStart) {
203+
Text[LineIndex] += " |";
204+
}
205+
}
206+
LongestLine += 5;
207+
} else {
208+
bool FoundStart = false;
209+
for (ssize_t LineIndex = Text.size() - 1; LineIndex >= 0; --LineIndex) {
210+
Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());
211+
if (Code[LineIndex].Addr == J.From) {
212+
Text[LineIndex] += " --+";
213+
FoundStart = true;
214+
} else if (Code[LineIndex].Addr == J.To) {
215+
Text[LineIndex] += " <-+";
216+
break;
217+
} else if (FoundStart) {
218+
Text[LineIndex] += " |";
219+
}
220+
}
221+
LongestLine += 5;
222+
}
223+
}
224+
225+
for (auto &Line : Text)
226+
OS << Line << '\n';
100227
}
101228

102229
LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }

clang/utils/TableGen/ClangOpcodesEmitter.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,12 @@ void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N,
171171
OS << "#ifdef GET_DISASM\n";
172172
Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
173173
OS << "case OP_" << ID << ":\n";
174-
OS << " PrintName(\"" << ID << "\");\n";
175-
OS << " OS << \"\\t\"";
174+
OS << " Text.Op = PrintName(\"" << ID << "\");\n";
175+
for (const auto *Arg : R->getValueAsListOfDefs("Args"))
176+
OS << " Text.Args.push_back(printArg<" << Arg->getValueAsString("Name")
177+
<< ">(P, PC));\n";
176178

177-
for (const auto *Arg : R->getValueAsListOfDefs("Args")) {
178-
OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";
179-
OS << " << \" \"";
180-
}
181-
182-
OS << " << \"\\n\";\n";
183-
OS << " continue;\n";
179+
OS << " break;\n";
184180
});
185181
OS << "#endif\n";
186182
}

0 commit comments

Comments
 (0)