From 263b01e4c76684150c64ad7e44b862757e9d5d95 Mon Sep 17 00:00:00 2001 From: Alex Reinking Date: Tue, 5 Nov 2024 12:40:35 -0500 Subject: [PATCH 1/2] Add LLDB pretty-printing --- .lldbinit | 1 + src/IRPrinter.cpp | 136 ++++++++++++++++++++++++++++---------------- src/IRPrinter.h | 17 ++++++ tools/lldbhalide.py | 103 +++++++++++++++++++++++++++++++++ 4 files changed, 209 insertions(+), 48 deletions(-) create mode 100644 .lldbinit create mode 100644 tools/lldbhalide.py diff --git a/.lldbinit b/.lldbinit new file mode 100644 index 000000000000..a07959c1b025 --- /dev/null +++ b/.lldbinit @@ -0,0 +1 @@ +command script import ./tools/lldbhalide.py diff --git a/src/IRPrinter.cpp b/src/IRPrinter.cpp index a42431f232d0..ac203e74dc62 100644 --- a/src/IRPrinter.cpp +++ b/src/IRPrinter.cpp @@ -567,6 +567,11 @@ void IRPrinter::print(const Stmt &ir) { ir.accept(this); } +void IRPrinter::print_summary(const Stmt &ir) { + ScopedValue old(is_summary, true); + ir.accept(this); +} + void IRPrinter::print_list(const std::vector &exprs) { for (size_t i = 0; i < exprs.size(); i++) { print_no_parens(exprs[i]); @@ -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(); } @@ -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) { @@ -905,13 +914,9 @@ 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) { @@ -919,11 +924,8 @@ void IRPrinter::visit(const Acquire *op) { 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) { @@ -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()) { + if (is_summary) { + stream << get_indent() << "...\n"; + } else if (const Let *next = let->body.as()) { print_lets(next); } else { stream << get_indent(); @@ -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); @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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 diff --git a/src/IRPrinter.h b/src/IRPrinter.h index 48afef8603d3..94edac36b68c 100644 --- a/src/IRPrinter.h +++ b/src/IRPrinter.h @@ -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 &exprs); @@ -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(); @@ -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; @@ -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 diff --git a/tools/lldbhalide.py b/tools/lldbhalide.py new file mode 100644 index 000000000000..ed4ff373b5e7 --- /dev/null +++ b/tools/lldbhalide.py @@ -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"" + 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"" + + +def baseexpr_summary(value, _): + if value is None or not value.IsValid(): + return f"" + + 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"" + + +def stmt_summary(value, _): + if value is None or not value.IsValid(): + return "" + + 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"" + + +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}") From 0e66142748490d0892338601b49c0c2ea90a91b5 Mon Sep 17 00:00:00 2001 From: Alex Reinking Date: Tue, 5 Nov 2024 12:58:26 -0500 Subject: [PATCH 2/2] clang-format --- src/IRPrinter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IRPrinter.h b/src/IRPrinter.h index 94edac36b68c..b7b5084c1eff 100644 --- a/src/IRPrinter.h +++ b/src/IRPrinter.h @@ -178,7 +178,7 @@ class IRPrinter : public IRVisitor { void print_lets(const Let *let); /** A helper for printing a braced statement */ - void print_braced_stmt(const Stmt &, int extra_indent=2); + void print_braced_stmt(const Stmt &, int extra_indent = 2); void visit(const IntImm *) override; void visit(const UIntImm *) override;