Skip to content

[clang][bytecode] Print jump lines in Function::dump() #135482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 152 additions & 25 deletions clang/lib/AST/ByteCode/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,39 +33,74 @@
using namespace clang;
using namespace clang::interp;

template <typename T> inline static T ReadArg(Program &P, CodePtr &OpPC) {
template <typename T>
inline static std::string printArg(Program &P, CodePtr &OpPC) {
if constexpr (std::is_pointer_v<T>) {
uint32_t ID = OpPC.read<uint32_t>();
return reinterpret_cast<T>(P.getNativePointer(ID));
std::string Result;
llvm::raw_string_ostream SS(Result);
SS << reinterpret_cast<T>(P.getNativePointer(ID));
return Result;
} else {
return OpPC.read<T>();
std::string Result;
llvm::raw_string_ostream SS(Result);
auto Arg = OpPC.read<T>();
SS << Arg;
return Result;
}
}

template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
Floating F = Floating::deserialize(*OpPC);
template <> inline std::string printArg<Floating>(Program &P, CodePtr &OpPC) {
auto F = Floating::deserialize(*OpPC);
OpPC += align(F.bytesToSerialize());
return F;

std::string Result;
llvm::raw_string_ostream SS(Result);
SS << F;
return Result;
}

template <>
inline IntegralAP<false> ReadArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
OpPC += align(I.bytesToSerialize());
return I;
}
inline std::string printArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
auto F = IntegralAP<false>::deserialize(*OpPC);
OpPC += align(F.bytesToSerialize());

std::string Result;
llvm::raw_string_ostream SS(Result);
SS << F;
return Result;
}
template <>
inline IntegralAP<true> ReadArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
OpPC += align(I.bytesToSerialize());
return I;
inline std::string printArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
auto F = IntegralAP<true>::deserialize(*OpPC);
OpPC += align(F.bytesToSerialize());

std::string Result;
llvm::raw_string_ostream SS(Result);
SS << F;
return Result;
}

template <> inline FixedPoint ReadArg<FixedPoint>(Program &P, CodePtr &OpPC) {
FixedPoint I = FixedPoint::deserialize(*OpPC);
OpPC += align(I.bytesToSerialize());
return I;
template <> inline std::string printArg<FixedPoint>(Program &P, CodePtr &OpPC) {
auto F = FixedPoint::deserialize(*OpPC);
OpPC += align(F.bytesToSerialize());

std::string Result;
llvm::raw_string_ostream SS(Result);
SS << F;
return Result;
}

static bool isJumpOpcode(Opcode Op) {
return Op == OP_Jmp || Op == OP_Jf || Op == OP_Jt;
}

static size_t getNumDisplayWidth(size_t N) {
unsigned L = 1u, M = 10u;
while (M <= N && ++L != std::numeric_limits<size_t>::digits10 + 1)
M *= 10u;

return L;
}

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

auto PrintName = [&OS](const char *Name) {
OS << Name;
long N = 30 - strlen(Name);
if (N > 0)
OS.indent(N);
struct OpText {
size_t Addr;
std::string Op;
bool IsJump;
llvm::SmallVector<std::string> Args;
};

auto PrintName = [](const char *Name) -> std::string {
return std::string(Name);
};

llvm::SmallVector<OpText> Code;
size_t LongestAddr = 0;
size_t LongestOp = 0;

for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
size_t Addr = PC - Start;
OpText Text;
auto Op = PC.read<Opcode>();
OS << llvm::format("%8d", Addr) << " ";
Text.Addr = Addr;
Text.IsJump = isJumpOpcode(Op);
switch (Op) {
#define GET_DISASM
#include "Opcodes.inc"
#undef GET_DISASM
}
Code.push_back(Text);
LongestOp = std::max(Text.Op.size(), LongestOp);
LongestAddr = std::max(getNumDisplayWidth(Addr), LongestAddr);
}

// Record jumps and their targets.
struct JmpData {
size_t From;
size_t To;
};
llvm::SmallVector<JmpData> Jumps;
for (auto &Text : Code) {
if (Text.IsJump)
Jumps.push_back({Text.Addr, Text.Addr + std::stoi(Text.Args[0]) +
align(sizeof(Opcode)) +
align(sizeof(int32_t))});
}

llvm::SmallVector<std::string> Text;
Text.reserve(Code.size());
size_t LongestLine = 0;
// Print code to a string, one at a time.
for (auto C : Code) {
std::string Line;
llvm::raw_string_ostream LS(Line);
LS << C.Addr;
LS.indent(LongestAddr - getNumDisplayWidth(C.Addr) + 4);
LS << C.Op;
LS.indent(LongestOp - C.Op.size() + 4);
for (auto &Arg : C.Args) {
LS << Arg << ' ';
}
Text.push_back(Line);
LongestLine = std::max(Line.size(), LongestLine);
}

assert(Code.size() == Text.size());

auto spaces = [](unsigned N) -> std::string {
std::string S;
for (unsigned I = 0; I != N; ++I)
S += ' ';
return S;
};

// Now, draw the jump lines.
for (auto &J : Jumps) {
if (J.To > J.From) {
bool FoundStart = false;
for (size_t LineIndex = 0; LineIndex != Text.size(); ++LineIndex) {
Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());

if (Code[LineIndex].Addr == J.From) {
Text[LineIndex] += " --+";
FoundStart = true;
} else if (Code[LineIndex].Addr == J.To) {
Text[LineIndex] += " <-+";
break;
} else if (FoundStart) {
Text[LineIndex] += " |";
}
}
LongestLine += 5;
} else {
bool FoundStart = false;
for (ssize_t LineIndex = Text.size() - 1; LineIndex >= 0; --LineIndex) {
Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());
if (Code[LineIndex].Addr == J.From) {
Text[LineIndex] += " --+";
FoundStart = true;
} else if (Code[LineIndex].Addr == J.To) {
Text[LineIndex] += " <-+";
break;
} else if (FoundStart) {
Text[LineIndex] += " |";
}
}
LongestLine += 5;
}
}

for (auto &Line : Text)
OS << Line << '\n';
}

LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
Expand Down
14 changes: 5 additions & 9 deletions clang/utils/TableGen/ClangOpcodesEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,12 @@ void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N,
OS << "#ifdef GET_DISASM\n";
Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
OS << "case OP_" << ID << ":\n";
OS << " PrintName(\"" << ID << "\");\n";
OS << " OS << \"\\t\"";
OS << " Text.Op = PrintName(\"" << ID << "\");\n";
for (const auto *Arg : R->getValueAsListOfDefs("Args"))
OS << " Text.Args.push_back(printArg<" << Arg->getValueAsString("Name")
<< ">(P, PC));\n";

for (const auto *Arg : R->getValueAsListOfDefs("Args")) {
OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";
OS << " << \" \"";
}

OS << " << \"\\n\";\n";
OS << " continue;\n";
OS << " break;\n";
});
OS << "#endif\n";
}
Expand Down