Skip to content
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

Add LLDB pretty-printing #8460

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .lldbinit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
command script import ./tools/lldbhalide.py
zvookin marked this conversation as resolved.
Show resolved Hide resolved
136 changes: 88 additions & 48 deletions src/IRPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,11 @@ void IRPrinter::print(const Stmt &ir) {
ir.accept(this);
}

void IRPrinter::print_summary(const Stmt &ir) {
ScopedValue<bool> old(is_summary, true);
ir.accept(this);
}

void IRPrinter::print_list(const std::vector<Expr> &exprs) {
for (size_t i = 0; i < exprs.size(); i++) {
print_no_parens(exprs[i]);
Expand Down Expand Up @@ -865,7 +870,9 @@ void IRPrinter::visit(const Let *op) {
stream << "let " << op->name << " = ";
print(op->value);
stream << " in ";
print(op->body);
if (!is_summary) {
print(op->body);
}
close();
}

Expand All @@ -875,7 +882,9 @@ void IRPrinter::visit(const LetStmt *op) {
print_no_parens(op->value);
stream << "\n";

print(op->body);
if (!is_summary) {
print(op->body);
}
}

void IRPrinter::visit(const AssertStmt *op) {
Expand Down Expand Up @@ -905,25 +914,18 @@ void IRPrinter::visit(const For *op) {
print_no_parens(op->min);
stream << ", ";
print_no_parens(op->extent);
stream << ") {\n";
stream << ") ";

indent++;
print(op->body);
indent--;

stream << get_indent() << "}\n";
print_braced_stmt(op->body);
}

void IRPrinter::visit(const Acquire *op) {
stream << get_indent() << "acquire (";
print_no_parens(op->semaphore);
stream << ", ";
print_no_parens(op->count);
stream << ") {\n";
indent++;
print(op->body);
indent--;
stream << get_indent() << "}\n";
stream << ") ";
print_braced_stmt(op->body, 1);
}

void IRPrinter::print_lets(const Let *let) {
Expand All @@ -932,7 +934,9 @@ void IRPrinter::print_lets(const Let *let) {
stream << "let " << let->name << " = ";
print_no_parens(let->value);
stream << " in\n";
if (const Let *next = let->body.as<Let>()) {
if (is_summary) {
stream << get_indent() << "...\n";
} else if (const Let *next = let->body.as<Let>()) {
print_lets(next);
} else {
stream << get_indent();
Expand All @@ -941,6 +945,19 @@ void IRPrinter::print_lets(const Let *let) {
}
}

void IRPrinter::print_braced_stmt(const Stmt &stmt, int extra_indent) {
if (is_summary) {
stream << "{ ... }\n";
return;
}

stream << "{\n";
indent += extra_indent;
print(stmt);
indent -= extra_indent;
stream << get_indent() << "}\n";
}

void IRPrinter::visit(const Store *op) {
stream << get_indent();
const bool has_pred = !is_const_one(op->predicate);
Expand Down Expand Up @@ -1038,7 +1055,10 @@ void IRPrinter::visit(const Allocate *op) {
stream << get_indent() << " custom_delete { " << op->free_function << "(" << op->name << "); }";
}
stream << "\n";
print(op->body);

if (!is_summary) {
print(op->body);
}
}

void IRPrinter::visit(const Free *op) {
Expand Down Expand Up @@ -1067,13 +1087,9 @@ void IRPrinter::visit(const Realize *op) {
stream << " if ";
print(op->condition);
}
stream << " {\n";

indent++;
print(op->body);
indent--;

stream << get_indent() << "}\n";
stream << " ";
print_braced_stmt(op->body);
}

void IRPrinter::visit(const Prefetch *op) {
Expand Down Expand Up @@ -1102,12 +1118,16 @@ void IRPrinter::visit(const Prefetch *op) {
indent--;
stream << get_indent() << "}\n";
}
print(op->body);
if (!is_summary) {
print(op->body);
}
}

void IRPrinter::visit(const Block *op) {
print(op->first);
print(op->rest);
if (!is_summary) {
print(op->first);
print(op->rest);
}
}

void IRPrinter::visit(const Fork *op) {
Expand All @@ -1121,14 +1141,23 @@ void IRPrinter::visit(const Fork *op) {
stmts.push_back(rest);

stream << get_indent() << "fork ";
for (const Stmt &s : stmts) {
stream << "{\n";
indent++;
print(s);
indent--;
stream << get_indent() << "} ";
if (is_summary) {
stream << "[" << stmts.size();
if (stmts.size() == 1) {
stream << " child]";
} else {
stream << " children]";
}
} else {
for (const Stmt &s : stmts) {
stream << "{\n";
indent++;
print(s);
indent--;
stream << get_indent() << "} ";
}
stream << "\n";
}
stream << "\n";
}

void IRPrinter::visit(const IfThenElse *op) {
Expand Down Expand Up @@ -1209,32 +1238,43 @@ void IRPrinter::visit(const VectorReduce *op) {
}

void IRPrinter::visit(const Atomic *op) {
stream << get_indent();

if (op->mutex_name.empty()) {
stream << get_indent() << "atomic ("
<< op->producer_name << ") {\n";
stream << "atomic (" << op->producer_name << ") ";
} else {
stream << get_indent() << "atomic ("
<< op->producer_name << ", "
<< op->mutex_name << ") {\n";
stream << "atomic (" << op->producer_name << ", " << op->mutex_name << ") ";
}
indent += 2;
print(op->body);
indent -= 2;
stream << get_indent() << "}\n";

print_braced_stmt(op->body);
}

void IRPrinter::visit(const HoistedStorage *op) {
if (op->name.empty()) {
stream << get_indent() << "hoisted_storage {\n";
stream << get_indent() << "hoisted_storage ";
} else {
stream << get_indent() << "hoisted_storage (";
stream << op->name;
stream << ") {\n";
stream << get_indent() << "hoisted_storage (" << op->name << ") ";
}
indent += 2;
print(op->body);
indent -= 2;
stream << get_indent() << "}\n";

print_braced_stmt(op->body);
}

std::string lldb_string(const Expr &ir) {
std::stringstream s{};
IRPrinter p(s);
p.print_no_parens(ir);
return s.str();
}

std::string lldb_string(const Internal::BaseExprNode *n) {
return lldb_string(Expr(n));
}

std::string lldb_string(const Stmt &ir) {
std::stringstream s{};
IRPrinter p(s);
p.print_summary(ir);
return s.str();
}

} // namespace Internal
Expand Down
17 changes: 17 additions & 0 deletions src/IRPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ class IRPrinter : public IRVisitor {
/** emit a statement on the output stream */
void print(const Stmt &);

/** emit a statement summary on the output stream */
void print_summary(const Stmt &);

/** emit a comma delimited list of exprs, without any leading or
* trailing punctuation. */
void print_list(const std::vector<Expr> &exprs);
Expand All @@ -157,6 +160,10 @@ class IRPrinter : public IRVisitor {
* surrounding set of parens. */
bool implicit_parens = false;

/** Print only a summary of a statement, with sub-statements replaced by
* ellipses (...). */
bool is_summary = false;

/** Either emits "(" or "", depending on the value of implicit_parens */
void open();

Expand All @@ -170,6 +177,9 @@ class IRPrinter : public IRVisitor {
/** A helper for printing a chain of lets with line breaks */
void print_lets(const Let *let);

/** A helper for printing a braced statement */
void print_braced_stmt(const Stmt &, int extra_indent = 2);

void visit(const IntImm *) override;
void visit(const UIntImm *) override;
void visit(const FloatImm *) override;
Expand Down Expand Up @@ -220,6 +230,13 @@ class IRPrinter : public IRVisitor {
void visit(const HoistedStorage *) override;
};

/** Debugging helpers for LLDB */
/// @{
std::string lldb_string(const Expr &);
std::string lldb_string(const Internal::BaseExprNode *);
std::string lldb_string(const Stmt &);
/// @}

} // namespace Internal
} // namespace Halide

Expand Down
103 changes: 103 additions & 0 deletions tools/lldbhalide.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Load this module into LLDB by running:
# command script import /path/to/Halide/tools/lldbhalide.py

import lldb


def normalize(raw):
return raw.lstrip('"').rstrip('"').replace(r'\n', ' ').replace(' ', ' ')


def addr(value):
if ptr := value.GetValueAsUnsigned(0):
return f"0x{ptr:x}"
if ptr := value.AddressOf().GetValueAsUnsigned(0):
return f"0x{ptr:x}"
raise ValueError(f'Could not determine address for: {value}')


def expr_summary(value, _):
if value is None or not value.IsValid():
return f"<invalid>"
try:
raw = value.target.EvaluateExpression(
f"Halide::Internal::lldb_string(*(Halide::Expr*){addr(value)})",
lldb.SBExpressionOptions()
).GetSummary()
return normalize(raw)
except Exception as e:
return f"<expr/error:{value},{e}>"


def baseexpr_summary(value, _):
if value is None or not value.IsValid():
return f"<invalid>"

try:
raw = value.target.EvaluateExpression(
f"Halide::Internal::lldb_string((const Halide::Internal::BaseExprNode*){addr(value)})",
lldb.SBExpressionOptions()
).GetSummary()
return normalize(raw)
except Exception as e:
return f"<baseexpr/error:{value},{e}>"


def stmt_summary(value, _):
if value is None or not value.IsValid():
return "<invalid>"

try:
raw = value.target.EvaluateExpression(
f"Halide::Internal::lldb_string(*(Halide::Internal::Stmt*){addr(value)})",
lldb.SBExpressionOptions()
).GetSummary()
return normalize(raw)
except Exception as e:
return f"<stmt/error:{value},{e}>"


class IRChildrenProvider:
def __init__(self, valobj, _):
self.inner = valobj.GetChildMemberWithName("ptr")
self.update()

def update(self):
pass

def num_children(self):
return self.inner.GetNumChildren()

def get_child_index(self, name):
return self.inner.GetIndexOfChildWithName(name)

def get_child_at_index(self, index):
return self.inner.GetChildAtIndex(index)


def __lldb_init_module(debugger, _):
base_exprs = ["Add", "And", "Broadcast", "Call", "Cast", "Div", "EQ", "GE", "GT", "LE", "LT", "Let", "Load", "Max",
"Min", "Mod", "Mul", "NE", "Not", "Or", "Ramp", "Reinterpret", "Select", "Shuffle", "Sub", "Variable",
"VectorReduce"]

for expr in base_exprs:
debugger.HandleCommand(
f"type summary add Halide::Internal::{expr} --python-function lldbhalide.baseexpr_summary"
)

debugger.HandleCommand(
"type summary add Halide::Expr --python-function lldbhalide.expr_summary"
)
debugger.HandleCommand(
'type synthetic add Halide::Expr -l lldbhalide.IRChildrenProvider'
)

debugger.HandleCommand(
"type summary add Halide::Internal::Stmt --python-function lldbhalide.stmt_summary"
)
debugger.HandleCommand(
'type synthetic add Halide::Internal::Stmt -l lldbhalide.IRChildrenProvider'
)

debugger.HandleCommand("type summary add halide_type_t -s '${var.code%S} bits=${var.bits%u} lanes=${var.lanes%u}'")
debugger.HandleCommand("type summary add Halide::Internal::RefCount -s ${var.count.Value%S}")
Loading