23#ifndef TVM_IR_OBJECT_FUNCTOR_H_
24#define TVM_IR_OBJECT_FUNCTOR_H_
26#include <tvm/ffi/error.h>
27#include <tvm/ffi/extra/structural_mutate.h>
28#include <tvm/ffi/extra/structural_visit.h>
84template <
typename FType>
87template <
typename R,
typename NodeArg,
typename... Args>
89 static_assert(std::is_same_v<NodeArg, const ffi::ObjectRef&> ||
90 std::is_same_v<NodeArg, const ffi::Object*>,
91 "ObjectFunctor requires an ObjectRef reference or borrowed Object pointer");
102 template <
typename T>
104 uint32_t type_index = GetTypeIndex(n);
105 if (type_index < begin_type_index_)
return false;
106 type_index -= begin_type_index_;
107 return type_index < func_.size() && func_[type_index] !=
nullptr;
116 uint32_t type_index = n->type_index();
117 if (type_index >= begin_type_index_) {
118 uint32_t index = type_index - begin_type_index_;
119 if (index < func_.size() && func_[index] !=
nullptr) {
120 return (*func_[index])(n, std::forward<Args>(args)...);
124 const TVMFFITypeInfo* type_info = TVMFFIGetTypeInfo(type_index);
125 for (int32_t i = type_info->type_depth - 1; i >= 0; --i) {
126 type_index = type_info->type_ancestors[i]->type_index;
127 if (type_index >= begin_type_index_) {
128 uint32_t index = type_index - begin_type_index_;
129 if (index < func_.size() && func_[index] !=
nullptr) {
130 return (*func_[index])(n, std::forward<Args>(args)...);
134 ThrowUnregistered(n);
142 template <
typename TNode>
144 static_assert(std::is_base_of_v<ffi::Object, TNode>,
145 "ObjectFunctor dispatch requires an object node type");
146 uint32_t tindex = TNode::RuntimeTypeIndex();
147 if (func_.size() <= tindex) {
148 func_.resize(tindex + 1,
nullptr);
150 TVM_FFI_ICHECK(func_[tindex] ==
nullptr)
151 <<
"Dispatch for " << TNode::_type_key <<
" is already set";
152 TVM_FFI_ICHECK_EQ(begin_type_index_, 0) <<
" Cannot call SetDispatch after calling Finalize";
162 template <
typename TNode>
164 uint32_t tindex = TNode::RuntimeTypeIndex();
165 TVM_FFI_ICHECK_LT(tindex, func_.size()) <<
"ClearDispatch: index out of range";
166 TVM_FFI_ICHECK_EQ(begin_type_index_, 0) <<
" Cannot call ClearDispatch after calling Finalize";
167 func_[tindex] =
nullptr;
176 TVM_FFI_ICHECK_EQ(begin_type_index_, 0) <<
"Can only call Finalize once";
177 while (begin_type_index_ < func_.size() && func_[begin_type_index_] ==
nullptr) {
181 size_t new_ftable_size = func_.size() - begin_type_index_;
182 if (begin_type_index_ != 0) {
183 std::memmove(func_.data(), func_.data() + begin_type_index_,
184 new_ftable_size *
sizeof(FPointer));
186 func_.resize(new_ftable_size);
187 func_.shrink_to_fit();
193 TVM_FFI_INLINE
static uint32_t GetTypeIndex(NodeArg n) {
194 if constexpr (std::is_pointer_v<NodeArg>) {
195 return n !=
nullptr ? n->type_index() : ffi::TypeIndex::kTVMFFINone;
197 return n.defined() ? n->type_index() : ffi::TypeIndex::kTVMFFINone;
200 TVM_FFI_INLINE
static uint32_t GetTypeIndex(ffi::AnyView n) {
return n.type_index(); }
202 [[noreturn]] TVM_FFI_COLD_CODE
static void ThrowUnregistered(NodeArg n) {
203 TVM_FFI_THROW(InternalError) <<
"ObjectFunctor calls un-registered function on type "
205 TVM_FFI_UNREACHABLE();
209 using FPointer = R (*)(NodeArg n, Args...);
211 std::vector<FPointer> func_;
213 uint32_t begin_type_index_{0};
217using ffi::InplaceMode;
218using ffi::UnchangedOr;
219using ffi::VisitInterrupt;
242 virtual ffi::Optional<VisitInterrupt>
Visit(ffi::AnyView value) {
243 if (native_vtable_->CanDispatch(value)) {
245 ffi::details::AnyUnsafe::RawObjectPtrFromAnyViewAfterCheck<const ffi::Object>(value);
247 return (*native_vtable_)(object,
this);
248 }
catch (ffi::Error& error) {
249 ffi::details::UpdateVisitErrorContext(error, ffi::GetRef<ffi::ObjectRef>(
object));
253 return StructuralVisitDefault(value);
263 Expected<ffi::Optional<VisitInterrupt>>
VisitExpected(ffi::AnyView value)
noexcept {
266 }
catch (ffi::Error& error) {
267 return ffi::Unexpected(std::move(error));
268 }
catch (
const std::exception& error) {
269 return ffi::Unexpected(ffi::Error(
"InternalError", error.what(),
""));
282 : ffi::StructuralVisitorObj(StructuralVTable()), native_vtable_(vtable) {}
296 template <
typename Self,
typename Node>
298 vtable->template SetDispatch<Node>(DispatchNode<Self, Node>);
303 template <
typename Self,
typename Node>
304 static ffi::Optional<VisitInterrupt> DispatchNode(
const ffi::Object* node,
ObjectVisitor* self) {
305 return static_cast<Self*
>(self)->Visit_(
static_cast<const Node*
>(node));
308 ffi::Optional<VisitInterrupt> StructuralVisitDefault(ffi::AnyView value) {
311 return ffi::StructuralVisitorObj::DefaultVisitExpected(value).value();
312 }
catch (ffi::Error& error) {
313 ffi::details::UpdateVisitErrorContext(error, value);
317 static const VTable* GlobalVTable() {
318 static const VTable table = [] {
326 static const ffi::StructuralVisitorVTable* StructuralVTable() {
327 static const ffi::StructuralVisitorVTable table{StructuralVTableVisitImpl};
330 static TVMFFIAny StructuralVTableVisitImpl(ffi::StructuralVisitorObj* self,
331 ffi::AnyView value)
noexcept {
332 return ffi::details::ExpectedUnsafe::MoveToTVMFFIAny(
333 static_cast<ObjectVisitor*
>(self)->VisitExpected(value));
336 const VTable*
const native_vtable_;
380 virtual UnchangedOr<ffi::Any>
Mutate(ffi::AnyView value,
381 InplaceMode inplace_mode = InplaceMode::kDisallow) {
382 const auto*
object = value.as<ffi::Object>();
383 if (
object ==
nullptr)
return ffi::Any(value);
384 if (!object->unique()) inplace_mode = InplaceMode::kDisallow;
385 if (native_vtable_->CanDispatch(
object)) {
387 return (*native_vtable_)(object,
this, inplace_mode);
388 }
catch (ffi::Error& error) {
389 ffi::details::UpdateVisitErrorContext(error, ffi::GetRef<ffi::ObjectRef>(
object));
394 return ffi::StructuralMutatorObj::DefaultMutateExpected(value, inplace_mode).value();
406 ffi::AnyView value, InplaceMode inplace_mode = InplaceMode::kDisallow)
noexcept {
408 return Mutate(value, inplace_mode);
409 }
catch (ffi::Error& error) {
410 return ffi::Unexpected(std::move(error));
411 }
catch (
const std::exception& error) {
412 return ffi::Unexpected(ffi::Error(
"InternalError", error.what(),
""));
417 ffi::Any
VarRemapGet(ffi::AnyView var) {
return VarRemapGetExpected(var).value(); }
420 VarRemapSetExpected(var, value).value();
429 return VarRemapGetImpl(var);
438 ffi::AnyView mapped_value)
noexcept {
439 return VarRemapSetImpl(var, mapped_value);
452 : ffi::StructuralMapEngineBase(StructuralVTable()), native_vtable_(vtable) {}
466 template <
typename Self,
typename Node>
468 vtable->template SetDispatch<Node>(DispatchNode<Self, Node>);
473 template <
typename Self,
typename Node>
474 static UnchangedOr<ffi::Any> DispatchNode(
const ffi::Object* node,
ObjectMutator* self,
475 InplaceMode inplace_mode) {
476 return ffi::details::UnchangedOrUnsafe::MoveFromTVMFFIAny<ffi::Any>(
477 ffi::details::UnchangedOrUnsafe::MoveToTVMFFIAny(
478 static_cast<Self*
>(self)->Mutate_(
static_cast<const Node*
>(node), inplace_mode)));
481 using ffi::StructuralMutatorObj::DefaultMutateExpected;
483 static const VTable* GlobalVTable() {
484 static const VTable table = [] {
492 static const ffi::StructuralMutatorVTable* StructuralVTable() {
493 static const ffi::StructuralMutatorVTable table{
494 StructuralVTableMutateImpl, StructuralVTableMaybeInplaceMutateImpl,
495 StructuralVTableVarRemapGetImpl, StructuralVTableVarRemapSetImpl};
498 static TVMFFIAny StructuralVTableMutateImpl(ffi::StructuralMutatorObj* self,
499 ffi::AnyView value)
noexcept {
500 return ffi::details::ExpectedUnsafe::MoveToTVMFFIAny(
501 static_cast<ObjectMutator*
>(self)->MutateExpected(value, InplaceMode::kDisallow));
503 static TVMFFIAny StructuralVTableMaybeInplaceMutateImpl(ffi::StructuralMutatorObj* self,
504 ffi::AnyView value)
noexcept {
505 return ffi::details::ExpectedUnsafe::MoveToTVMFFIAny(
506 static_cast<ObjectMutator*
>(self)->MutateExpected(value, InplaceMode::kAllow));
508 static TVMFFIAny StructuralVTableVarRemapGetImpl(ffi::StructuralMutatorObj* self,
509 ffi::AnyView key)
noexcept {
510 return ffi::details::ExpectedUnsafe::MoveToTVMFFIAny(
511 static_cast<ObjectMutator*
>(self)->VarRemapGetImpl(key));
513 static TVMFFIAny StructuralVTableVarRemapSetImpl(ffi::StructuralMutatorObj* self,
514 ffi::AnyView key, ffi::AnyView value)
noexcept {
515 return ffi::details::ExpectedUnsafe::MoveToTVMFFIAny(
516 static_cast<ObjectMutator*
>(self)->VarRemapSetImpl(key, value));
519 const VTable*
const native_vtable_;
529#define TVM_DEFINE_OBJECT_FUNCTOR_DEFAULT_CONSTRUCTOR(Class, Parent) \
532 static const VTable table = [] { \
534 Class::InitVTable(&table); \
void Finalize()
Finalize the functor after calling sequence of SetDispatch This function will attempt to find the min...
Definition object_functor.h:175
ObjectFunctor & ClearDispatch()
unset the dispatcher for type TNode
Definition object_functor.h:163
TVM_FFI_INLINE bool CanDispatch(const T &n) const
Whether a dispatch function is registered for the exact runtime type.
Definition object_functor.h:103
ObjectFunctor & SetDispatch(R(*f)(NodeArg n, Args...))
set the dispatcher for type TNode
Definition object_functor.h:143
R result_type
the result type of this functor
Definition object_functor.h:95
TVM_FFI_INLINE R operator()(NodeArg n, Args... args) const
invoke the functor, dispatch on type of n
Definition object_functor.h:115
A dynamically dispatched functor on the type of the first argument.
Definition object_functor.h:85
Native mutation with exact dispatch and structural fallback.
Definition object_functor.h:346
ObjectMutator(const ObjectMutator &other)=delete
static void SetDispatch(VTable *vtable)
Register an exact node type in a fresh table initialized by its parent. Derived node types require se...
Definition object_functor.h:467
TVM_FFI_INLINE Expected< void > VarRemapSetExpected(ffi::AnyView var, ffi::AnyView mapped_value) noexcept
Record a replacement in the variable-remap environment.
Definition object_functor.h:437
TVM_FFI_INLINE Expected< ffi::Any > VarRemapGetExpected(ffi::AnyView var) noexcept
Look up a replacement in the variable-remap environment.
Definition object_functor.h:428
ObjectMutator()
Construct a mutator using structural fallback for every object.
Definition object_functor.h:349
ObjectMutator & operator=(const ObjectMutator &other)=delete
virtual UnchangedOr< ffi::Any > Mutate(ffi::AnyView value, InplaceMode inplace_mode=InplaceMode::kDisallow)
Mutate a borrowed value, throwing on failure.
Definition object_functor.h:380
ffi::Any VarRemapGet(ffi::AnyView var)
Look up a variable replacement, throwing on failure.
Definition object_functor.h:417
ObjectMutator(const VTable *vtable)
Construct a mutator with a finalized native dispatch table.
Definition object_functor.h:451
static void InitVTable(VTable *vtable)
Initialize the base registrations in a fresh mutable table.
Definition object_functor.h:457
Expected< UnchangedOr< ffi::Any > > MutateExpected(ffi::AnyView value, InplaceMode inplace_mode=InplaceMode::kDisallow) noexcept
Adapt the virtual throwing entrypoint to the structural ABI.
Definition object_functor.h:405
void VarRemapSet(ffi::AnyView var, ffi::AnyView value)
Record a variable replacement, throwing on failure.
Definition object_functor.h:419
Native visiting with exact dispatch and structural fallback.
Definition object_functor.h:228
ObjectVisitor(const ObjectVisitor &other)=delete
ObjectVisitor & operator=(const ObjectVisitor &other)=delete
static void InitVTable(VTable *vtable)
Initialize the base registrations in a fresh mutable table.
Definition object_functor.h:287
ObjectVisitor(const VTable *vtable)
Construct a visitor with a finalized native dispatch table.
Definition object_functor.h:281
static void SetDispatch(VTable *vtable)
Register an exact node type in a fresh table initialized by its parent. Derived node types require se...
Definition object_functor.h:297
virtual ffi::Optional< VisitInterrupt > Visit(ffi::AnyView value)
Visit a borrowed object or inline value, throwing on failure.
Definition object_functor.h:242
Expected< ffi::Optional< VisitInterrupt > > VisitExpected(ffi::AnyView value) noexcept
Adapt the virtual throwing entrypoint to the structural ABI.
Definition object_functor.h:263
ObjectVisitor()
Construct a visitor using structural fallback for every value.
Definition object_functor.h:231
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition attr.h:23
#define TVM_TIRX_DLL
Definition base.h:83