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"
 

Reply via email to