28#ifndef TVM_RELAX_NESTED_MSG_H_
29#define TVM_RELAX_NESTED_MSG_H_
31#include <tvm/ffi/container/array.h>
32#include <tvm/ffi/optional.h>
140 data_ = std::move(
other);
148 data_ = std::move(
other);
165 bool operator==(std::nullptr_t)
const {
return data_ ==
nullptr; }
166 bool operator!=(std::nullptr_t)
const {
return data_ !=
nullptr; }
170 return data_.type_index() != ffi::TypeIndex::kTVMFFINone &&
171 data_.type_index() != ffi::TypeIndex::kTVMFFIArray;
175 bool IsNull()
const {
return data_.type_index() == ffi::TypeIndex::kTVMFFINone; }
178 bool IsNested()
const {
return data_.type_index() == ffi::TypeIndex::kTVMFFIArray; }
186 return ffi::details::AnyUnsafe::CopyFromAnyViewAfterCheck<T>(data_);
194 return ffi::details::AnyUnsafe::CopyFromAnyViewAfterCheck<ffi::Array<NestedMsg<T>,
void>>(
201 explicit NestedMsg(ffi::Any data) : data_(data) {}
202 template <
typename,
typename>
213template <
typename T,
typename FType>
215 if (msg ==
nullptr)
return;
234template <
typename T,
typename FType>
236 if (lhs.IsNull())
return rhs.IsNull();
237 if (rhs.IsNull())
return lhs.IsNull();
239 return rhs.IsLeaf() &&
fequal(lhs.LeafValue(), rhs.LeafValue());
241 if (!rhs.IsNested())
return false;
242 ffi::Array<NestedMsg<T>>
arr_lhs = lhs.NestedArray();
243 ffi::Array<NestedMsg<T>>
arr_rhs = rhs.NestedArray();
265template <
typename T,
typename FType>
267 if (
auto* tuple = expr.as<
TupleNode>()) {
268 ffi::Array<NestedMsg<T>>
res;
269 res.reserve(tuple->fields.size());
270 for (
Expr x : tuple->fields) {
292template <
typename T,
typename FType>
295 ffi::Array<NestedMsg<T>>
res;
296 res.reserve(tuple->fields.size());
297 for (
Type x : tuple->fields) {
320template <
typename T,
typename FType>
324 ffi::Array<NestedMsg<T>>
res;
325 res.reserve(tuple->fields.size());
326 for (
size_t i = 0;
i < tuple->fields.size(); ++
i) {
358template <
typename TargetType,
typename T,
typename FMapLeaf,
typename FCombine>
362 }
else if (msg.IsLeaf()) {
366 ffi::Array<NestedMsg<T>>
arr = msg.NestedArray();
367 ffi::Array<TargetType>
subexpr;
369 for (
size_t i = 0;
i <
arr.size(); ++
i) {
388template <
typename T,
typename FType>
393 if (
arr.size() >= 1) {
394 simplified_flag = true;
395 for (size_t i = 0; i < arr.size() && simplified_flag; ++i) {
396 auto* node = arr[i].as<TupleGetItemNode>();
397 if (node == nullptr || node->index != static_cast<int>(i)) {
398 simplified_flag = false;
400 if (simplified_tuple.has_value()) {
401 simplified_flag &= simplified_tuple.value().same_as(node->tuple);
403 simplified_tuple = node->tuple;
404 TVM_FFI_ICHECK(simplified_tuple.has_value());
429template <
typename T,
typename FType>
431 if (lhs.IsNull())
return rhs;
432 if (rhs.IsNull())
return lhs;
435 TVM_FFI_ICHECK(rhs.IsLeaf()) <<
"Cannot combine leaf with nested";
439 TVM_FFI_ICHECK(rhs.IsNested()) <<
"Cannot combine leaf with nested";
440 ffi::Array<NestedMsg<T>>
arr_lhs = lhs.NestedArray();
441 ffi::Array<NestedMsg<T>>
arr_rhs = rhs.NestedArray();
443 <<
"Cannot combine two nested array with different sizes";
444 ffi::Array<NestedMsg<T>>
res;
461template <
typename T,
typename FType>
465 }
else if (msg.IsLeaf()) {
469 ffi::Array<NestedMsg<T>>
arr = msg.NestedArray();
470 ffi::Array<NestedMsg<T>>
res;
492template <
typename T,
typename FType>
494 if (
auto* tuple = expr.as<
TupleNode>()) {
495 TVM_FFI_ICHECK(msg.IsNested()) <<
"Expected nested to match tuple";
496 ffi::Array<NestedMsg<T>>
arr = msg.NestedArray();
498 <<
"Expected nested array size to match tuple size";
499 for (
size_t i = 0;
i <
arr.size(); ++
i) {
521template <
typename T, std::
size_t N,
typename FType>
525 std::array<ffi::Array<NestedMsg<T>>,
N>
msg_arrays;
526 for (
size_t i = 0;
i <
N; ++
i) {
531 ffi::Array<Expr> fields;
532 fields.reserve(tuple->fields.size());
533 for (
size_t i = 0;
i < tuple->fields.size(); ++
i) {
541 for (
size_t j = 0;
j <
N; ++
j) {
549 for (
const auto& msg :
msgs) {
550 TVM_FFI_ICHECK(msg.IsLeaf()) <<
"Expected leaf to match non-tuple";
570template <
typename T, std::
size_t N,
typename FType>
573 std::array<ffi::Array<NestedMsg<T>>,
N>
msg_arrays;
574 for (
size_t i = 0;
i <
N; ++
i) {
579 ffi::Array<Type> fields;
580 fields.reserve(tuple->fields.size());
581 for (
size_t i = 0;
i < tuple->fields.size(); ++
i) {
584 for (
size_t j = 0;
j <
N; ++
j) {
592 for (
const auto& msg :
msgs) {
593 TVM_FFI_ICHECK(msg.IsLeaf()) <<
"Expected leaf to match non-tuple";
604inline constexpr bool use_default_type_traits_v<relax::NestedMsg<T>> =
false;
607struct TypeTraits<relax::NestedMsg<T>> :
public TypeTraitsBase {
608 TVM_FFI_INLINE
static void CopyToAnyView(
const relax::NestedMsg<T>& src, TVMFFIAny* result) {
609 *result = ffi::AnyView(src.data_).CopyToTVMFFIAny();
612 TVM_FFI_INLINE
static void MoveToAny(relax::NestedMsg<T> src, TVMFFIAny* result) {
613 *result = details::AnyUnsafe::MoveAnyToTVMFFIAny(std::move(src.data_));
616 TVM_FFI_INLINE
static std::string GetMismatchTypeInfo(
const TVMFFIAny* src) {
617 return TypeTraitsBase::GetMismatchTypeInfo(src);
620 static bool CheckAnyStrict(
const TVMFFIAny* src) {
621 if (src->type_index == TypeIndex::kTVMFFINone) {
624 if (TypeTraits<T>::CheckAnyStrict(src)) {
627 if (src->type_index == TypeIndex::kTVMFFIArray) {
628 const ffi::ArrayObj* array =
reinterpret_cast<const ffi::ArrayObj*
>(src->v_obj);
629 for (
size_t i = 0; i < array->size(); ++i) {
630 const Any& any_v = (*array)[i];
631 if (!details::AnyUnsafe::CheckAnyStrict<relax::NestedMsg<T>>(any_v))
return false;
637 TVM_FFI_INLINE
static relax::NestedMsg<T> CopyFromAnyViewAfterCheck(
const TVMFFIAny* src) {
638 return relax::NestedMsg<T>(Any(AnyView::CopyFromTVMFFIAny(*src)));
641 TVM_FFI_INLINE
static relax::NestedMsg<T> MoveFromAnyAfterCheck(TVMFFIAny* src) {
642 return relax::NestedMsg<T>(details::AnyUnsafe::MoveTVMFFIAnyToAny(src));
645 static std::optional<relax::NestedMsg<T>> TryCastFromAnyView(
const TVMFFIAny* src) {
646 if (CheckAnyStrict(src)) {
647 return CopyFromAnyViewAfterCheck(src);
650 if (src->type_index == TypeIndex::kTVMFFINone) {
651 return relax::NestedMsg<T>(std::nullopt);
653 if (
auto opt_value = TypeTraits<T>::TryCastFromAnyView(src)) {
654 return relax::NestedMsg<T>(*std::move(opt_value));
656 if (src->type_index == TypeIndex::kTVMFFIArray) {
657 const ArrayObj* n =
reinterpret_cast<const ArrayObj*
>(src->v_obj);
658 ffi::Array<relax::NestedMsg<T>> result;
659 result.reserve(n->size());
660 for (
size_t i = 0; i < n->size(); i++) {
661 const Any& any_v = (*n)[i];
662 if (
auto opt_v = any_v.try_cast<relax::NestedMsg<T>>()) {
663 result.push_back(*std::move(opt_v));
668 return relax::NestedMsg<T>(result);
673 TVM_FFI_INLINE
static std::string TypeStr() {
674 return "NestedMsg<" + details::Type2Str<T>::v() +
">";
677 TVM_FFI_INLINE
static std::string TypeSchema() {
678 std::ostringstream oss;
679 oss << R
"({"type":"NestedMsg","args":[)";
680 oss << details::TypeSchema<T>::v();
Managed reference to ExprNode.
Definition base_expr.h:335
Managed reference to TupleGetItemNode.
Definition expr.h:94
Tuple container.
Definition expr.h:48
The type of tuple values.
Definition type.h:90
Managed reference to TupleTypeNode.
Definition type.h:108
Managed reference to TupleNode.
Definition expr.h:62
Managed reference to TypeNode.
Definition base_expr.h:77
RAII wrapper function to enter and exit a context object similar to python's with syntax.
Definition with_context.h:59
Container that stores possibly nested message with leaf message type T.
Definition nested_msg.h:119
NestedMsg< T > & operator=(ffi::Array< NestedMsg< T >, void > other)
Definition nested_msg.h:147
NestedMsg(T other)
Definition nested_msg.h:137
friend struct ffi::TypeTraits
Definition nested_msg.h:203
NestedMsg(std::nullptr_t)
Definition nested_msg.h:131
NestedMsg(std::initializer_list< NestedMsg< T > > other)
Definition nested_msg.h:153
NestedMsg(const NestedMsg< T > &)=default
ffi::Array< NestedMsg< T >, void > NestedArray() const
Definition nested_msg.h:193
NestedMsg< T > & operator=(const NestedMsg< T > &)=default
NestedMsg(ffi::Array< NestedMsg< T >, void > other)
Definition nested_msg.h:144
NestedMsg< T > & operator=(int val)=delete
T LeafValue() const
Definition nested_msg.h:184
NestedMsg(int val)=delete
NestedMsg< T > & operator=(std::initializer_list< NestedMsg< T > > other)
Definition nested_msg.h:155
bool IsNull() const
Definition nested_msg.h:175
NestedMsg< T > & operator=(NestedMsg< T > &&)=default
bool IsNested() const
Definition nested_msg.h:178
bool operator==(std::nullptr_t) const
Definition nested_msg.h:165
NestedMsg< T > & operator=(T other)
Definition nested_msg.h:139
NestedMsg(NestedMsg< T > &&)=default
NestedMsg< T > & operator=(std::nullptr_t)
Definition nested_msg.h:132
NestedMsg(std::nullopt_t)
Nullopt handling.
Definition nested_msg.h:128
bool IsLeaf() const
Definition nested_msg.h:169
bool operator!=(std::nullptr_t) const
Definition nested_msg.h:166
NestedMsg< T > CombineNestedMsg(NestedMsg< T > lhs, NestedMsg< T > rhs, FType fcombine)
Recursively combine two nested message into one.
Definition nested_msg.h:430
NestedMsg< T > MapNestedMsg(NestedMsg< T > msg, FType fmapleaf)
Recursively map a nested message to another one, with leaf mapped by the input fmapleaf.
Definition nested_msg.h:462
Expr TransformTupleLeaf(Expr expr, std::array< NestedMsg< T >, N > msgs, FType ftransleaf)
Recursively transform the tuple structure in expr and msgs along with it.
Definition nested_msg.h:522
TargetType NestedMsgTo(NestedMsg< T > msg, FMapLeaf fmapleaf, FCombine fcombine)
Map nested message back to TargetType.
Definition nested_msg.h:359
Type GetType(const Expr &expr)
Get the underlying Relax type of expr.
Definition type.h:400
NestedMsg< T > MapToNestedMsgByType(Expr expr, FType fmapleaf)
Map expr with possible nested-tuple to nested message.
Definition nested_msg.h:321
NestedMsg< T > MapToNestedMsg(Expr expr, FType fmapleaf)
Map expr with possible nested-tuple to nested message.
Definition nested_msg.h:266
void ForEachLeaf(const NestedMsg< T > &msg, FType fvisit)
Apply fvisit for each leaf elements in the nested message.
Definition nested_msg.h:214
void DecomposeNestedMsg(Expr expr, NestedMsg< T > msg, FType fvisitleaf)
Recursively decompose the tuple structure in expr and msg along with it.
Definition nested_msg.h:493
Expr NestedMsgToExpr(NestedMsg< T > msg, FType fmapleaf)
Map nested message back to the expr.
Definition nested_msg.h:389
bool Equal(const NestedMsg< T > &lhs, const NestedMsg< T > &rhs, FType fequal)
Recursively compare two nested messages.
Definition nested_msg.h:235
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition analyzer.h:40
Type GetType(const PrimExpr &expr)
Get the type of the expression under the unified type system.
Relax types, including the richer dependent Relax type nodes.