This is an automated email from the ASF dual-hosted git repository. tqchen pushed a commit to branch sequal in repository https://gitbox.apache.org/repos/asf/tvm.git
commit ae257030177eab86551fa36fb12cc7c73b4f3e3e Author: tqchen <[email protected]> AuthorDate: Thu Jul 17 10:30:00 2025 -0400 initial stab on access path --- ffi/CMakeLists.txt | 1 + ffi/include/tvm/ffi/c_api.h | 84 ++++++++++++++++++- ffi/include/tvm/ffi/reflection/access_path.h | 115 +++++++++++++++++++++++++++ ffi/include/tvm/ffi/reflection/registry.h | 6 +- ffi/src/ffi/container.cc | 3 +- ffi/src/ffi/reflection/access_path.cc | 37 +++++++++ ffi/tests/cpp/test_reflection.cc | 1 + 7 files changed, 243 insertions(+), 4 deletions(-) diff --git a/ffi/CMakeLists.txt b/ffi/CMakeLists.txt index 2aafacf5ac..78bb36ac5a 100644 --- a/ffi/CMakeLists.txt +++ b/ffi/CMakeLists.txt @@ -57,6 +57,7 @@ add_library(tvm_ffi_objs OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/dtype.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/testing.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/container.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/reflection/access_path.cc" ) set_target_properties( tvm_ffi_objs PROPERTIES diff --git a/ffi/include/tvm/ffi/c_api.h b/ffi/include/tvm/ffi/c_api.h index 545604a473..359d2191ac 100644 --- a/ffi/include/tvm/ffi/c_api.h +++ b/ffi/include/tvm/ffi/c_api.h @@ -326,12 +326,90 @@ typedef enum { kTVMFFIFieldFlagBitMaskHasDefault = 1 << 1, /*! \brief The field is a static method. */ kTVMFFIFieldFlagBitMaskIsStaticMethod = 1 << 2, + /*! + * \brief The field should be ignored when performing structural eq/hash + * + * This is an optional meta-data for structural eq/hash. + */ + kTVMFFIFieldFlagBitMaskStructuralEqHashIgnore = 1 << 3, + /*! + * \brief The field enters a def region where var can be defined/matched. + * + * This is an optional meta-data for structural eq/hash. + */ + kTVMFFIFieldFlagBitMaskStructuralEqHashDef = 1 << 4, #ifdef __cplusplus }; #else } TVMFFIFieldFlagBitMask; #endif +/*! + * \brief Optional meta-data for structural eq/hash. + * + * This meta-data is only useful when we want to leverage the information + * to perform richer semantics aware structural comparison and hash. + * It can be safely ignored if such information is not needed. + * + * The meta-data record comparison method in tree node and DAG node. + * + * \code + * x = VarNode() + * v0 = AddNode(x, 1) + * v1 = AddNode(x, 1) + * v2 = AddNode(v0, v0) + * v3 = AddNode(v1, v0) + * \endcode + * + * Consider the construct sequence of AddNode below, + * if AddNode is treated as a tree node, then v2 and v3 + * structural equals to each other, but if AddNode is + * treated as a DAG node, then v2 and v3 does not + * structural equals to each other. + */ +#ifdef __cplusplus +enum TVMFFIStructuralEqHashKind : int32_t { +#else +typedef enum { +#endif + /*! \brief Do not support structural eq/hash. */ + kTVMFFIStructuralEqHashKindUnsupported = 0, + /*! + * \brief The object be compared as a tree node. + */ + kTVMFFIStructuralEqHashKindTreeNode = 1, + /*! + * \brief The object is treated as a free variable that can be mapped + * to another free variable in the definition region. + */ + kTVMFFIStructuralEqHashKindFreeVar = 2, + /*! + * \brief The field should be compared as a DAG node. + */ + kTVMFFIStructuralEqHashKindDAGNode = 3, + /*! + * \brief The object is treated as a constant tree node. + * + * Same as tree node, but the object does not contain free var + * as any of its nested children. + * + * That means we can use pointer equality for equality. + */ + kTVMFFIStructuralEqHashKindConstTreeNode = 4, + /*! + * \brief One can simply use pointer equality for equality. + * + * This is useful for "singleton"-style object that can + * is only an unique copy of each value. + */ + kTVMFFIStructuralEqHashKindUniqueInstance = 5, +#ifdef __cplusplus +}; +#else +} TVMFFIStructuralEqHashKind; +#endif + + /*! * \brief Information support for optional object reflection. */ @@ -431,7 +509,11 @@ typedef struct { * * This field is set optional and set to 0 if not registered. */ - int64_t total_size; + int32_t total_size; + /*! + * \brief Optional meta-data for structural eq/hash. + */ + TVMFFIStructuralEqHashKind structural_eq_hash_kind; } TVMFFITypeExtraInfo; /*! diff --git a/ffi/include/tvm/ffi/reflection/access_path.h b/ffi/include/tvm/ffi/reflection/access_path.h new file mode 100644 index 0000000000..236b1ad99a --- /dev/null +++ b/ffi/include/tvm/ffi/reflection/access_path.h @@ -0,0 +1,115 @@ +/* + * 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 tvm/ffi/reflection/registry.h + * \brief Registry of reflection metadata. + */ +#ifndef TVM_FFI_REFLECTION_ACCESS_PATH_H_ +#define TVM_FFI_REFLECTION_ACCESS_PATH_H_ + +#include <tvm/ffi/c_api.h> +#include <tvm/ffi/any.h> +#include <tvm/ffi/container/array.h> +#include <tvm/ffi/reflection/registry.h> + +namespace tvm { +namespace ffi { +namespace reflection { + +/*! + * \brief Represent a single step in the object path. + */ +class AccessStepObj: public Object { + public: + enum class AccessKind : int32_t { + kObjectField = 0, + kArrayIndex = 1, + kMapValue = 2, + // the following two are used for error reporting when + // the supposed access field is not available + kArrayIndexMissing = 3, + kMapValueMissing = 4, + }; + /*! + * \brief The kind of the access pattern. + */ + AccessKind kind; + /*! + * \brief The access key + * \note for array access, it will always be integer + * for field access, it will be string + */ + Any key; + + AccessStepObj(AccessKind kind, Any key) + : kind(kind), key(key) {} + + static void RegisterReflection() { + namespace refl = tvm::ffi::reflection; + refl::ObjectDef<AccessStepObj>() + .def_ro("kind", &AccessStepObj::kind) + .def_ro("key", &AccessStepObj::key); + } + + static constexpr const char* _type_key = "tvm.ffi.reflection.AccessStep"; + TVM_FFI_DECLARE_FINAL_OBJECT_INFO(AccessStepObj, Object); +}; + +/*! + * \brief Managed NDArray. + * The array is backed by reference counted blocks. + * + * \note This class can be subclassed to implement downstream customized + * NDArray types that are backed by the same NDArrayObj storage type. + */ +class AccessStep : public ObjectRef { + public: + using AccessKind = AccessStepObj::AccessKind; + + AccessStep(AccessKind kind, Any key) + : ObjectRef(make_object<AccessStepObj>(kind, key)) {} + + static AccessStep ObjectField(String field_name) { + return AccessStep(AccessKind::kObjectField, field_name); + } + + static AccessStep ArrayIndex(int64_t index) { + return AccessStep(AccessKind::kArrayIndex, index); + } + + static AccessStep ArrayIndexMissing(int64_t index) { + return AccessStep(AccessKind::kArrayIndexMissing, index); + } + + static AccessStep MapValue(String key) { + return AccessStep(AccessKind::kMapValue, key); + } + + static AccessStep MapValueMissing(Any key) { + return AccessStep(AccessKind::kMapValueMissing, key); + } + + TVM_FFI_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS(AccessStep, ObjectRef, AccessStepObj); +}; + +using AccessPath = Array<AccessStep>; +} // namespace reflection +} // namespace ffi +} // namespace tvm +#endif // TVM_FFI_REFLECTION_OBJECT_PATH_H_ diff --git a/ffi/include/tvm/ffi/reflection/registry.h b/ffi/include/tvm/ffi/reflection/registry.h index 27e0b0877c..2df57f01eb 100644 --- a/ffi/include/tvm/ffi/reflection/registry.h +++ b/ffi/include/tvm/ffi/reflection/registry.h @@ -83,7 +83,11 @@ class ReflectionDefBase { template <typename T> static int FieldSetter(void* field, const TVMFFIAny* value) { TVM_FFI_SAFE_CALL_BEGIN(); - *reinterpret_cast<T*>(field) = AnyView::CopyFromTVMFFIAny(*value).cast<T>(); + if constexpr (std::is_same_v<T, Any>) { + *reinterpret_cast<T*>(field) = AnyView::CopyFromTVMFFIAny(*value); + } else { + *reinterpret_cast<T*>(field) = AnyView::CopyFromTVMFFIAny(*value).cast<T>(); + } TVM_FFI_SAFE_CALL_END(); } diff --git a/ffi/src/ffi/container.cc b/ffi/src/ffi/container.cc index 76b9cd6671..858cbd47c7 100644 --- a/ffi/src/ffi/container.cc +++ b/ffi/src/ffi/container.cc @@ -18,8 +18,7 @@ * under the License. */ /* - * \file src/ffi/ffi_api.cc - * \brief Extra ffi apis for frontend to access containers. + * \file src/ffi/container.cc */ #include <tvm/ffi/container/array.h> #include <tvm/ffi/container/map.h> diff --git a/ffi/src/ffi/reflection/access_path.cc b/ffi/src/ffi/reflection/access_path.cc new file mode 100644 index 0000000000..6e905d76cf --- /dev/null +++ b/ffi/src/ffi/reflection/access_path.cc @@ -0,0 +1,37 @@ + +/* + * 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 src/ffi/ffi_api.cc + * \brief Extra ffi apis for frontend to access containers. + */ + +#include <tvm/ffi/reflection/access_path.h> + +namespace tvm { +namespace ffi { +namespace reflection { + +TVM_FFI_STATIC_INIT_BLOCK({ + AccessStepObj::RegisterReflection(); +}); + +} // namespace reflection +} // namespace ffi +} // namespace tvm diff --git a/ffi/tests/cpp/test_reflection.cc b/ffi/tests/cpp/test_reflection.cc index 3f6b5def01..fd01365043 100644 --- a/ffi/tests/cpp/test_reflection.cc +++ b/ffi/tests/cpp/test_reflection.cc @@ -23,6 +23,7 @@ #include <tvm/ffi/reflection/accessor.h> #include <tvm/ffi/reflection/registry.h> #include <tvm/ffi/string.h> +#include <tvm/ffi/reflection/access_path.h> #include "./testing_object.h"
