This is an automated email from the ASF dual-hosted git repository.
tqchen 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 44dbd138d5 [FFI] Bump tvm-ffi to 63224e3 and fix regressions (#18938)
44dbd138d5 is described below
commit 44dbd138d51314309955fba8c3d1294e4a89da35
Author: Tianqi Chen <[email protected]>
AuthorDate: Sat Mar 28 09:38:18 2026 -0400
[FFI] Bump tvm-ffi to 63224e3 and fix regressions (#18938)
## Summary
Bump tvm-ffi submodule from c85fd42 (#471) to 63224e3 (#512), spanning
41 commits with 7 breaking changes. Fix regressions introduced by the
bump:
### Fixes
1. **Duplicate field declarations in C++ types** — New tvm-ffi
auto-wires `__init__` from C++ reflection by walking the parent type
chain. Child types that re-declared parent fields
(`RXPlaceholderOpNode`, `FunctionFrameNode`) caused duplicate parameter
errors. Fixed by removing duplicate field registrations from child
types.
2. **Repr format regression** (7 tests) — New tvm-ffi `CObject.__repr__`
uses dataclass repr. Added `Node.__repr__` in `python/tvm/ir/base.py` to
use TVMScript printer for IR nodes.
3. **Host/device function split** (3 tests) — `str(target.kind)` now
returns full dataclass repr instead of kind name. Changed to
`target.kind.name` in `python/tvm/tirx/build.py`.
4. **`__slots__` enforcement** — New tvm-ffi enforces `__slots__=()` on
Object subclasses. Added `__slots__ = ("__dict__",)` to classes that
need instance attributes: `Pass`, `BlockBuilder`, `TVMDerivedObject`.
### Changes
- `3rdparty/tvm-ffi` — submodule bump c85fd42 → 63224e3
- `python/tvm/ir/base.py` — `Node.__repr__` using TVMScript printer
- `python/tvm/ir/transform.py` — `Pass.__slots__ = ("__dict__",)`
- `python/tvm/tirx/build.py` — `target.kind.name` instead of
`str(target.kind)`
- `python/tvm/relax/block_builder.py` — `BlockBuilder.__slots__ =
("__dict__",)`
- `python/tvm/runtime/support.py` — `TVMDerivedObject.__slots__ =
("__dict__", "__weakref__")`
- `python/tvm/s_tir/meta_schedule/utils.py` —
`TVMDerivedObject.__slots__ = ("__dict__",)`
- `include/tvm/script/ir_builder/relax/frame.h` — remove duplicate field
registrations
- `src/relax/ir/emit_te.h` — remove duplicate field registrations
## Test plan
- [x] tirx-base: 251 passed, 23 skipped
- [x] relax import + build: verified
- [ ] Full CI
---
3rdparty/tvm-ffi | 2 +-
include/tvm/script/ir_builder/relax/frame.h | 5 +-
python/tvm/ir/base.py | 8 +++
python/tvm/ir/transform.py | 2 +
python/tvm/relax/binding_rewrite.py | 2 +
python/tvm/relax/block_builder.py | 2 +
python/tvm/runtime/support.py | 2 +
python/tvm/s_tir/meta_schedule/utils.py | 2 +
python/tvm/tirx/build.py | 2 +-
src/ir/expr.cc | 4 ++
src/node/repr_printer.cc | 74 ++++++++++++++++++-
src/relax/ir/emit_te.h | 7 +-
src/s_tir/schedule/instruction.cc | 83 ++++++++++++----------
src/s_tir/schedule/trace.cc | 46 +++++++-----
src/target/target.cc | 8 ++-
src/tirx/ir/expr.cc | 9 +++
tests/python/ir/test_pass_instrument.py | 4 +-
.../python/tvmscript/test_tvmscript_printer_doc.py | 4 +-
18 files changed, 193 insertions(+), 73 deletions(-)
diff --git a/3rdparty/tvm-ffi b/3rdparty/tvm-ffi
index c85fd42df6..63224e3f1e 160000
--- a/3rdparty/tvm-ffi
+++ b/3rdparty/tvm-ffi
@@ -1 +1 @@
-Subproject commit c85fd42df6eae4ae0ec1aaa4ebb67ac859758cf5
+Subproject commit 63224e3f1e464cc62307223787926a48fc8df8c0
diff --git a/include/tvm/script/ir_builder/relax/frame.h
b/include/tvm/script/ir_builder/relax/frame.h
index 898e318950..3d4ca32674 100644
--- a/include/tvm/script/ir_builder/relax/frame.h
+++ b/include/tvm/script/ir_builder/relax/frame.h
@@ -125,9 +125,8 @@ class FunctionFrameNode : public SeqExprFrameNode {
.def_ro("params", &FunctionFrameNode::params)
.def_ro("ret_struct_info", &FunctionFrameNode::ret_struct_info)
.def_ro("is_pure", &FunctionFrameNode::is_pure)
- .def_ro("attrs", &FunctionFrameNode::attrs)
- .def_ro("binding_blocks", &FunctionFrameNode::binding_blocks)
- .def_ro("output", &FunctionFrameNode::output);
+ .def_ro("attrs", &FunctionFrameNode::attrs);
+ // `binding_blocks` and `output` are inherited from SeqExprFrameNode.
// `block_builder` is not registered as it's not visited.
}
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.ir_builder.relax.FunctionFrame",
FunctionFrameNode,
diff --git a/python/tvm/ir/base.py b/python/tvm/ir/base.py
index e466ef8500..15629dcbe6 100644
--- a/python/tvm/ir/base.py
+++ b/python/tvm/ir/base.py
@@ -27,6 +27,14 @@ from . import _ffi_api, json_compact
class Node(Object):
"""Base class of all IR Nodes."""
+ def __repr__(self) -> str:
+ from tvm.runtime.script_printer import _script # noqa: PLC0415
+
+ try:
+ return _script(self, None)
+ except Exception: # noqa: BLE001
+ return super().__repr__()
+
@register_object("ir.SourceMap")
class SourceMap(Object):
diff --git a/python/tvm/ir/transform.py b/python/tvm/ir/transform.py
index 28c187d7de..3e22a2b908 100644
--- a/python/tvm/ir/transform.py
+++ b/python/tvm/ir/transform.py
@@ -147,6 +147,8 @@ class Pass(tvm.runtime.Object):
conveniently interact with the base class.
"""
+ __slots__ = ("__dict__",)
+
@property
def info(self):
"""Get the pass meta."""
diff --git a/python/tvm/relax/binding_rewrite.py
b/python/tvm/relax/binding_rewrite.py
index 0128789368..0198befd33 100644
--- a/python/tvm/relax/binding_rewrite.py
+++ b/python/tvm/relax/binding_rewrite.py
@@ -38,6 +38,8 @@ class DataflowBlockRewrite(Object):
use mutate_irmodule which rewrites the old function that registered in the
constructor.
"""
+ __slots__ = ("__dict__",)
+
def __init__(self, dfb: DataflowBlock, root_fn: Function):
"""
Construct a rewriter with the DataflowBlock to rewrite and its root
function.
diff --git a/python/tvm/relax/block_builder.py
b/python/tvm/relax/block_builder.py
index 1d6057cec5..13bea3180c 100644
--- a/python/tvm/relax/block_builder.py
+++ b/python/tvm/relax/block_builder.py
@@ -153,6 +153,8 @@ class BlockBuilder(Object):
mod = bb.get()
"""
+ __slots__ = ("__dict__",)
+
_stack = []
@staticmethod
diff --git a/python/tvm/runtime/support.py b/python/tvm/runtime/support.py
index d40f5c2636..b0ac671763 100644
--- a/python/tvm/runtime/support.py
+++ b/python/tvm/runtime/support.py
@@ -149,6 +149,8 @@ def derived_object(cls: type[T]) -> type[T]:
class TVMDerivedObject(metadata["cls"]): # type: ignore
"""The derived object to avoid cyclic dependency."""
+ __slots__ = ("__dict__", "__weakref__",)
+
_cls = cls
_type = "TVMDerivedObject"
diff --git a/python/tvm/s_tir/meta_schedule/utils.py
b/python/tvm/s_tir/meta_schedule/utils.py
index b4cd2f4009..2460a6cc26 100644
--- a/python/tvm/s_tir/meta_schedule/utils.py
+++ b/python/tvm/s_tir/meta_schedule/utils.py
@@ -109,6 +109,8 @@ def derived_object(cls: type) -> type:
class TVMDerivedObject(metadata["cls"]): # type: ignore
"""The derived object to avoid cyclic dependency."""
+ __slots__ = ("__dict__", "__weakref__",)
+
_cls = cls
_type = "TVMDerivedObject"
diff --git a/python/tvm/tirx/build.py b/python/tvm/tirx/build.py
index d310afee79..020730d2f9 100644
--- a/python/tvm/tirx/build.py
+++ b/python/tvm/tirx/build.py
@@ -100,7 +100,7 @@ def split_host_device_mods(mod: IRModule) ->
tuple[IRModule, dict[Target, IRModu
def is_host_func(f):
target = f.attrs.get("target", tvm.target.Target("llvm"))
- return str(target.kind) in ["llvm", "c"]
+ return target.kind.name in ["llvm", "c"]
host_mod = tvm.tirx.transform.Filter(is_host_func)(mod)
device_mod = tvm.tirx.transform.Filter(lambda f: not is_host_func(f))(mod)
diff --git a/src/ir/expr.cc b/src/ir/expr.cc
index 4acb050734..f9d6e0fc60 100644
--- a/src/ir/expr.cc
+++ b/src/ir/expr.cc
@@ -225,6 +225,10 @@ 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) + "\")";
+ });
}
} // namespace tvm
diff --git a/src/node/repr_printer.cc b/src/node/repr_printer.cc
index b60583c6ab..142ad74eb5 100644
--- a/src/node/repr_printer.cc
+++ b/src/node/repr_printer.cc
@@ -22,11 +22,15 @@
* \file node/repr_printer.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 {
@@ -117,14 +121,66 @@ 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 << Downcast<ffi::reflection::AccessPath>(node);
+ p->stream <<
FormatAccessPath(Downcast<ffi::reflection::AccessPath>(node));
});
TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
.set_dispatch<ffi::reflection::AccessStepObj>([](const ObjectRef& node,
ReprPrinter* p) {
- p->stream << Downcast<ffi::reflection::AccessStep>(node);
+ std::ostringstream os;
+ FormatAccessStep(os, Downcast<ffi::reflection::AccessStep>(node));
+ p->stream << os.str();
});
TVM_FFI_STATIC_INIT_BLOCK() {
@@ -134,5 +190,19 @@ TVM_FFI_STATIC_INIT_BLOCK() {
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
diff --git a/src/relax/ir/emit_te.h b/src/relax/ir/emit_te.h
index d7c998729a..31b4cc2927 100644
--- a/src/relax/ir/emit_te.h
+++ b/src/relax/ir/emit_te.h
@@ -44,12 +44,7 @@ class RXPlaceholderOpNode : public te::PlaceholderOpNode {
static void RegisterReflection() {
namespace refl = tvm::ffi::reflection;
refl::ObjectDef<RXPlaceholderOpNode>()
- .def_ro("name", &RXPlaceholderOpNode::name)
- .def_ro("tag", &RXPlaceholderOpNode::tag)
- .def_ro("attrs", &RXPlaceholderOpNode::attrs)
- .def_ro("value", &RXPlaceholderOpNode::value)
- .def_ro("shape", &RXPlaceholderOpNode::shape)
- .def_ro("dtype", &RXPlaceholderOpNode::dtype);
+ .def_ro("value", &RXPlaceholderOpNode::value);
}
// FFI system configuration for structural equality and hashing
diff --git a/src/s_tir/schedule/instruction.cc
b/src/s_tir/schedule/instruction.cc
index 29fe3c2d88..ef635462ab 100644
--- a/src/s_tir/schedule/instruction.cc
+++ b/src/s_tir/schedule/instruction.cc
@@ -63,46 +63,49 @@ InstructionKindRegEntry&
InstructionKindRegEntry::RegisterOrGet(const ffi::Strin
/**************** Repr ****************/
+namespace {
+ffi::String InstructionAsPythonRepr(const InstructionNode* self) {
+ ffi::Array<Any> inputs;
+ inputs.reserve(self->inputs.size());
+ for (const Any& obj : self->inputs) {
+ if (obj == nullptr) {
+ inputs.push_back(ffi::String("None"));
+ } else if (auto opt_str = obj.as<ffi::String>()) {
+ inputs.push_back(ffi::String('"' + (*opt_str).operator std::string() +
'"'));
+ } else if (obj.as<SBlockRVNode>() || obj.as<LoopRVNode>()) {
+ inputs.push_back(ffi::String("_"));
+ } else if (obj.type_index() < ffi::TypeIndex::kTVMFFISmallStr) {
+ inputs.push_back(obj);
+ } 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> {
+ ObjectPtr<VarNode> new_var = ffi::make_object<VarNode>(*var.get());
+ new_var->name_hint = "_";
+ return Var(new_var);
+ });
+ std::ostringstream os;
+ os << new_expr;
+ inputs.push_back(ffi::String(os.str()));
+ } else if (obj.as<IndexMapNode>()) {
+ inputs.push_back(obj);
+ } else {
+ TVM_FFI_THROW(TypeError) << "Stringifying is not supported for type: "
<< obj.GetTypeKey();
+ throw;
+ }
+ }
+ return self->kind->f_as_python(
+ /*inputs=*/inputs,
+ /*attrs=*/self->attrs,
+ /*decision=*/Any(nullptr),
+ /*outputs=*/ffi::Array<ffi::String>(self->outputs.size(),
ffi::String("_")));
+}
+} // namespace
+
TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
.set_dispatch<InstructionNode>([](const ObjectRef& obj, ReprPrinter* p) {
- const auto* self = obj.as<InstructionNode>();
- TVM_FFI_ICHECK_NOTNULL(self);
- ffi::Array<Any> inputs;
- inputs.reserve(self->inputs.size());
- for (const Any& obj : self->inputs) {
- if (obj == nullptr) {
- inputs.push_back(ffi::String("None"));
- } else if (auto opt_str = obj.as<ffi::String>()) {
- inputs.push_back(ffi::String('"' + (*opt_str).operator std::string()
+ '"'));
- } else if (obj.as<SBlockRVNode>() || obj.as<LoopRVNode>()) {
- inputs.push_back(ffi::String("_"));
- } else if (obj.type_index() < ffi::TypeIndex::kTVMFFISmallStr) {
- inputs.push_back(obj);
- } 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> {
- ObjectPtr<VarNode> new_var =
ffi::make_object<VarNode>(*var.get());
- new_var->name_hint = "_";
- return Var(new_var);
- });
- std::ostringstream os;
- os << new_expr;
- inputs.push_back(ffi::String(os.str()));
- } else if (obj.as<IndexMapNode>()) {
- inputs.push_back(obj);
- } else {
- TVM_FFI_THROW(TypeError)
- << "Stringifying is not supported for type: " <<
obj.GetTypeKey();
- throw;
- }
- }
- p->stream << self->kind->f_as_python(
- /*inputs=*/inputs,
- /*attrs=*/self->attrs,
- /*decision=*/Any(nullptr),
- /*outputs=*/ffi::Array<ffi::String>(self->outputs.size(),
ffi::String("_")));
+ p->stream << InstructionAsPythonRepr(obj.as<InstructionNode>());
});
/**************** FFI ****************/
@@ -116,6 +119,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());
+ });
}
} // namespace s_tir
diff --git a/src/s_tir/schedule/trace.cc b/src/s_tir/schedule/trace.cc
index a63fb15f64..17b169b857 100644
--- a/src/s_tir/schedule/trace.cc
+++ b/src/s_tir/schedule/trace.cc
@@ -18,6 +18,8 @@
*/
#include <tvm/ffi/reflection/registry.h>
+#include <sstream>
+
#include "./utils.h"
namespace tvm {
@@ -522,25 +524,31 @@ Trace TraceNode::Simplified(bool remove_postproc) const {
/**************** Repr ****************/
+namespace {
+ffi::String TraceAsPythonRepr(const TraceNode* self) {
+ std::ostringstream os;
+ os << "# from tvm import s_tir\n";
+ os << "def apply_trace(sch: s_tir.Schedule) -> None:\n";
+ ffi::Array<ffi::String> repr = self->AsPython(/*remove_postproc=*/false);
+ bool is_first = true;
+ for (const ffi::String& line : repr) {
+ if (is_first) {
+ is_first = false;
+ } else {
+ os << '\n';
+ }
+ os << " " << std::string(line);
+ }
+ if (is_first) {
+ os << " pass";
+ }
+ return os.str();
+}
+} // namespace
+
TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
.set_dispatch<TraceNode>([](const ObjectRef& obj, ReprPrinter* p) {
- const auto* self = obj.as<TraceNode>();
- TVM_FFI_ICHECK_NOTNULL(self);
- p->stream << "# from tvm import s_tir\n";
- p->stream << "def apply_trace(sch: s_tir.Schedule) -> None:\n";
- ffi::Array<ffi::String> repr = self->AsPython(/*remove_postproc=*/false);
- bool is_first = true;
- for (const ffi::String& line : repr) {
- if (is_first) {
- is_first = false;
- } else {
- p->stream << '\n';
- }
- p->stream << " " << line;
- }
- if (is_first) {
- p->stream << " pass";
- }
+ p->stream << TraceAsPythonRepr(obj.as<TraceNode>());
p->stream << std::flush;
});
@@ -594,6 +602,10 @@ TVM_FFI_STATIC_INIT_BLOCK() {
.def_method("s_tir.schedule.TraceWithDecision", &TraceNode::WithDecision)
.def_method("s_tir.schedule.TraceSimplified", &TraceNode::Simplified)
.def("s_tir.schedule.TraceApplyJSONToSchedule",
Trace::ApplyJSONToSchedule);
+ // Register __ffi_repr__ so str(trace) returns the Python script format
+ refl::TypeAttrDef<TraceNode>().def(
+ refl::type_attr::kRepr,
+ [](Trace trace, ffi::Function) -> ffi::String { return
TraceAsPythonRepr(trace.get()); });
}
} // namespace s_tir
diff --git a/src/target/target.cc b/src/target/target.cc
index 4f1b4e3af2..2c093ee73f 100644
--- a/src/target/target.cc
+++ b/src/target/target.cc
@@ -479,7 +479,13 @@ TVM_FFI_STATIC_INIT_BLOCK() {
return (*it).second;
}
return Any();
- });
+ })
+ .def("target.TargetAsJSON",
+ [](const Target& target) -> ffi::String { return target->str(); });
+ // Register __ffi_repr__ so that ffi.ReprPrint uses JSON format for Target
+ refl::TypeAttrDef<TargetNode>().def(
+ refl::type_attr::kRepr,
+ [](Target target, ffi::Function) -> ffi::String { return target->str();
});
}
TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
diff --git a/src/tirx/ir/expr.cc b/src/tirx/ir/expr.cc
index 8b841e18dc..f4130e70d6 100644
--- a/src/tirx/ir/expr.cc
+++ b/src/tirx/ir/expr.cc
@@ -84,6 +84,15 @@ 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);
+ });
}
#define TVM_DEFINE_BINOP_CONSTRUCTOR(Name) \
diff --git a/tests/python/ir/test_pass_instrument.py
b/tests/python/ir/test_pass_instrument.py
index 5814cd59b9..aca226e4e4 100644
--- a/tests/python/ir/test_pass_instrument.py
+++ b/tests/python/ir/test_pass_instrument.py
@@ -42,7 +42,7 @@ def test_tir_print_all_passes(capsys):
all_passes_output = capsys.readouterr().out
assert "Before Running Pass:" in all_passes_output
assert "After Running Pass:" in all_passes_output
- assert "pass name: tirx." in all_passes_output
+ assert 'name="tirx.' in all_passes_output
def test_relax_print_all_passes(capsys):
@@ -60,4 +60,4 @@ def test_relax_print_all_passes(capsys):
all_passes_output = capsys.readouterr().out
assert "Before Running Pass:" in all_passes_output
assert "After Running Pass:" in all_passes_output
- assert "pass name: _pipeline" in all_passes_output
+ assert 'name="_pipeline"' in all_passes_output
diff --git a/tests/python/tvmscript/test_tvmscript_printer_doc.py
b/tests/python/tvmscript/test_tvmscript_printer_doc.py
index e3fe8a8745..8e9c7f0a74 100644
--- a/tests/python/tvmscript/test_tvmscript_printer_doc.py
+++ b/tests/python/tvmscript/test_tvmscript_printer_doc.py
@@ -539,8 +539,8 @@ def test_stmt_doc_comment():
comment = "test comment"
doc.comment = comment
# Make sure the previous statement doesn't set attribute
- # as if it's an ordinary Python object.
- assert "comment" not in doc.__dict__
+ # as if it's an ordinary Python object (__slots__ enforces this).
+ assert not hasattr(doc, "__dict__") or "comment" not in doc.__dict__
assert doc.comment == comment