This is an automated email from the ASF dual-hosted git repository.
tlopex pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new 200f4fd5cd [REFACTOR][NODE] Migrate ReprPrinter to tvm-ffi
__ffi_repr__ mechanism (#19461)
200f4fd5cd is described below
commit 200f4fd5cdaa6f63bc65145e17d7f4a86370b905
Author: Tianqi Chen <[email protected]>
AuthorDate: Mon Apr 27 16:39:55 2026 -0400
[REFACTOR][NODE] Migrate ReprPrinter to tvm-ffi __ffi_repr__ mechanism
(#19461)
This PR phases out the legacy `ReprPrinter` machinery
(`include/tvm/node/repr_printer.h`, `src/node/repr_printer.cc`,
`src/node/container_printing.cc`) by migrating ~169 dispatch sites to
the tvm-ffi `__ffi_repr__` mechanism.
**Summary of changes:**
- All ~169 `TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable).set_dispatch<T>`
sites have been migrated: most non-user-facing types now use the
dataclass auto-default; user-facing types (`script/printer/`, `Trace`,
DPL pattern syntax, Span/SequentialSpan/SourceName, `data_layout`
Layout/BijectiveLayout, `target_kind`/`virtual_device`) retain custom
hooks via `__ffi_repr__`.
- Adds `include/tvm/node/repr.h` with `operator<<(ostream,
ObjectRef/Any/Variant)` delegating to `ffi::ReprPrint`. Adds
`src/node/repr.cc` with `Dump()` debug helpers and the `node.AsRepr` FFI
for Python compatibility.
- Note: null `ObjectRef` now reprs as `None` (Python-compatible) rather
than `(nullptr)`; one test was updated for this
(`test_tir_transform_vectorize.py::test_illegal_extent`). The
auto-default uses the full type-key (e.g. `arith.ModularSet(...)`) per
design direction.
**Test results:**
- all-platform-minimal: 75p/77s
- tirx-base: 273p/2s
- arith: 982p/1s/8xf (preexisting xfails)
- ir+target: 236p/7s
- tvmscript: 771p/1xf
- tirx-transform+analysis: 374p/9xf/1xp
- s_tir (excl. 2 broken test files): 1279p/36s/2xf + 15 preexisting CUDA
sketch failures
- relax: covered (no repr-pinned tests)
- Pre-commit clean
---
include/tvm/ir/expr.h | 2 +-
include/tvm/node/functor.h | 28 ++-
include/tvm/node/{repr_printer.h => repr.h} | 56 ++----
include/tvm/node/repr_printer.h | 116 +------------
include/tvm/node/script_printer.h | 2 +-
include/tvm/relax/exec_builder.h | 2 +-
include/tvm/s_tir/meta_schedule/mutator.h | 2 +
src/arith/canonical_simplify.cc | 35 +---
src/arith/const_int_bound.cc | 10 +-
src/arith/int_constraints.cc | 22 +--
src/arith/int_set.cc | 7 +-
src/arith/iter_affine_map.cc | 19 +--
src/arith/modular_set.cc | 8 +-
src/arith/presburger_set.cc | 10 +-
src/arith/rewrite_simplify.cc | 11 +-
src/ir/env_func.cc | 6 +-
src/ir/expr.cc | 6 +-
src/ir/instrument.cc | 8 +-
src/ir/op.cc | 6 +-
src/ir/source_map.cc | 60 ++++---
src/ir/structural_equal.cc | 2 +-
src/ir/structural_hash.cc | 30 +---
src/ir/transform.cc | 57 +------
src/node/container_printing.cc | 52 +-----
src/node/repr.cc | 97 +++++++++++
src/node/repr_printer.cc | 189 +--------------------
src/node/script_printer.cc | 9 +-
src/relax/ir/dataflow_pattern.cc | 29 +++-
src/relax/ir/emit_te.cc | 7 +-
src/relax/ir/expr.cc | 2 -
src/relax/ir/transform.cc | 18 +-
src/s_tir/data_layout.cc | 26 +--
src/s_tir/meta_schedule/arg_info.cc | 24 ++-
src/s_tir/meta_schedule/cost_model/cost_model.cc | 15 +-
.../feature_extractor/feature_extractor.cc | 10 +-
.../measure_callback/measure_callback.cc | 10 +-
src/s_tir/meta_schedule/mutator/mutator.cc | 9 +-
src/s_tir/meta_schedule/postproc/postproc.cc | 9 +-
.../meta_schedule/schedule_rule/schedule_rule.cc | 9 +-
src/s_tir/schedule/instruction.cc | 17 +-
src/s_tir/schedule/trace.cc | 6 -
src/script/printer/ir/utils.h | 2 +-
src/script/printer/relax/utils.h | 2 +-
src/script/printer/tirx/utils.h | 2 +-
src/script/printer/utils.h | 26 ++-
src/target/target.cc | 5 +-
src/target/target_kind.cc | 11 +-
src/target/virtual_device.cc | 63 +++----
src/te/operation/compute_op.cc | 8 +-
src/te/operation/extern_op.cc | 7 +-
src/te/operation/placeholder_op.cc | 7 +-
src/te/operation/scan_op.cc | 6 +-
src/te/tensor.cc | 6 +-
src/tirx/ir/expr.cc | 11 +-
src/tirx/ir/transform.cc | 9 +-
.../tirx-transform/test_tir_transform_vectorize.py | 2 +-
56 files changed, 362 insertions(+), 848 deletions(-)
diff --git a/include/tvm/ir/expr.h b/include/tvm/ir/expr.h
index 942595b53d..968bef0727 100644
--- a/include/tvm/ir/expr.h
+++ b/include/tvm/ir/expr.h
@@ -29,7 +29,7 @@
#include <tvm/ir/source_map.h>
#include <tvm/ir/type.h>
#include <tvm/node/cast.h>
-#include <tvm/node/repr_printer.h>
+#include <tvm/node/repr.h>
#include <tvm/node/script_printer.h>
#include <tvm/runtime/object.h>
diff --git a/include/tvm/node/functor.h b/include/tvm/node/functor.h
index b9a4681532..3f0babdbd0 100644
--- a/include/tvm/node/functor.h
+++ b/include/tvm/node/functor.h
@@ -160,38 +160,32 @@ class NodeFunctor<R(const ObjectRef& n, Args...)> {
* \brief Useful macro to set NodeFunctor dispatch in a global static field.
*
* \code
- * // Use NodeFunctor to implement ReprPrinter similar to Visitor Pattern.
+ * // Use NodeFunctor to implement TVMScriptPrinter similar to Visitor
Pattern.
* // vtable allows easy patch of new Node types, without changing
- * // interface of ReprPrinter.
+ * // the interface of TVMScriptPrinter.
*
- * class ReprPrinter {
+ * class TVMScriptPrinter {
* public:
- * std::ostream& stream;
* // the dispatch function.
- * void print(Expr e) {
- * const static FType& f = *vtable();
- * f(e, this);
+ * static std::string Script(const ObjectRef& node, const PrinterConfig&
cfg) {
+ * return vtable()(node, cfg);
* }
- *
- * using FType = NodeFunctor<void (const ObjectRef&, ReprPrinter* )>;
+ * using FType = NodeFunctor<std::string(const ObjectRef&, const
PrinterConfig&)>;
* // function to return global function table
* static FType& vtable();
* };
*
* // in cpp/cc file
- * ReprPrinter::FType& ReprPrinter::vtable() { // NOLINT(*)
+ * TVMScriptPrinter::FType& TVMScriptPrinter::vtable() {
* static FType inst; return inst;
* }
*
- * TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- * .set_dispatch<Add>([](const ObjectRef& ref, ReprPrinter* p) {
- * auto* n = static_cast<const Add*>(ref.get());
- * p->print(n->a);
- * p->stream << '+'
- * p->print(n->b);
+ * TVM_STATIC_IR_FUNCTOR(TVMScriptPrinter, vtable)
+ * .set_dispatch<AddNode>([](const ObjectRef& ref, const PrinterConfig& cfg) {
+ * auto* n = static_cast<const AddNode*>(ref.get());
+ * return Script(n->a, cfg) + " + " + Script(n->b, cfg);
* });
*
- *
* \endcode
*
* \param ClsName The name of the class
diff --git a/include/tvm/node/repr_printer.h b/include/tvm/node/repr.h
similarity index 69%
copy from include/tvm/node/repr_printer.h
copy to include/tvm/node/repr.h
index 1c1f1ec380..48276df1ec 100644
--- a/include/tvm/node/repr_printer.h
+++ b/include/tvm/node/repr.h
@@ -17,41 +17,23 @@
* under the License.
*/
/*!
- * \file tvm/node/repr_printer.h
- * \brief Printer class to print repr string of each AST/IR nodes.
+ * \file tvm/node/repr.h
+ * \brief ostream operator<< for ObjectRef, Any, and Variant, delegating to
+ * ffi::ReprPrint. Also re-exports the Dump() debug helpers.
+ *
+ * Include this header wherever you need `os << some_objectref` and you are
+ * no longer pulling in the legacy repr_printer.h.
*/
-#ifndef TVM_NODE_REPR_PRINTER_H_
-#define TVM_NODE_REPR_PRINTER_H_
+#ifndef TVM_NODE_REPR_H_
+#define TVM_NODE_REPR_H_
+#include <tvm/ffi/extra/dataclass.h>
#include <tvm/ffi/reflection/access_path.h>
-#include <tvm/node/functor.h>
-#include <tvm/node/script_printer.h>
+#include <tvm/runtime/object.h>
#include <iostream>
-#include <string>
namespace tvm {
-/*! \brief A printer class to print the AST/IR nodes. */
-class ReprPrinter {
- public:
- /*! \brief The output stream */
- std::ostream& stream;
- /*! \brief The indentation level. */
- int indent{0};
-
- explicit ReprPrinter(std::ostream& stream) // NOLINT(*)
- : stream(stream) {}
-
- /*! \brief The node to be printed. */
- TVM_DLL void Print(const ObjectRef& node);
- /*! \brief The node to be printed. */
- TVM_DLL void Print(const ffi::Any& node);
- /*! \brief Print indent to the stream */
- TVM_DLL void PrintIndent();
- // Allow registration to be printer.
- using FType = NodeFunctor<void(const ObjectRef&, ReprPrinter*)>;
- TVM_DLL static FType& vtable();
-};
/*!
* \brief Dump the node to stderr, used for debug purposes.
@@ -69,23 +51,21 @@ TVM_DLL void Dump(const runtime::Object* node);
namespace tvm {
namespace ffi {
-// default print function for all objects
-// provide in the runtime namespace as this is where objectref originally
comes from.
+
+// ostream << ObjectRef — delegates to ffi::ReprPrint
inline std::ostream& operator<<(std::ostream& os, const ObjectRef& n) { //
NOLINT(*)
- ReprPrinter(os).Print(n);
- return os;
+ return os << ffi::ReprPrint(Any(n));
}
-// default print function for any
+// ostream << Any — delegates to ffi::ReprPrint
inline std::ostream& operator<<(std::ostream& os, const Any& n) { // NOLINT(*)
- ReprPrinter(os).Print(n);
- return os;
+ return os << ffi::ReprPrint(n);
}
+// ostream << Variant<...> — delegates to ffi::ReprPrint
template <typename... V>
inline std::ostream& operator<<(std::ostream& os, const ffi::Variant<V...>& n)
{ // NOLINT(*)
- ReprPrinter(os).Print(Any(n));
- return os;
+ return os << ffi::ReprPrint(Any(n));
}
namespace reflection {
@@ -135,4 +115,4 @@ inline std::ostream& operator<<(std::ostream& os, const
AccessPath& path) {
} // namespace reflection
} // namespace ffi
} // namespace tvm
-#endif // TVM_NODE_REPR_PRINTER_H_
+#endif // TVM_NODE_REPR_H_
diff --git a/include/tvm/node/repr_printer.h b/include/tvm/node/repr_printer.h
index 1c1f1ec380..71d19f5245 100644
--- a/include/tvm/node/repr_printer.h
+++ b/include/tvm/node/repr_printer.h
@@ -18,121 +18,13 @@
*/
/*!
* \file tvm/node/repr_printer.h
- * \brief Printer class to print repr string of each AST/IR nodes.
+ * \brief DEPRECATED: The legacy ReprPrinter has been replaced by
+ * ffi::ReprPrint. This header is kept as an empty shim;
+ * include <tvm/node/repr.h> instead.
*/
#ifndef TVM_NODE_REPR_PRINTER_H_
#define TVM_NODE_REPR_PRINTER_H_
-#include <tvm/ffi/reflection/access_path.h>
-#include <tvm/node/functor.h>
-#include <tvm/node/script_printer.h>
+#include <tvm/node/repr.h>
-#include <iostream>
-#include <string>
-
-namespace tvm {
-/*! \brief A printer class to print the AST/IR nodes. */
-class ReprPrinter {
- public:
- /*! \brief The output stream */
- std::ostream& stream;
- /*! \brief The indentation level. */
- int indent{0};
-
- explicit ReprPrinter(std::ostream& stream) // NOLINT(*)
- : stream(stream) {}
-
- /*! \brief The node to be printed. */
- TVM_DLL void Print(const ObjectRef& node);
- /*! \brief The node to be printed. */
- TVM_DLL void Print(const ffi::Any& node);
- /*! \brief Print indent to the stream */
- TVM_DLL void PrintIndent();
- // Allow registration to be printer.
- using FType = NodeFunctor<void(const ObjectRef&, ReprPrinter*)>;
- TVM_DLL static FType& vtable();
-};
-
-/*!
- * \brief Dump the node to stderr, used for debug purposes.
- * \param node The input node
- */
-TVM_DLL void Dump(const runtime::ObjectRef& node);
-
-/*!
- * \brief Dump the node to stderr, used for debug purposes.
- * \param node The input node
- */
-TVM_DLL void Dump(const runtime::Object* node);
-
-} // namespace tvm
-
-namespace tvm {
-namespace ffi {
-// default print function for all objects
-// provide in the runtime namespace as this is where objectref originally
comes from.
-inline std::ostream& operator<<(std::ostream& os, const ObjectRef& n) { //
NOLINT(*)
- ReprPrinter(os).Print(n);
- return os;
-}
-
-// default print function for any
-inline std::ostream& operator<<(std::ostream& os, const Any& n) { // NOLINT(*)
- ReprPrinter(os).Print(n);
- return os;
-}
-
-template <typename... V>
-inline std::ostream& operator<<(std::ostream& os, const ffi::Variant<V...>& n)
{ // NOLINT(*)
- ReprPrinter(os).Print(Any(n));
- return os;
-}
-
-namespace reflection {
-
-inline std::ostream& operator<<(std::ostream& os, const AccessStep& step) {
- namespace refl = ffi::reflection;
- switch (step->kind) {
- case refl::AccessKind::kAttr: {
- os << '.' << step->key.cast<ffi::String>();
- return os;
- }
- case refl::AccessKind::kArrayItem: {
- os << "[" << step->key.cast<int64_t>() << "]";
- return os;
- }
- case refl::AccessKind::kMapItem: {
- os << "[" << step->key << "]";
- return os;
- }
- case refl::AccessKind::kAttrMissing: {
- os << ".<missing attr " << step->key.cast<ffi::String>() << "`>";
- return os;
- }
- case refl::AccessKind::kArrayItemMissing: {
- os << "[<missing item at " << step->key.cast<int64_t>() << ">]";
- return os;
- }
- case refl::AccessKind::kMapItemMissing: {
- os << "[<missing item at " << step->key << ">]";
- return os;
- }
- default: {
- TVM_FFI_THROW(InternalError) << "Unknown access step kind: " <<
static_cast<int>(step->kind);
- }
- }
- return os;
-}
-
-inline std::ostream& operator<<(std::ostream& os, const AccessPath& path) {
- ffi::Array<AccessStep> steps = path->ToSteps();
- os << "<root>";
- for (const auto& step : steps) {
- os << step;
- }
- return os;
-}
-} // namespace reflection
-} // namespace ffi
-} // namespace tvm
#endif // TVM_NODE_REPR_PRINTER_H_
diff --git a/include/tvm/node/script_printer.h
b/include/tvm/node/script_printer.h
index c72ee10d2c..5eeab20107 100644
--- a/include/tvm/node/script_printer.h
+++ b/include/tvm/node/script_printer.h
@@ -161,7 +161,7 @@ class TVM_DLL PrinterConfig : public ObjectRef {
PrinterConfigNode);
};
-/*! \brief Legacy behavior of ReprPrinter. */
+/*! \brief TVMScript-based printer for IR nodes. */
class TVMScriptPrinter {
public:
/* Convert the object to TVMScript format */
diff --git a/include/tvm/relax/exec_builder.h b/include/tvm/relax/exec_builder.h
index 66bae5411a..f85b5af460 100644
--- a/include/tvm/relax/exec_builder.h
+++ b/include/tvm/relax/exec_builder.h
@@ -28,7 +28,7 @@
#include <tvm/ffi/function.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ir/expr.h>
-#include <tvm/node/repr_printer.h>
+#include <tvm/node/repr.h>
#include <tvm/runtime/object.h>
#include <tvm/runtime/vm/bytecode.h>
#include <tvm/runtime/vm/executable.h>
diff --git a/include/tvm/s_tir/meta_schedule/mutator.h
b/include/tvm/s_tir/meta_schedule/mutator.h
index 76f41f998f..42708dec57 100644
--- a/include/tvm/s_tir/meta_schedule/mutator.h
+++ b/include/tvm/s_tir/meta_schedule/mutator.h
@@ -162,6 +162,8 @@ class PyMutatorNode : public MutatorNode {
FAsString f_as_string;
static void RegisterReflection() {
+ namespace refl = tvm::ffi::reflection;
+ refl::ObjectDef<PyMutatorNode>();
// `f_initialize_with_tune_context` is not registered
// `f_apply` is not registered
// `f_clone` is not registered
diff --git a/src/arith/canonical_simplify.cc b/src/arith/canonical_simplify.cc
index 68696b9de1..3d1d55269d 100644
--- a/src/arith/canonical_simplify.cc
+++ b/src/arith/canonical_simplify.cc
@@ -535,40 +535,7 @@ void SumExprNode::AddToSelf(const SumExpr& other, int64_t
scale) {
this->AddToSelf(other->base * scale);
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<SplitExprNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const SplitExprNode*>(node.get());
- auto factor_str = [](int64_t f) {
- return f == SplitExprNode::kPosInf ? std::string("+inf") :
std::to_string(f);
- };
- p->stream << "split(";
- p->Print(op->index);
- p->stream << ", lower=" << factor_str(op->lower_factor)
- << ", upper=" << factor_str(op->upper_factor) << ", scale=" <<
op->scale
- << ", div_mode=";
- switch (op->div_mode) {
- // No "default", so that the compiler will emit a warning if more div
modes are
- // added that are not covered by the switch.
- case kTruncDiv:
- p->stream << "truncdiv";
- break;
- case kFloorDiv:
- p->stream << "floordiv";
- break;
- }
- p->stream << ')';
- });
-
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<SumExprNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const SumExprNode*>(node.get());
- p->stream << "sum(base=" << op->base;
- for (const SplitExpr& s : op->args) {
- p->stream << ", ";
- p->Print(s);
- }
- p->stream << ')';
- });
+// Pattern A (RM): auto-default repr from reflection for SplitExprNode and
SumExprNode.
// Sub-class RewriteSimplifier::Impl to take benefit of
// rewriter for condition simplification etc.
diff --git a/src/arith/const_int_bound.cc b/src/arith/const_int_bound.cc
index 8e306ba966..4b0b57d84f 100644
--- a/src/arith/const_int_bound.cc
+++ b/src/arith/const_int_bound.cc
@@ -67,15 +67,7 @@ inline void PrintBoundValue(std::ostream& os, int64_t val) {
}
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ConstIntBoundNode>([](const ObjectRef& node, ReprPrinter* p)
{
- auto* op = static_cast<const ConstIntBoundNode*>(node.get());
- p->stream << "ConstIntBound[";
- PrintBoundValue(p->stream, op->min_value);
- p->stream << ',';
- PrintBoundValue(p->stream, op->max_value);
- p->stream << ']';
- });
+// Pattern A (RM): auto-default repr from reflection.
// internal entry for const int bound
struct ConstIntBoundAnalyzer::Entry {
diff --git a/src/arith/int_constraints.cc b/src/arith/int_constraints.cc
index 6d8e539357..be6dcdeb35 100644
--- a/src/arith/int_constraints.cc
+++ b/src/arith/int_constraints.cc
@@ -219,12 +219,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<IntGroupBoundsNode>([](const ObjectRef& node, ReprPrinter*
p) {
- auto* op = static_cast<const IntGroupBoundsNode*>(node.get());
- p->stream << "IntGroupBounds(coef=" << op->coef << ", lower=" <<
op->lower
- << ", equal=" << op->equal << ", upper=" << op->upper << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
IntConstraints::IntConstraints(ffi::Array<Var> variables, ffi::Map<Var, Range>
ranges,
ffi::Array<PrimExpr> relations) {
@@ -255,12 +250,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<IntConstraintsNode>([](const ObjectRef& node, ReprPrinter*
p) {
- auto* op = static_cast<const IntConstraintsNode*>(node.get());
- p->stream << "IntConstraints(" << op->variables << ", " << op->ranges <<
", " << op->relations
- << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
IntConstraintsTransform::IntConstraintsTransform(IntConstraints src,
IntConstraints dst,
ffi::Map<Var, PrimExpr>
src_to_dst,
@@ -302,13 +292,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<IntConstraintsTransformNode>([](const ObjectRef& node,
ReprPrinter* p) {
- auto* op = static_cast<const IntConstraintsTransformNode*>(node.get());
- p->stream << "IntConstraintsTransform("
- << "\n\t" << op->src << "\n\t" << op->dst << "\n\t" <<
op->src_to_dst << "\n\t"
- << op->dst_to_src << "\n)";
- });
+// Pattern A (RM): auto-default repr from reflection.
} // namespace arith
} // namespace tvm
diff --git a/src/arith/int_set.cc b/src/arith/int_set.cc
index c8e1d73771..f48a1e1e26 100644
--- a/src/arith/int_set.cc
+++ b/src/arith/int_set.cc
@@ -1227,12 +1227,7 @@ ffi::Array<IntSet> EstimateRegionUpperBound(const
ffi::Array<Range>& region,
return result;
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<IntervalSetNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const IntervalSetNode*>(node.get());
- p->stream << "IntervalSet"
- << "[" << op->min_value << ", " << op->max_value << ']';
- });
+// Pattern A (RM): auto-default repr from reflection.
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
diff --git a/src/arith/iter_affine_map.cc b/src/arith/iter_affine_map.cc
index a4d5097167..d42114e579 100644
--- a/src/arith/iter_affine_map.cc
+++ b/src/arith/iter_affine_map.cc
@@ -61,11 +61,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
[](PrimExpr source, PrimExpr extent) { return
IterMark(source, extent); });
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<IterMarkNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const IterMarkNode*>(node.get());
- p->stream << "IterMark(" << op->source << ", extent=" << op->extent <<
")";
- });
+// Pattern A (RM): auto-default repr from reflection.
IterSplitExpr::IterSplitExpr(IterMark source) {
auto n = ffi::make_object<IterSplitExprNode>();
@@ -108,12 +104,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<IterSplitExprNode>([](const ObjectRef& node, ReprPrinter* p)
{
- auto* op = static_cast<const IterSplitExprNode*>(node.get());
- p->stream << "IterSplit(" << op->source << ", lower_factor=" <<
op->lower_factor
- << ", extent=" << op->extent << ", scale=" << op->scale << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
IterSumExpr::IterSumExpr(ffi::Array<IterSplitExpr> args, PrimExpr base) {
auto n = ffi::make_object<IterSumExprNode>();
@@ -130,11 +121,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<IterSumExprNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const IterSumExprNode*>(node.get());
- p->stream << "IterSum(" << op->args << ", " << op->base << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
/*!
* \brief Collector that collects the outgoing split reference of each
IterMark.
diff --git a/src/arith/modular_set.cc b/src/arith/modular_set.cc
index 9aaa81b1ba..9bc45bb77f 100644
--- a/src/arith/modular_set.cc
+++ b/src/arith/modular_set.cc
@@ -49,12 +49,8 @@ ModularSet::ModularSet(int64_t coeff, int64_t base) {
data_ = std::move(node);
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ModularSetNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const ModularSetNode*>(node.get());
- p->stream << "ModularSet("
- << "coeff=" << op->coeff << ", base=" << op->base << ')';
- });
+// Pattern A (RM): auto-default repr from reflection produces
+// "arith.ModularSet(coeff=..., base=...)"
ModularSet MakeModularSet(int64_t coeff, int64_t base) { return
ModularSet(coeff, base); }
diff --git a/src/arith/presburger_set.cc b/src/arith/presburger_set.cc
index 3c7bd25d86..a62c34c525 100644
--- a/src/arith/presburger_set.cc
+++ b/src/arith/presburger_set.cc
@@ -260,15 +260,7 @@ IntSet EvalSet(const PrimExpr& e, const PresburgerSet&
set) {
return result;
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PresburgerSetNode>([](const ObjectRef& node, ReprPrinter* p)
{
- auto set = node.as<PresburgerSetNode>();
- TVM_FFI_ICHECK(ret) << "Unknown type:" << node->GetTypeKey();
- p->stream << "{";
- p->stream << set->GetVars() << ": ";
- p->stream << node.as<PresburgerSetNode>()->GenerateConstraint();
- p->stream << "}";
- });
+// Pattern A (RM): auto-default repr from reflection.
#else // defined(TVM_MLIR_VERSION) && TVM_MLIR_VERSION >= 150
diff --git a/src/arith/rewrite_simplify.cc b/src/arith/rewrite_simplify.cc
index cb96bb07f6..8649bf96be 100644
--- a/src/arith/rewrite_simplify.cc
+++ b/src/arith/rewrite_simplify.cc
@@ -2428,16 +2428,7 @@ RewriteSimplifier::RewriteSimplifier(Analyzer* parent) :
impl_(new Impl(parent))
RewriteSimplifier::~RewriteSimplifier() { delete impl_; }
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<RewriteSimplifierStatsNode>([](const ObjectRef& node,
ReprPrinter* p) {
- auto* ptr = node.as<RewriteSimplifierStatsNode>();
- p->stream << "RewriteSimplifierStats(nodes_visited = " <<
ptr->nodes_visited
- << ", constraints_entered = " << ptr->constraints_entered
- << ", rewrites_attempted = " << ptr->rewrites_attempted
- << ", rewrites_performed = " << ptr->rewrites_performed
- << ", max_recursive_depth = " << ptr->max_recursive_depth
- << ", num_recursive_rewrites = " <<
ptr->num_recursive_rewrites << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
} // namespace arith
} // namespace tvm
diff --git a/src/ir/env_func.cc b/src/ir/env_func.cc
index e90ea07a0b..5c64047c96 100644
--- a/src/ir/env_func.cc
+++ b/src/ir/env_func.cc
@@ -33,11 +33,7 @@ using ffi::Any;
using ffi::Function;
using ffi::PackedArgs;
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<EnvFuncNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const EnvFuncNode*>(node.get());
- p->stream << "EnvFunc(" << op->name << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
ObjectPtr<Object> CreateEnvNode(const std::string& name) {
auto f = tvm::ffi::Function::GetGlobal(name);
diff --git a/src/ir/expr.cc b/src/ir/expr.cc
index f9d6e0fc60..b5cc09e11d 100644
--- a/src/ir/expr.cc
+++ b/src/ir/expr.cc
@@ -225,10 +225,8 @@ TVM_FFI_STATIC_INIT_BLOCK() {
ss << ref;
return ss.str();
});
- refl::TypeAttrDef<GlobalVarNode>().def(
- refl::type_attr::kRepr, [](GlobalVar gvar, ffi::Function) -> ffi::String
{
- return "I.GlobalVar(\"" + std::string(gvar->name_hint) + "\")";
- });
+ // Note: kRepr for GlobalVarNode is registered in script/printer/ir/ir.cc
+ // via TVM_SCRIPT_REPR(GlobalVarNode, ReprPrintIR).
}
} // namespace tvm
diff --git a/src/ir/instrument.cc b/src/ir/instrument.cc
index 8d1dd2ecf5..ced20ba1b1 100644
--- a/src/ir/instrument.cc
+++ b/src/ir/instrument.cc
@@ -25,7 +25,7 @@
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ir/instrument.h>
#include <tvm/ir/transform.h>
-#include <tvm/node/repr_printer.h>
+#include <tvm/node/repr.h>
#include <chrono>
#include <stack>
@@ -190,11 +190,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<BasePassInstrumentNode>([](const ObjectRef& ref,
ReprPrinter* p) {
- auto* node = static_cast<const BasePassInstrumentNode*>(ref.get());
- p->stream << node->name;
- });
+// Pattern A (RM): auto-default repr from reflection.
/*! \brief PassProfile stores profiling information for a given pass and its
sub-passes. */
struct PassProfile {
diff --git a/src/ir/op.cc b/src/ir/op.cc
index 3a260e886a..fb5751b63f 100644
--- a/src/ir/op.cc
+++ b/src/ir/op.cc
@@ -160,10 +160,6 @@ TVM_FFI_STATIC_INIT_BLOCK() {
.def("__data_from_json__", [](const ffi::String& name) -> Op { return
Op::Get(name); });
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<OpNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = static_cast<const OpNode*>(ref.get());
- p->stream << "Op(" << node->name << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
} // namespace tvm
diff --git a/src/ir/source_map.cc b/src/ir/source_map.cc
index 7b94890623..89842cfc05 100644
--- a/src/ir/source_map.cc
+++ b/src/ir/source_map.cc
@@ -20,6 +20,7 @@
* \file source_map.cc
* \brief The implementation of the source map data structure.
*/
+#include <tvm/ffi/extra/dataclass.h>
#include <tvm/ffi/function.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ir/source_map.h>
@@ -73,11 +74,15 @@ TVM_FFI_STATIC_INIT_BLOCK() {
refl::GlobalDef().def("ir.SourceName", SourceName::Get);
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<SourceNameNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = static_cast<const SourceNameNode*>(ref.get());
- p->stream << "SourceName(" << node->name << ", " << node << ")";
- });
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::TypeAttrDef<SourceNameNode>().def(
+ refl::type_attr::kRepr, [](SourceName sn, ffi::Function) -> ffi::String {
+ std::ostringstream os;
+ os << "SourceName(" << sn->name << ", " << static_cast<const
void*>(sn.get()) << ")";
+ return os.str();
+ });
+}
Span::Span(SourceName source_name, int line, int end_line, int column, int
end_column) {
auto n = ffi::make_object<SpanNode>();
@@ -150,25 +155,32 @@ TVM_FFI_STATIC_INIT_BLOCK() {
.def("ir.SequentialSpan", [](tvm::ffi::Array<Span> spans) { return
SequentialSpan(spans); });
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<SpanNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = static_cast<const SpanNode*>(ref.get());
- p->stream << "Span(" << node->source_name << ", " << node->line << ", "
<< node->end_line
- << ", " << node->column << ", " << node->end_column << ")";
- });
-
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<SequentialSpanNode>([](const ObjectRef& ref, ReprPrinter* p)
{
- auto* node = static_cast<const SequentialSpanNode*>(ref.get());
-
- p->stream << "SequentailSpan([ ";
- int index = 0;
- const int last = node->spans.size() - 1;
- while (index < last) {
- p->stream << node->spans[index++] << ", ";
- }
- p->stream << node->spans[last] << " ])";
- });
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::TypeAttrDef<SpanNode>().def(
+ refl::type_attr::kRepr, [](Span span, ffi::Function fn_repr) ->
ffi::String {
+ std::ostringstream os;
+ os << "Span(" <<
fn_repr(ffi::AnyView(span->source_name)).cast<ffi::String>() << ", "
+ << span->line << ", " << span->end_line << ", " << span->column <<
", "
+ << span->end_column << ")";
+ return os.str();
+ });
+ refl::TypeAttrDef<SequentialSpanNode>().def(
+ refl::type_attr::kRepr, [](SequentialSpan seq, ffi::Function fn_repr) ->
ffi::String {
+ // Fix typo: was "SequentailSpan", now "SequentialSpan"
+ std::ostringstream os;
+ os << "SequentialSpan([ ";
+ const int last = static_cast<int>(seq->spans.size()) - 1;
+ for (int i = 0; i < last; ++i) {
+ os << fn_repr(ffi::AnyView(seq->spans[i])).cast<ffi::String>() << ",
";
+ }
+ if (last >= 0) {
+ os << fn_repr(ffi::AnyView(seq->spans[last])).cast<ffi::String>();
+ }
+ os << " ])";
+ return os.str();
+ });
+}
/*! \brief Construct a source from a string. */
Source::Source(SourceName src_name, std::string source) {
diff --git a/src/ir/structural_equal.cc b/src/ir/structural_equal.cc
index 1d7cbd23d0..b8f80f4d57 100644
--- a/src/ir/structural_equal.cc
+++ b/src/ir/structural_equal.cc
@@ -25,7 +25,7 @@
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ir/module.h>
#include <tvm/node/functor.h>
-#include <tvm/node/repr_printer.h>
+#include <tvm/node/repr.h>
#include <tvm/node/script_printer.h>
#include <optional>
diff --git a/src/ir/structural_hash.cc b/src/ir/structural_hash.cc
index ad74742e51..b875f86625 100644
--- a/src/ir/structural_hash.cc
+++ b/src/ir/structural_hash.cc
@@ -97,11 +97,7 @@ struct ReportNodeTrait {
TVM_FFI_STATIC_INIT_BLOCK() { ReportNodeTrait::RegisterReflection(); }
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<runtime::profiling::ReportNode>([](const ObjectRef& node,
ReprPrinter* p) {
- auto* op = static_cast<const
runtime::profiling::ReportNode*>(node.get());
- p->stream << op->AsTable();
- });
+// Pattern A (RM): auto-default repr from reflection for ReportNode.
struct CountNodeTrait {
static void RegisterReflection() {
@@ -113,11 +109,7 @@ struct CountNodeTrait {
TVM_FFI_STATIC_INIT_BLOCK() { CountNodeTrait::RegisterReflection(); }
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<runtime::profiling::CountNode>([](const ObjectRef& node,
ReprPrinter* p) {
- auto* op = static_cast<const runtime::profiling::CountNode*>(node.get());
- p->stream << op->GetTypeKey() << "(" << op->value << ")";
- });
+// Pattern A (RM): auto-default repr from reflection for CountNode.
struct DurationNodeTrait {
static void RegisterReflection() {
@@ -129,11 +121,7 @@ struct DurationNodeTrait {
TVM_FFI_STATIC_INIT_BLOCK() { DurationNodeTrait::RegisterReflection(); }
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<runtime::profiling::DurationNode>([](const ObjectRef& node,
ReprPrinter* p) {
- auto* op = static_cast<const
runtime::profiling::DurationNode*>(node.get());
- p->stream << op->GetTypeKey() << "(" << op->microseconds << ")";
- });
+// Pattern A (RM): auto-default repr from reflection for DurationNode.
struct PercentNodeTrait {
static void RegisterReflection() {
@@ -145,11 +133,7 @@ struct PercentNodeTrait {
TVM_FFI_STATIC_INIT_BLOCK() { PercentNodeTrait::RegisterReflection(); }
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<runtime::profiling::PercentNode>([](const ObjectRef& node,
ReprPrinter* p) {
- auto* op = static_cast<const
runtime::profiling::PercentNode*>(node.get());
- p->stream << op->GetTypeKey() << "(" << op->percent << ")";
- });
+// Pattern A (RM): auto-default repr from reflection for PercentNode.
struct RatioNodeTrait {
static void RegisterReflection() {
@@ -161,10 +145,6 @@ struct RatioNodeTrait {
TVM_FFI_STATIC_INIT_BLOCK() { RatioNodeTrait::RegisterReflection(); }
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<runtime::profiling::RatioNode>([](const ObjectRef& node,
ReprPrinter* p) {
- auto* op = static_cast<const runtime::profiling::RatioNode*>(node.get());
- p->stream << op->GetTypeKey() << "(" << op->ratio << ")";
- });
+// Pattern A (RM): auto-default repr from reflection for RatioNode.
} // namespace tvm
diff --git a/src/ir/transform.cc b/src/ir/transform.cc
index 9d2dec6b1a..8c56f737d4 100644
--- a/src/ir/transform.cc
+++ b/src/ir/transform.cc
@@ -26,7 +26,7 @@
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ffi/rvalue_ref.h>
#include <tvm/ir/transform.h>
-#include <tvm/node/repr_printer.h>
+#include <tvm/node/repr.h>
#include <tvm/relax/expr.h>
#include <tvm/runtime/device_api.h>
@@ -35,7 +35,6 @@
namespace tvm {
namespace transform {
-using tvm::ReprPrinter;
using tvm::ffi::Any;
TVM_REGISTER_PASS_CONFIG_OPTION("testing.immutable_module", Bool);
@@ -505,23 +504,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PassInfoNode>([](const ObjectRef& ref, tvm::ReprPrinter* p) {
- auto* node = static_cast<const PassInfoNode*>(ref.get());
- p->stream << "The meta data of the pass - ";
- p->stream << "pass name: " << node->name;
- p->stream << ", opt_level: " << node->opt_level;
- if (node->required.empty()) {
- p->stream << ", required passes: []\n";
- } else {
- p->stream << ", required passes: ["
- << "\n";
- for (const auto& it : node->required) {
- p->stream << it << ", ";
- }
- p->stream << "]\n";
- }
- });
+// Pattern A (RM): auto-default repr from reflection for PassInfoNode.
TVM_FFI_STATIC_INIT_BLOCK() {
PassContextNode::RegisterReflection();
@@ -545,13 +528,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
[](Pass pass, ffi::RValueRef<IRModule> mod) { return
pass(*std::move(mod)); });
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ModulePassNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = static_cast<const ModulePassNode*>(ref.get());
- const PassInfo info = node->Info();
- p->stream << "Run Module pass: " << info->name << " at the optimization
level "
- << info->opt_level;
- });
+// Pattern A (RM): auto-default repr from reflection for ModulePassNode.
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
@@ -566,19 +543,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<SequentialNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = static_cast<const SequentialNode*>(ref.get());
- const PassInfo info = node->Info();
- p->stream << "Run Sequential pass: " << info->name << " at the
optimization level "
- << info->opt_level << ". ";
- p->stream << "The passes will be executed are: [";
- for (const auto& it : node->passes) {
- const PassInfo pass_info = it->Info();
- p->stream << pass_info->name << " ";
- }
- p->stream << "]";
- });
+// Pattern A (RM): auto-default repr from reflection for SequentialNode.
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
@@ -602,19 +567,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PassContextNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = static_cast<const PassContextNode*>(ref.get());
- p->stream << "Pass context information: "
- << "\n";
- p->stream << "\topt_level: " << node->opt_level << "\n";
-
- p->stream << "\trequired passes: " << node->required_pass << "\n";
- p->stream << "\tdisabled passes: " << node->disabled_pass << "\n";
- p->stream << "\tinstruments: " << node->instruments << "\n";
-
- p->stream << "\tconfig: " << node->config << "\n";
- });
+// Pattern A (RM): auto-default repr from reflection for PassContextNode.
class PassContext::Internal {
public:
diff --git a/src/node/container_printing.cc b/src/node/container_printing.cc
index b4773b2a81..3a6700c788 100644
--- a/src/node/container_printing.cc
+++ b/src/node/container_printing.cc
@@ -18,51 +18,9 @@
*/
/*!
- * Printer implementation for containers
- * \file node/container_printint.cc
+ * \file node/container_printing.cc
+ * \brief DEPRECATED — tvm-ffi provides built-in repr for Array/Map/Shape.
+ * The legacy ReprPrinter dispatches for containers are no longer
needed.
*/
-#include <tvm/ffi/function.h>
-#include <tvm/node/cast.h>
-#include <tvm/node/functor.h>
-#include <tvm/node/repr_printer.h>
-
-namespace tvm {
-
-// Container printer
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ffi::ArrayObj>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const ffi::ArrayObj*>(node.get());
- p->stream << '[';
- for (size_t i = 0; i < op->size(); ++i) {
- if (i != 0) {
- p->stream << ", ";
- }
- p->Print(op->at(i));
- }
- p->stream << ']';
- });
-
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ffi::MapObj>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const ffi::MapObj*>(node.get());
- p->stream << '{';
- for (auto it = op->begin(); it != op->end(); ++it) {
- if (it != op->begin()) {
- p->stream << ", ";
- }
- if (auto opt_str = it->first.as<ffi::String>()) {
- p->stream << '\"' << opt_str.value() << "\": ";
- } else {
- p->Print(it->first);
- p->stream << ": ";
- }
- p->Print(it->second);
- }
- p->stream << '}';
- });
-
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ffi::ShapeObj>([](const ObjectRef& node, ReprPrinter* p) {
- p->stream << Downcast<ffi::Shape>(node);
- });
-} // namespace tvm
+// This file is intentionally empty. Container repr is handled by
+// ffi::ReprPrint (tvm-ffi/src/ffi/extra/dataclass.cc).
diff --git a/src/node/repr.cc b/src/node/repr.cc
new file mode 100644
index 0000000000..a194708c6d
--- /dev/null
+++ b/src/node/repr.cc
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file node/repr.cc
+ * \brief Implements Dump helpers and FFI registration for ffi-repr-based
printing.
+ *
+ * The legacy ReprPrinter has been replaced by ffi::ReprPrint. This file:
+ * - Implements the Dump() debug helpers (they call ffi::ReprPrint).
+ * - Registers node.AsRepr (for backward Python compatibility) via
ffi::ReprPrint.
+ * - Registers __ffi_repr__ hooks for AccessPath and AccessStep.
+ */
+#include <tvm/ffi/extra/dataclass.h>
+#include <tvm/ffi/function.h>
+#include <tvm/ffi/reflection/access_path.h>
+#include <tvm/ffi/reflection/registry.h>
+#include <tvm/node/repr.h>
+#include <tvm/runtime/device_api.h>
+
+#include <sstream>
+
+namespace tvm {
+
+void Dump(const runtime::ObjectRef& n) { std::cerr <<
ffi::ReprPrint(ffi::Any(n)) << "\n"; }
+
+void Dump(const runtime::Object* n) {
Dump(runtime::GetRef<runtime::ObjectRef>(n)); }
+
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ // node.AsRepr: backward-compatible Python entry point.
+ // Python's tvm.runtime._ffi_node_api sets __object_repr__ = AsRepr via
init_ffi_api.
+ refl::GlobalDef().def("node.AsRepr",
+ [](ffi::Any obj) -> ffi::String { return
ffi::ReprPrint(obj); });
+ // Register __ffi_repr__ for AccessPath/AccessStep so that ffi.ReprPrint
+ // uses the concise "<root>.field[idx]" format.
+ //
+ // AccessStep: format one step fragment (e.g. ".field", "[0]", "[key]?").
+ refl::TypeAttrDef<ffi::reflection::AccessStepObj>().def(
+ refl::type_attr::kRepr,
+ [](ffi::reflection::AccessStep step, ffi::Function fn_repr) ->
ffi::String {
+ using ffi::reflection::AccessKind;
+ std::ostringstream os;
+ switch (step->kind) {
+ case AccessKind::kAttr:
+ os << "." << step->key.cast<ffi::String>();
+ break;
+ case AccessKind::kArrayItem:
+ os << "[" << step->key.cast<int64_t>() << "]";
+ break;
+ case AccessKind::kMapItem:
+ os << "[" << fn_repr(step->key).cast<ffi::String>() << "]";
+ break;
+ case AccessKind::kAttrMissing:
+ os << "." << step->key.cast<ffi::String>() << "?";
+ break;
+ case AccessKind::kArrayItemMissing:
+ os << "[" << step->key.cast<int64_t>() << "]?";
+ break;
+ case AccessKind::kMapItemMissing:
+ os << "[" << fn_repr(step->key).cast<ffi::String>() << "]?";
+ break;
+ }
+ return os.str();
+ });
+ // AccessPath: recurse through parent via fn_repr rather than walking the
+ // linked list manually. Root (no step) emits "<root>"; each non-root node
+ // prepends its parent's repr and appends the current step's repr.
+ refl::TypeAttrDef<ffi::reflection::AccessPathObj>().def(
+ refl::type_attr::kRepr,
+ [](ffi::reflection::AccessPath path, ffi::Function fn_repr) ->
ffi::String {
+ if (!path->step.has_value()) {
+ // Root node: no parent, no step.
+ return "<root>";
+ }
+ std::ostringstream os;
+ os << fn_repr(path->parent.value()).cast<ffi::String>();
+ os << fn_repr(path->step.value()).cast<ffi::String>();
+ return os.str();
+ });
+}
+} // namespace tvm
diff --git a/src/node/repr_printer.cc b/src/node/repr_printer.cc
index 142ad74eb5..de01909c8d 100644
--- a/src/node/repr_printer.cc
+++ b/src/node/repr_printer.cc
@@ -18,191 +18,8 @@
*/
/*!
- * Printer utilities
* \file node/repr_printer.cc
+ * \brief DEPRECATED — implementation moved to src/node/repr.cc.
*/
-#include <tvm/ffi/function.h>
-#include <tvm/ffi/reflection/access_path.h>
-#include <tvm/ffi/reflection/registry.h>
-#include <tvm/node/cast.h>
-#include <tvm/node/repr_printer.h>
-#include <tvm/runtime/device_api.h>
-
-#include <sstream>
-#include <vector>
-
-#include "../support/str_escape.h"
-
-namespace tvm {
-
-void ReprPrinter::Print(const ObjectRef& node) {
- static const FType& f = vtable();
- if (!node.defined()) {
- stream << "(nullptr)";
- } else {
- if (f.can_dispatch(node)) {
- f(node, this);
- } else {
- // default value, output type key and addr.
- stream << node->GetTypeKey() << "(" << node.get() << ")";
- }
- }
-}
-
-void ReprPrinter::Print(const ffi::Any& node) {
- switch (node.type_index()) {
- case ffi::TypeIndex::kTVMFFINone: {
- stream << "(nullptr)";
- break;
- }
- case ffi::TypeIndex::kTVMFFIInt: {
- stream << node.cast<int64_t>();
- break;
- }
- case ffi::TypeIndex::kTVMFFIBool: {
- stream << node.cast<bool>();
- break;
- }
- case ffi::TypeIndex::kTVMFFIFloat: {
- stream << node.cast<double>();
- break;
- }
- case ffi::TypeIndex::kTVMFFIOpaquePtr: {
- stream << node.cast<void*>();
- break;
- }
- case ffi::TypeIndex::kTVMFFIDataType: {
- stream << node.cast<DataType>();
- break;
- }
- case ffi::TypeIndex::kTVMFFIDevice: {
- runtime::operator<<(stream, node.cast<Device>());
- break;
- }
- case ffi::TypeIndex::kTVMFFIObject: {
- Print(node.cast<ObjectRef>());
- break;
- }
- case ffi::TypeIndex::kTVMFFISmallStr:
- case ffi::TypeIndex::kTVMFFIStr: {
- ffi::String str = node.cast<ffi::String>();
- stream << '"' << support::StrEscape(str.data(), str.size()) << '"';
- break;
- }
- case ffi::TypeIndex::kTVMFFISmallBytes:
- case ffi::TypeIndex::kTVMFFIBytes: {
- ffi::Bytes bytes = node.cast<ffi::Bytes>();
- stream << "b\"" << support::StrEscape(bytes.data(), bytes.size()) << '"';
- break;
- }
- default: {
- if (auto opt_obj = node.as<ObjectRef>()) {
- Print(opt_obj.value());
- } else {
- stream << "Any(type_key=`" << node.GetTypeKey() << "`)";
- }
- break;
- }
- }
-}
-
-void ReprPrinter::PrintIndent() {
- for (int i = 0; i < indent; ++i) {
- stream << ' ';
- }
-}
-
-ReprPrinter::FType& ReprPrinter::vtable() {
- static FType inst;
- return inst;
-}
-
-void Dump(const runtime::ObjectRef& n) { std::cerr << n << "\n"; }
-
-void Dump(const runtime::Object* n) {
Dump(runtime::GetRef<runtime::ObjectRef>(n)); }
-
-namespace {
-/*!
- * \brief Format an AccessStep as a concise string fragment.
- *
- * For map keys, uses ffi.ReprPrint which dispatches to __ffi_repr__.
- */
-void FormatAccessStep(std::ostringstream& os, const
ffi::reflection::AccessStep& step) {
- using ffi::reflection::AccessKind;
- static const ffi::Function repr_fn =
ffi::Function::GetGlobal("ffi.ReprPrint").value();
- switch (step->kind) {
- case AccessKind::kAttr:
- os << "." << step->key.cast<ffi::String>();
- break;
- case AccessKind::kArrayItem:
- os << "[" << step->key.cast<int64_t>() << "]";
- break;
- case AccessKind::kMapItem:
- os << "[" << repr_fn(step->key).cast<ffi::String>() << "]";
- break;
- case AccessKind::kAttrMissing:
- os << "." << step->key.cast<ffi::String>() << "?";
- break;
- case AccessKind::kArrayItemMissing:
- os << "[" << step->key.cast<int64_t>() << "]?";
- break;
- case AccessKind::kMapItemMissing:
- os << "[" << repr_fn(step->key).cast<ffi::String>() << "]?";
- break;
- }
-}
-
-/*!
- * \brief Format an AccessPath as "<root>.field[idx]".
- */
-ffi::String FormatAccessPath(const ffi::reflection::AccessPath& path) {
- std::vector<ffi::reflection::AccessStep> steps;
- const ffi::reflection::AccessPathObj* cur = path.get();
- while (cur->step.defined()) {
- steps.push_back(cur->step.value());
- cur = static_cast<const
ffi::reflection::AccessPathObj*>(cur->parent.get());
- }
- std::ostringstream os;
- os << "<root>";
- for (auto it = steps.rbegin(); it != steps.rend(); ++it) {
- FormatAccessStep(os, *it);
- }
- return os.str();
-}
-} // namespace
-
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ffi::reflection::AccessPathObj>([](const ObjectRef& node,
ReprPrinter* p) {
- p->stream <<
FormatAccessPath(Downcast<ffi::reflection::AccessPath>(node));
- });
-
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ffi::reflection::AccessStepObj>([](const ObjectRef& node,
ReprPrinter* p) {
- std::ostringstream os;
- FormatAccessStep(os, Downcast<ffi::reflection::AccessStep>(node));
- p->stream << os.str();
- });
-
-TVM_FFI_STATIC_INIT_BLOCK() {
- namespace refl = tvm::ffi::reflection;
- refl::GlobalDef().def("node.AsRepr", [](ffi::Any obj) {
- std::ostringstream os;
- os << obj;
- return os.str();
- });
- // Register __ffi_repr__ for AccessPath/AccessStep so that ffi.ReprPrint
- // uses the concise "<root>.field[idx]" format instead of the dataclass repr.
- refl::TypeAttrDef<ffi::reflection::AccessPathObj>().def(
- refl::type_attr::kRepr,
- [](ffi::reflection::AccessPath path, ffi::Function) -> ffi::String {
- return FormatAccessPath(path);
- });
- refl::TypeAttrDef<ffi::reflection::AccessStepObj>().def(
- refl::type_attr::kRepr,
- [](ffi::reflection::AccessStep step, ffi::Function) -> ffi::String {
- std::ostringstream os;
- FormatAccessStep(os, step);
- return os.str();
- });
-}
-} // namespace tvm
+// This file is intentionally empty. The legacy ReprPrinter has been removed.
+// See src/node/repr.cc for the replacement implementation.
diff --git a/src/node/script_printer.cc b/src/node/script_printer.cc
index 1774ba4b4b..2edf7860b5 100644
--- a/src/node/script_printer.cc
+++ b/src/node/script_printer.cc
@@ -16,11 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
+#include <tvm/ffi/extra/dataclass.h>
#include <tvm/ffi/function.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ir/expr.h>
#include <tvm/node/cast.h>
-#include <tvm/node/repr_printer.h>
+#include <tvm/node/repr.h>
#include <tvm/node/script_printer.h>
#include <algorithm>
@@ -39,10 +40,8 @@ TVMScriptPrinter::FType& TVMScriptPrinter::vtable() {
std::string TVMScriptPrinter::Script(const ObjectRef& node,
const ffi::Optional<PrinterConfig>& cfg) {
if (!TVMScriptPrinter::vtable().can_dispatch(node)) {
- std::ostringstream os;
- ReprPrinter printer(os);
- printer.Print(node);
- return os.str();
+ // Fall back to ffi::ReprPrint for types not registered with
TVMScriptPrinter.
+ return std::string(ffi::ReprPrint(ffi::Any(node)));
}
return TVMScriptPrinter::vtable()(node, cfg.value_or(PrinterConfig()));
}
diff --git a/src/relax/ir/dataflow_pattern.cc b/src/relax/ir/dataflow_pattern.cc
index ce34f4705f..90a8379236 100644
--- a/src/relax/ir/dataflow_pattern.cc
+++ b/src/relax/ir/dataflow_pattern.cc
@@ -22,10 +22,13 @@
* \brief The dataflow pattern language for Relax
*/
+#include <tvm/ffi/extra/dataclass.h>
#include <tvm/ffi/reflection/registry.h>
+#include <tvm/node/repr.h>
#include <tvm/relax/dataflow_pattern.h>
#include <tvm/relax/dataflow_pattern_functor.h>
+#include <sstream>
#include <stack>
#include <string>
@@ -56,12 +59,26 @@ TVM_FFI_STATIC_INIT_BLOCK() {
ConstantPatternNode::RegisterReflection();
}
-#define RELAX_PATTERN_PRINTER_DEF(NODE_TYPE, REPR_LAMBDA) \
- TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable) \
- .set_dispatch<NODE_TYPE>([](const ObjectRef& ref, ReprPrinter* p) { \
- auto* node = static_cast<const NODE_TYPE*>(ref.get()); \
- REPR_LAMBDA(p, node); \
- })
+// Helper used inside RELAX_PATTERN_PRINTER_DEF lambdas.
+// Mimics the ReprPrinter interface (p->stream, p->Print) so that existing
+// REPR_LAMBDA bodies compile without modification.
+struct PatternReprPrinterHelper {
+ std::ostringstream stream;
+ void Print(const ObjectRef& x) { stream << ffi::ReprPrint(ffi::Any(x)); }
+};
+
+#define RELAX_PATTERN_PRINTER_DEF(NODE_TYPE, REPR_LAMBDA)
\
+ TVM_FFI_STATIC_INIT_BLOCK() {
\
+ namespace refl = tvm::ffi::reflection;
\
+ refl::TypeAttrDef<NODE_TYPE>().def(refl::type_attr::kRepr,
\
+ [](ffi::ObjectRef ref, ffi::Function)
-> ffi::String { \
+ auto* node = static_cast<const
NODE_TYPE*>(ref.get()); \
+ PatternReprPrinterHelper printer;
\
+ auto* p = &printer;
\
+ REPR_LAMBDA(p, node);
\
+ return printer.stream.str();
\
+ });
\
+ }
ExternFuncPattern::ExternFuncPattern(ffi::String global_symbol) {
ObjectPtr<ExternFuncPatternNode> n =
ffi::make_object<ExternFuncPatternNode>();
diff --git a/src/relax/ir/emit_te.cc b/src/relax/ir/emit_te.cc
index 004a856fd6..f5b0c4474d 100644
--- a/src/relax/ir/emit_te.cc
+++ b/src/relax/ir/emit_te.cc
@@ -29,12 +29,7 @@
namespace tvm {
namespace relax {
-// RXPlaceholderOpNode
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<RXPlaceholderOpNode>([](const ObjectRef& node, ReprPrinter*
p) {
- auto* op = static_cast<const RXPlaceholderOpNode*>(node.get());
- p->stream << "rxplaceholder(" << op->name << ", " << op << ")";
- });
+// Pattern A (RM): auto-default repr from reflection for RXPlaceholderOpNode.
TVM_FFI_STATIC_INIT_BLOCK() { RXPlaceholderOpNode::RegisterReflection(); }
diff --git a/src/relax/ir/expr.cc b/src/relax/ir/expr.cc
index 2fbd573a5f..e58f88f04a 100644
--- a/src/relax/ir/expr.cc
+++ b/src/relax/ir/expr.cc
@@ -27,8 +27,6 @@
namespace tvm {
namespace relax {
-using tvm::ReprPrinter;
-
TVM_FFI_STATIC_INIT_BLOCK() {
IdNode::RegisterReflection();
CallNode::RegisterReflection();
diff --git a/src/relax/ir/transform.cc b/src/relax/ir/transform.cc
index 3fcdeeab83..49b32307f7 100644
--- a/src/relax/ir/transform.cc
+++ b/src/relax/ir/transform.cc
@@ -24,7 +24,7 @@
#include <tvm/ffi/function.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ffi/rvalue_ref.h>
-#include <tvm/node/repr_printer.h>
+#include <tvm/node/repr.h>
#include <tvm/relax/analysis.h>
#include <tvm/relax/expr_functor.h>
#include <tvm/relax/struct_info_functor.h>
@@ -176,13 +176,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<FunctionPassNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = static_cast<const FunctionPassNode*>(ref.get());
- const PassInfo info = node->Info();
- p->stream << "Run Function pass: " << info->name << " at the
optimization level "
- << info->opt_level;
- });
+// Pattern A (RM): auto-default repr from reflection for FunctionPassNode.
class DataflowBlockPass;
@@ -399,13 +393,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<DataflowBlockPassNode>([](const ObjectRef& ref, ReprPrinter*
p) {
- auto* node = static_cast<const DataflowBlockPassNode*>(ref.get());
- const PassInfo info = node->Info();
- p->stream << "Run DataflowBlock pass: " << info->name << " at the
optimization level "
- << info->opt_level;
- });
+// Pattern A (RM): auto-default repr from reflection for DataflowBlockPassNode.
TVM_FFI_STATIC_INIT_BLOCK() {
FunctionPassNode::RegisterReflection();
diff --git a/src/s_tir/data_layout.cc b/src/s_tir/data_layout.cc
index bee4c2e31f..392fd7a874 100644
--- a/src/s_tir/data_layout.cc
+++ b/src/s_tir/data_layout.cc
@@ -289,11 +289,13 @@ int32_t Layout::FactorOf(const LayoutAxis& axis) const {
return factor;
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<LayoutNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* l = static_cast<const LayoutNode*>(node.get());
- p->stream << "Layout(" << l->name << ")";
- });
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::TypeAttrDef<LayoutNode>().def(refl::type_attr::kRepr,
+ [](Layout l, ffi::Function) ->
ffi::String {
+ return "Layout(" +
std::string(l->name) + ")";
+ });
+}
inline bool GetStoreRule(ffi::Array<PrimExpr>* index_rule,
ffi::Array<PrimExpr>* shape_rule,
const Layout& src_layout, const Layout& dst_layout) {
@@ -570,12 +572,14 @@ BijectiveLayout::BijectiveLayout(Layout src_layout,
Layout dst_layout) {
}
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<BijectiveLayoutNode>([](const ObjectRef& node, ReprPrinter*
p) {
- auto* b = static_cast<const BijectiveLayoutNode*>(node.get());
- p->stream << "BijectiveLayout(" << b->src_layout.name() << "->" <<
b->dst_layout.name()
- << ")";
- });
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::TypeAttrDef<BijectiveLayoutNode>().def(
+ refl::type_attr::kRepr, [](BijectiveLayout bl, ffi::Function) ->
ffi::String {
+ return "BijectiveLayout(" + std::string(bl->src_layout.name()) + "->" +
+ std::string(bl->dst_layout.name()) + ")";
+ });
+}
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
diff --git a/src/s_tir/meta_schedule/arg_info.cc
b/src/s_tir/meta_schedule/arg_info.cc
index f873f0a8a3..bcb2fd81c6 100644
--- a/src/s_tir/meta_schedule/arg_info.cc
+++ b/src/s_tir/meta_schedule/arg_info.cc
@@ -19,6 +19,8 @@
#include <tvm/ffi/reflection/registry.h>
#include <tvm/s_tir/transform.h>
+#include <sstream>
+
#include "./utils.h"
namespace tvm {
@@ -153,12 +155,22 @@ TensorInfo TensorInfo::FromJSON(const ObjectRef&
json_obj) {
/******** Repr ********/
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<TensorInfoNode>([](const ObjectRef& n, ReprPrinter* p) {
- const auto* self = n.as<TensorInfoNode>();
- TVM_FFI_ICHECK(self);
- p->stream << "TensorInfo(\"" << self->dtype << "\", " << self->shape <<
")";
- });
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::TypeAttrDef<TensorInfoNode>().def(refl::type_attr::kRepr,
+ [](TensorInfo ti, ffi::Function) ->
ffi::String {
+ std::ostringstream os;
+ os << "TensorInfo(\"" << ti->dtype
<< "\", [";
+ bool first = true;
+ for (int64_t v : ti->shape) {
+ if (!first) os << ", ";
+ os << v;
+ first = false;
+ }
+ os << "])";
+ return os.str();
+ });
+}
/******** FFI ********/
TVM_FFI_STATIC_INIT_BLOCK() { TensorInfoNode::RegisterReflection(); }
diff --git a/src/s_tir/meta_schedule/cost_model/cost_model.cc
b/src/s_tir/meta_schedule/cost_model/cost_model.cc
index 34d0cf5d77..6e9e8a464b 100644
--- a/src/s_tir/meta_schedule/cost_model/cost_model.cc
+++ b/src/s_tir/meta_schedule/cost_model/cost_model.cc
@@ -63,17 +63,16 @@ CostModel CostModel::PyCostModel(PyCostModelNode::FLoad
f_load, //
return CostModel(n);
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PyCostModelNode>([](const ObjectRef& n, ReprPrinter* p) {
- const auto* self = n.as<PyCostModelNode>();
- TVM_FFI_ICHECK(self);
- PyCostModelNode::FAsString f_as_string = (*self).f_as_string;
- TVM_FFI_ICHECK(f_as_string != nullptr) << "PyCostModel's AsString method
not implemented!";
- p->stream << f_as_string();
- });
+// Pattern A (RM): auto-default repr from reflection.
+// Ensure the type index is allocated for Python registration to work.
+// (Previously,
TVM_STATIC_IR_FUNCTOR(ReprPrinter).set_dispatch<PyCostModelNode> had
+// a side-effect of calling PyCostModelNode::RuntimeTypeIndex() which
registered the type.)
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
+ // Trigger type index allocation for types that Python @register_object
needs to find.
+ refl::ObjectDef<CostModelNode>();
+ refl::ObjectDef<PyCostModelNode>();
refl::GlobalDef()
.def_method("s_tir.meta_schedule.CostModelLoad", &CostModelNode::Load)
.def_method("s_tir.meta_schedule.CostModelSave", &CostModelNode::Save)
diff --git a/src/s_tir/meta_schedule/feature_extractor/feature_extractor.cc
b/src/s_tir/meta_schedule/feature_extractor/feature_extractor.cc
index e037231943..af8acc3d1c 100644
--- a/src/s_tir/meta_schedule/feature_extractor/feature_extractor.cc
+++ b/src/s_tir/meta_schedule/feature_extractor/feature_extractor.cc
@@ -40,15 +40,7 @@ FeatureExtractor FeatureExtractor::PyFeatureExtractor(
return FeatureExtractor(n);
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PyFeatureExtractorNode>([](const ObjectRef& n, ReprPrinter*
p) {
- const auto* self = n.as<PyFeatureExtractorNode>();
- TVM_FFI_ICHECK(self);
- PyFeatureExtractorNode::FAsString f_as_string = (*self).f_as_string;
- TVM_FFI_ICHECK(f_as_string != nullptr)
- << "PyFeatureExtractor's AsString method not implemented!";
- p->stream << f_as_string();
- });
+// Pattern A (RM): auto-default repr from reflection.
TVM_FFI_STATIC_INIT_BLOCK() {
FeatureExtractorNode::RegisterReflection();
diff --git a/src/s_tir/meta_schedule/measure_callback/measure_callback.cc
b/src/s_tir/meta_schedule/measure_callback/measure_callback.cc
index 9f2a3056c2..38343338e6 100644
--- a/src/s_tir/meta_schedule/measure_callback/measure_callback.cc
+++ b/src/s_tir/meta_schedule/measure_callback/measure_callback.cc
@@ -50,15 +50,7 @@ ffi::Array<MeasureCallback, void> MeasureCallback::Default()
{
};
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PyMeasureCallbackNode>([](const ObjectRef& n, ReprPrinter*
p) {
- const auto* self = n.as<PyMeasureCallbackNode>();
- TVM_FFI_ICHECK(self);
- PyMeasureCallbackNode::FAsString f_as_string = (*self).f_as_string;
- TVM_FFI_ICHECK(f_as_string != nullptr)
- << "PyMeasureCallback's AsString method not implemented!";
- p->stream << f_as_string();
- });
+// Pattern A (RM): auto-default repr from reflection.
TVM_FFI_STATIC_INIT_BLOCK() {
MeasureCallbackNode::RegisterReflection();
diff --git a/src/s_tir/meta_schedule/mutator/mutator.cc
b/src/s_tir/meta_schedule/mutator/mutator.cc
index 8821a239b4..b4b46f8e2a 100644
--- a/src/s_tir/meta_schedule/mutator/mutator.cc
+++ b/src/s_tir/meta_schedule/mutator/mutator.cc
@@ -79,14 +79,7 @@ ffi::Map<Mutator, FloatImm> Mutator::DefaultHexagon() {
{Mutator::MutateParallel(/*max_jobs_per_core=*/16),
FloatImm(DataType::Float(64), 0.02)}};
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PyMutatorNode>([](const ObjectRef& n, ReprPrinter* p) {
- const auto* self = n.as<PyMutatorNode>();
- TVM_FFI_ICHECK(self);
- PyMutatorNode::FAsString f_as_string = (*self).f_as_string;
- TVM_FFI_ICHECK(f_as_string != nullptr) << "PyMutator's AsString method
not implemented!";
- p->stream << f_as_string();
- });
+// Pattern A (RM): auto-default repr from reflection.
TVM_FFI_STATIC_INIT_BLOCK() {
MutatorNode::RegisterReflection();
diff --git a/src/s_tir/meta_schedule/postproc/postproc.cc
b/src/s_tir/meta_schedule/postproc/postproc.cc
index ac8f73f260..d9363b811c 100644
--- a/src/s_tir/meta_schedule/postproc/postproc.cc
+++ b/src/s_tir/meta_schedule/postproc/postproc.cc
@@ -111,14 +111,7 @@ ffi::Array<Postproc> Postproc::DefaultHexagon() {
};
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PyPostprocNode>([](const ObjectRef& n, ReprPrinter* p) {
- const auto* self = n.as<PyPostprocNode>();
- TVM_FFI_ICHECK(self);
- PyPostprocNode::FAsString f_as_string = (*self).f_as_string;
- TVM_FFI_ICHECK(f_as_string != nullptr) << "PyPostproc's AsString method
not implemented!";
- p->stream << f_as_string();
- });
+// Pattern A (RM): auto-default repr from reflection.
TVM_FFI_STATIC_INIT_BLOCK() {
PostprocNode::RegisterReflection();
diff --git a/src/s_tir/meta_schedule/schedule_rule/schedule_rule.cc
b/src/s_tir/meta_schedule/schedule_rule/schedule_rule.cc
index 04a9a99eba..57ca24e531 100644
--- a/src/s_tir/meta_schedule/schedule_rule/schedule_rule.cc
+++ b/src/s_tir/meta_schedule/schedule_rule/schedule_rule.cc
@@ -451,14 +451,7 @@ ffi::Array<ScheduleRule> ScheduleRule::DefaultARM(const
ffi::String& type) {
ScheduleRule::RandomComputeLocation());
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PyScheduleRuleNode>([](const ObjectRef& n, ReprPrinter* p) {
- const auto* self = n.as<PyScheduleRuleNode>();
- TVM_FFI_ICHECK(self);
- PyScheduleRuleNode::FAsString f_as_string = (*self).f_as_string;
- TVM_FFI_ICHECK(f_as_string != nullptr) << "PyScheduleRule's AsString
method not implemented!";
- p->stream << f_as_string();
- });
+// Pattern A (RM): auto-default repr from reflection.
TVM_FFI_STATIC_INIT_BLOCK() {
ScheduleRuleNode::RegisterReflection();
diff --git a/src/s_tir/schedule/instruction.cc
b/src/s_tir/schedule/instruction.cc
index ef635462ab..a75ec7a333 100644
--- a/src/s_tir/schedule/instruction.cc
+++ b/src/s_tir/schedule/instruction.cc
@@ -79,8 +79,8 @@ ffi::String InstructionAsPythonRepr(const InstructionNode*
self) {
} else if (obj.as<IntImmNode>() || obj.as<FloatImmNode>()) {
inputs.push_back(obj);
} else if (const auto* expr = obj.as<PrimExprNode>()) {
- PrimExpr new_expr = Substitute(
- ffi::GetRef<PrimExpr>(expr), [](const Var& var) ->
ffi::Optional<PrimExpr> {
+ PrimExpr new_expr =
+ Substitute(ffi::GetRef<PrimExpr>(expr), [](const Var& var) ->
ffi::Optional<PrimExpr> {
ObjectPtr<VarNode> new_var = ffi::make_object<VarNode>(*var.get());
new_var->name_hint = "_";
return Var(new_var);
@@ -103,10 +103,7 @@ ffi::String InstructionAsPythonRepr(const InstructionNode*
self) {
}
} // namespace
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<InstructionNode>([](const ObjectRef& obj, ReprPrinter* p) {
- p->stream << InstructionAsPythonRepr(obj.as<InstructionNode>());
- });
+// AC: kRepr already registered below in TVM_FFI_STATIC_INIT_BLOCK.
/**************** FFI ****************/
@@ -119,10 +116,10 @@ TVM_FFI_STATIC_INIT_BLOCK() {
ffi::Array<Any> outputs) -> Instruction {
return Instruction(kind, inputs, attrs, outputs);
});
- refl::TypeAttrDef<InstructionNode>().def(
- refl::type_attr::kRepr, [](Instruction inst, ffi::Function) ->
ffi::String {
- return InstructionAsPythonRepr(inst.get());
- });
+ refl::TypeAttrDef<InstructionNode>().def(refl::type_attr::kRepr,
+ [](Instruction inst, ffi::Function)
-> ffi::String {
+ return
InstructionAsPythonRepr(inst.get());
+ });
}
} // namespace s_tir
diff --git a/src/s_tir/schedule/trace.cc b/src/s_tir/schedule/trace.cc
index 17b169b857..fae3279e90 100644
--- a/src/s_tir/schedule/trace.cc
+++ b/src/s_tir/schedule/trace.cc
@@ -546,12 +546,6 @@ ffi::String TraceAsPythonRepr(const TraceNode* self) {
}
} // namespace
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<TraceNode>([](const ObjectRef& obj, ReprPrinter* p) {
- p->stream << TraceAsPythonRepr(obj.as<TraceNode>());
- p->stream << std::flush;
- });
-
/**************** Instruction Registration ****************/
struct EnterPostprocTraits : public UnpackedInstTraits<EnterPostprocTraits> {
diff --git a/src/script/printer/ir/utils.h b/src/script/printer/ir/utils.h
index 588e6066d9..6afc52cab7 100644
--- a/src/script/printer/ir/utils.h
+++ b/src/script/printer/ir/utils.h
@@ -59,7 +59,7 @@ class IRFrame : public Frame {
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(IRFrame, Frame, IRFrameNode);
};
-/*! \brief Redirected method for the ReprPrinter */
+/*! \brief Redirected method for the ffi repr hook */
inline std::string ReprPrintIR(const ObjectRef& obj, const PrinterConfig& cfg)
{
IRDocsifier d(cfg);
With<IRFrame> f(d);
diff --git a/src/script/printer/relax/utils.h b/src/script/printer/relax/utils.h
index d6aa98fda7..9982d31da9 100644
--- a/src/script/printer/relax/utils.h
+++ b/src/script/printer/relax/utils.h
@@ -67,7 +67,7 @@ class RelaxFrame : public Frame {
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(RelaxFrame, Frame,
RelaxFrameNode);
};
-/*! \brief Redirected method for the ReprPrinter */
+/*! \brief Redirected method for the ffi repr hook */
inline std::string ReprPrintRelax(const ObjectRef& obj, const PrinterConfig&
cfg) {
IRDocsifier d(cfg);
With<RelaxFrame> f(d);
diff --git a/src/script/printer/tirx/utils.h b/src/script/printer/tirx/utils.h
index fb512769b0..3810b35715 100644
--- a/src/script/printer/tirx/utils.h
+++ b/src/script/printer/tirx/utils.h
@@ -166,7 +166,7 @@ inline ffi::Optional<Frame> FindLowestVarDef(const
ObjectRef& var, const IRDocsi
return std::nullopt;
}
-/*! \brief Redirected method for the ReprPrinter */
+/*! \brief Redirected method for the ffi repr hook */
inline std::string ReprPrintTIR(const ObjectRef& obj, const PrinterConfig&
cfg) {
IRDocsifier d(cfg);
d->SetCommonPrefix(obj, [](const ObjectRef& obj) {
diff --git a/src/script/printer/utils.h b/src/script/printer/utils.h
index 78f12d4983..1ec51450e3 100644
--- a/src/script/printer/utils.h
+++ b/src/script/printer/utils.h
@@ -19,11 +19,14 @@
#ifndef TVM_SCRIPT_PRINTER_UTILS_H_
#define TVM_SCRIPT_PRINTER_UTILS_H_
+#include <tvm/ffi/extra/dataclass.h>
#include <tvm/ffi/extra/json.h>
#include <tvm/ffi/extra/serialization.h>
+#include <tvm/ffi/reflection/registry.h>
#include <tvm/runtime/base.h>
#include <tvm/script/printer/ir_docsifier.h>
+#include <sstream>
#include <string>
#include <unordered_set>
#include <utility>
@@ -35,18 +38,25 @@ namespace tvm {
namespace script {
namespace printer {
-#define TVM_SCRIPT_REPR(ObjectType, Method) \
- TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable) \
- .set_dispatch<ObjectType>(RedirectedReprPrinterMethod); \
- TVM_STATIC_IR_FUNCTOR(TVMScriptPrinter,
vtable).set_dispatch<ObjectType>(Method);
-
-inline void RedirectedReprPrinterMethod(const ObjectRef& obj, ReprPrinter* p) {
+#define TVM_SCRIPT_REPR(ObjectType, Method)
\
+ TVM_FFI_STATIC_INIT_BLOCK() {
\
+ namespace refl = tvm::ffi::reflection;
\
+ refl::TypeAttrDef<ObjectType>().def(refl::type_attr::kRepr,
\
+ [](ffi::ObjectRef obj, ffi::Function)
-> ffi::String { \
+ return
RedirectedReprPrinterMethod(obj); \
+ });
\
+ }
\
+ TVM_STATIC_IR_FUNCTOR(TVMScriptPrinter,
vtable).set_dispatch<ObjectType>(Method)
+
+inline std::string RedirectedReprPrinterMethod(const ObjectRef& obj) {
try {
- p->stream << TVMScriptPrinter::Script(obj, std::nullopt);
+ return TVMScriptPrinter::Script(obj, std::nullopt);
} catch (const tvm::Error& e) {
LOG(WARNING) << "TVMScript printer falls back to the basic address printer
with the error:\n"
<< e.what();
- p->stream << obj->GetTypeKey() << '(' << obj.get() << ')';
+ std::ostringstream os;
+ os << obj->GetTypeKey() << '(' << obj.get() << ')';
+ return os.str();
}
}
diff --git a/src/target/target.cc b/src/target/target.cc
index 2c093ee73f..3a414d40ba 100644
--- a/src/target/target.cc
+++ b/src/target/target.cc
@@ -488,9 +488,6 @@ TVM_FFI_STATIC_INIT_BLOCK() {
[](Target target, ffi::Function) -> ffi::String { return target->str();
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<TargetNode>([](const ObjectRef& obj, ReprPrinter* p) {
- p->stream << Downcast<Target>(obj)->str();
- });
+// AC: kRepr already registered above at
refl::TypeAttrDef<TargetNode>().def(kRepr, ...)
} // namespace tvm
diff --git a/src/target/target_kind.cc b/src/target/target_kind.cc
index 2fb5e17d5f..8d4cd50a9a 100644
--- a/src/target/target_kind.cc
+++ b/src/target/target_kind.cc
@@ -54,11 +54,12 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<TargetKindNode>([](const ObjectRef& obj, ReprPrinter* p) {
- const TargetKind& kind = Downcast<TargetKind>(obj);
- p->stream << kind->name;
- });
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::TypeAttrDef<TargetKindNode>().def(
+ refl::type_attr::kRepr,
+ [](TargetKind kind, ffi::Function) -> ffi::String { return kind->name;
});
+}
/********** Registry-related code **********/
diff --git a/src/target/virtual_device.cc b/src/target/virtual_device.cc
index cd9d8f4ead..c17298fdfd 100644
--- a/src/target/virtual_device.cc
+++ b/src/target/virtual_device.cc
@@ -26,45 +26,46 @@
#include <tvm/runtime/device_api.h>
#include <tvm/target/virtual_device.h>
+#include <sstream>
+
namespace tvm {
TVM_FFI_STATIC_INIT_BLOCK() { VirtualDeviceNode::RegisterReflection(); }
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<VirtualDeviceNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = ref.as<VirtualDeviceNode>();
- p->stream << "VirtualDevice(";
- if (node->IsFullyUnconstrained()) {
- p->stream << "?";
- } else {
- bool need_sep = false;
- if (node->device_type() != kInvalidDeviceType) {
- p->stream << "device_type=" << node->device_type();
- need_sep = true;
- }
- if (node->virtual_device_id >= 0) {
- if (need_sep) {
- p->stream << ", ";
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::TypeAttrDef<VirtualDeviceNode>().def(
+ refl::type_attr::kRepr, [](VirtualDevice vd, ffi::Function) ->
ffi::String {
+ auto* node = vd.get();
+ std::ostringstream os;
+ os << "VirtualDevice(";
+ if (node->IsFullyUnconstrained()) {
+ os << "?";
+ } else {
+ bool need_sep = false;
+ if (node->device_type() != kInvalidDeviceType) {
+ os << "device_type=" << node->device_type();
+ need_sep = true;
}
- p->stream << "virtual_device_id=" << node->virtual_device_id;
- need_sep = true;
- }
- if (node->target.defined()) {
- if (need_sep) {
- p->stream << ", ";
+ if (node->virtual_device_id >= 0) {
+ if (need_sep) os << ", ";
+ os << "virtual_device_id=" << node->virtual_device_id;
+ need_sep = true;
}
- p->stream << "target=" << node->target->str();
- need_sep = true;
- }
- if (!node->memory_scope.empty()) {
- if (need_sep) {
- p->stream << ", ";
+ if (node->target.defined()) {
+ if (need_sep) os << ", ";
+ os << "target=" << node->target->str();
+ need_sep = true;
+ }
+ if (!node->memory_scope.empty()) {
+ if (need_sep) os << ", ";
+ os << "memory_scope='" << node->memory_scope << "'";
}
- p->stream << "memory_scope='" << node->memory_scope << "'";
}
- }
- p->stream << ")";
- });
+ os << ")";
+ return os.str();
+ });
+}
VirtualDevice::VirtualDevice(int device_type_int, int virtual_device_id,
Target target,
MemoryScope memory_scope) {
diff --git a/src/te/operation/compute_op.cc b/src/te/operation/compute_op.cc
index 40ac3232c3..9df3242eca 100644
--- a/src/te/operation/compute_op.cc
+++ b/src/te/operation/compute_op.cc
@@ -45,13 +45,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
ComputeOpNode::RegisterReflection();
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ComputeOpNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const ComputeOpNode*>(node.get());
- p->stream << "compute(" << op->name << ", body=" << op->body << ",
axis=" << op->axis
- << ", reduce_axis=" << op->reduce_axis << ", tag=" << op->tag
- << ", attrs=" << op->attrs << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
/// Verify if ComputeOp is valid with respect to Reduce operations.
static void VerifyComputeOp(const ComputeOpNode* op);
diff --git a/src/te/operation/extern_op.cc b/src/te/operation/extern_op.cc
index 7149156091..b6b7c17691 100644
--- a/src/te/operation/extern_op.cc
+++ b/src/te/operation/extern_op.cc
@@ -33,12 +33,7 @@ using namespace tirx;
TVM_FFI_STATIC_INIT_BLOCK() { ExternOpNode::RegisterReflection(); }
-// ExternOpNode
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ExternOpNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const ExternOpNode*>(node.get());
- p->stream << "extern(" << op->name << ", " << op << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
int ExternOpNode::num_outputs() const { return
static_cast<int>(output_placeholders.size()); }
diff --git a/src/te/operation/placeholder_op.cc
b/src/te/operation/placeholder_op.cc
index a063c83045..17f4791d76 100644
--- a/src/te/operation/placeholder_op.cc
+++ b/src/te/operation/placeholder_op.cc
@@ -31,12 +31,7 @@ namespace te {
TVM_FFI_STATIC_INIT_BLOCK() { PlaceholderOpNode::RegisterReflection(); }
-// PlaceholderOpNode
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PlaceholderOpNode>([](const ObjectRef& node, ReprPrinter* p)
{
- auto* op = static_cast<const PlaceholderOpNode*>(node.get());
- p->stream << "placeholder(" << op->name << ", " << op << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
int PlaceholderOpNode::num_outputs() const { return 1; }
diff --git a/src/te/operation/scan_op.cc b/src/te/operation/scan_op.cc
index 09f464f466..bfee2b4222 100644
--- a/src/te/operation/scan_op.cc
+++ b/src/te/operation/scan_op.cc
@@ -32,11 +32,7 @@ using namespace tirx;
TVM_FFI_STATIC_INIT_BLOCK() { ScanOpNode::RegisterReflection(); }
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<ScanOpNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* op = static_cast<const ScanOpNode*>(node.get());
- p->stream << "scan(" << op->name << ", " << op << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
int ScanOpNode::num_outputs() const { return static_cast<int>(update.size()); }
diff --git a/src/te/tensor.cc b/src/te/tensor.cc
index 031f2a0aba..fe521ea9c9 100644
--- a/src/te/tensor.cc
+++ b/src/te/tensor.cc
@@ -121,11 +121,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<TensorNode>([](const ObjectRef& node, ReprPrinter* p) {
- auto* t = static_cast<const TensorNode*>(node.get());
- p->stream << "Tensor(shape=" << t->shape << ", op.name=" << t->op->name
<< ')';
- });
+// Pattern A (RM): auto-default repr from reflection.
// Other tensor ops.
TVM_FFI_STATIC_INIT_BLOCK() {
diff --git a/src/tirx/ir/expr.cc b/src/tirx/ir/expr.cc
index f4130e70d6..a3f300a03b 100644
--- a/src/tirx/ir/expr.cc
+++ b/src/tirx/ir/expr.cc
@@ -84,15 +84,8 @@ TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
refl::GlobalDef().def("tirx.convert",
[](ffi::Variant<PrimExpr, ffi::Array<PrimExpr>> expr)
{ return expr; });
- // Register __ffi_repr__ for Var/SizeVar so repr shows just the name
- refl::TypeAttrDef<VarNode>().def(refl::type_attr::kRepr,
- [](Var var, ffi::Function) -> ffi::String {
- return std::string(var->name_hint);
- });
- refl::TypeAttrDef<SizeVarNode>().def(refl::type_attr::kRepr,
- [](SizeVar var, ffi::Function) ->
ffi::String {
- return std::string(var->name_hint);
- });
+ // Note: kRepr for VarNode/SizeVarNode is registered via TVM_SCRIPT_REPR in
+ // src/script/printer/tirx/expr.cc (-> ReprPrintTIR which delegates to
TVMScriptPrinter).
}
#define TVM_DEFINE_BINOP_CONSTRUCTOR(Name) \
diff --git a/src/tirx/ir/transform.cc b/src/tirx/ir/transform.cc
index f5a99c454c..3cf2f58008 100644
--- a/src/tirx/ir/transform.cc
+++ b/src/tirx/ir/transform.cc
@@ -24,7 +24,7 @@
#include <tvm/ffi/function.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ffi/rvalue_ref.h>
-#include <tvm/node/repr_printer.h>
+#include <tvm/node/repr.h>
#include <tvm/tirx/transform.h>
namespace tvm {
@@ -158,12 +158,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
});
}
-TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
- .set_dispatch<PrimFuncPassNode>([](const ObjectRef& ref, ReprPrinter* p) {
- auto* node = static_cast<const PrimFuncPassNode*>(ref.get());
- const PassInfo info = node->Info();
- p->stream << "PrimFuncPass(" << info->name << ", opt_level=" <<
info->opt_level << ")";
- });
+// Pattern A (RM): auto-default repr from reflection.
} // namespace transform
} // namespace tirx
diff --git a/tests/python/tirx-transform/test_tir_transform_vectorize.py
b/tests/python/tirx-transform/test_tir_transform_vectorize.py
index 02b82df6e4..ec38c4a975 100644
--- a/tests/python/tirx-transform/test_tir_transform_vectorize.py
+++ b/tests/python/tirx-transform/test_tir_transform_vectorize.py
@@ -499,7 +499,7 @@ def test_illegal_extent():
for j in T.vectorized(n):
A[j] = 3
- error_msg = "Failed to vectorize loop with extent n for target
\\(nullptr\\)"
+ error_msg = "Failed to vectorize loop with extent n for target None"
with pytest.raises(tvm.error.InternalError, match=error_msg):
tvm.tirx.transform.VectorizeLoop()(Mod)