gemini-code-assist[bot] commented on code in PR #402: URL: https://github.com/apache/tvm-ffi/pull/402#discussion_r2680813868
########## examples/abi_overview/example_code.c: ########## @@ -0,0 +1,185 @@ +/* + * 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. + */ + +// NOLINTBEGIN(modernize-deprecated-headers,modernize-use-nullptr) +#include <assert.h> +#include <dlpack/dlpack.h> +#include <tvm/ffi/c_api.h> + +int IS_OWNING_ANY = 1; + +// [Any_AnyView.FromInt_Float.begin] +TVMFFIAny Any_AnyView_FromInt(int64_t value) { + TVMFFIAny any; + any.type_index = kTVMFFIInt; + any.zero_padding = 0; + any.v_int64 = value; + return any; +} + +TVMFFIAny Any_AnyView_FromFloat(double value) { + TVMFFIAny any; + any.type_index = kTVMFFIFloat; + any.zero_padding = 0; + any.v_float64 = value; + return any; +} +// [Any_AnyView.FromInt_Float.end] + +// [Any_AnyView.FromObjectPtr.begin] +TVMFFIAny Any_AnyView_FromObjectPtr(TVMFFIObject* obj) { + TVMFFIAny any; + assert(obj != NULL); + any.type_index = kTVMFFIObject; + any.zero_padding = 0; + any.v_obj = obj; + // Increment refcount if it's Any (owning) instead of AnyView (borrowing) + if (IS_OWNING_ANY) { + TVMFFIObjectIncRef(obj); + } + return any; +} +// [Any_AnyView.FromObjectPtr.end] + +// [Any_AnyView.Destroy.begin] +void Any_AnyView_Destroy(TVMFFIAny* any) { + if (IS_OWNING_ANY) { + // Checks if `any` holds a heap-allocated object, + // and if so, decrements the reference count + if (any->type_index >= kTVMFFIStaticObjectBegin) { + TVMFFIObjectDecRef(any->v_obj); + } + } + *any = (TVMFFIAny){0}; // Clears the `any` struct +} +// [Any_AnyView.Destroy.end] + +// [Any_AnyView.GetInt_Float.begin] +int64_t Any_AnyView_GetInt(const TVMFFIAny* any) { + if (any->type_index == kTVMFFIInt || any->type_index == kTVMFFIBool) { + return any->v_int64; + } else if (any->type_index == kTVMFFIFloat) { + return (int64_t)(any->v_float64); + } + assert(0); // FAILED to read int + return 0; +} + +double Any_AnyView_GetFloat(const TVMFFIAny* any) { + if (any->type_index == kTVMFFIInt || any->type_index == kTVMFFIFloat) { + return (double)(any->v_int64); + } else if (any->type_index == kTVMFFIFloat) { + return any->v_float64; + } Review Comment:  There's a bug in this function's logic. If `any->type_index` is `kTVMFFIFloat`, the first `if` condition becomes true, and it incorrectly tries to return `(double)(any->v_int64)`. The `v_int64` field is not valid for a float value. The `else if` block that correctly handles floats is therefore unreachable. To fix this, the first `if` condition should not check for `kTVMFFIFloat`. ```suggestion if (any->type_index == kTVMFFIInt || any->type_index == kTVMFFIBool) { return (double)(any->v_int64); } else if (any->type_index == kTVMFFIFloat) { return any->v_float64; } ``` ########## docs/concepts/abi_overview.rst: ########## @@ -0,0 +1,466 @@ +.. 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. + +ABI Overview +============ + +.. hint:: + + Authoritative ABI specifications are defined in + + - C header `tvm/ffi/c_api.h <https://github.com/apache/tvm-ffi/blob/main/include/tvm/ffi/c_api.h>`_, which contains the core ABI, and + - C header `tvm/ffi/extra/c_env_api.h <https://github.com/apache/tvm-ffi/blob/main/include/tvm/ffi/extra/c_env_api.h>`_, which contains extra support features. + +Overall, TVM-FFI ABI is designed is around the following key principles: Review Comment:  There's a small grammatical error here. It says 'is designed is', which should be 'is designed'. ```suggestion Overall, TVM-FFI ABI is designed around the following key principles: ``` ########## docs/concepts/abi_overview.rst: ########## @@ -0,0 +1,466 @@ +.. 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. + +ABI Overview +============ + +.. hint:: + + Authoritative ABI specifications are defined in + + - C header `tvm/ffi/c_api.h <https://github.com/apache/tvm-ffi/blob/main/include/tvm/ffi/c_api.h>`_, which contains the core ABI, and + - C header `tvm/ffi/extra/c_env_api.h <https://github.com/apache/tvm-ffi/blob/main/include/tvm/ffi/extra/c_env_api.h>`_, which contains extra support features. + +Overall, TVM-FFI ABI is designed is around the following key principles: + +- **Minimal and efficient**. Keep things simple when possible and bring close-to-metal efficiency. +- **Stability guarantee**. The ABI is stable across compiler versions and independent of host languages or frameworks. +- **Expressive for machine learning** TBA. +- **Extensible**. The ABI is extensible to support new types and features. + +This tutorial covers common concepts and usage patterns with TVM-FFI's ABI with low-level C code for precise reference. + +Any and AnyView +--------------- + +.. seealso:: + + :doc:`any` for :cpp:class:`~tvm::ffi::Any` and :cpp:class:`~tvm::ffi::AnyView` usage patterns. + +At the core of TVM-FFI is :cpp:class:`TVMFFIAny`, a 16-byte tagged union that can hold any value +recognized by the FFI system. It enables type-erased value passing across language boundaries. + +.. dropdown:: C ABI Reference: :cpp:class:`TVMFFIAny` + :icon: code + + .. literalinclude:: ../../include/tvm/ffi/c_api.h + :language: c + :start-after: [TVMFFIAny.begin] + :end-before: [TVMFFIAny.end] + :caption: tvm/ffi/c_api.h + +**Ownership**. :cpp:class:`TVMFFIAny` has two variants with exact same layout but different :ref:`ownership semantics <any-ownership>`: + +- Managed owning :cpp:class:`tvm::ffi::Any` +- Unmanaged borrowing :cpp:class:`tvm::ffi::AnyView` + +.. note:: + To switch a borrowing :cpp:class:`~tvm::ffi::AnyView` to an owning :cpp:class:`~tvm::ffi::Any`, use :cpp:func:`TVMFFIAnyViewToOwnedAny`. + +**Runtime Type Index**. The ``type_index`` field identifies what kind of value is stored. + +- :ref:`Atomic POD types <any-atomic-types>`, where ``type_index`` < :cpp:enumerator:`kTVMFFIStaticObjectBegin <TVMFFITypeIndex::kTVMFFIStaticObjectBegin>`. + They are stored in-place in payload union, without heap allocation or reference counting. +- :ref:`Object types <any-heap-allocated-objects>`, where ``type_index`` >= :cpp:enumerator:`kTVMFFIStaticObjectBegin <TVMFFITypeIndex::kTVMFFIStaticObjectBegin>`. + They are stored in a heap-allocated, reference-counted TVM-FFI object. + +.. important:: + Type index system in TVM-FFI does not rely on C++ features such as RTTI. + + +Construct Any +~~~~~~~~~~~~~ + +**Constructing from atomic POD types**. The C code below constructs an :cpp:class:`TVMFFIAny` from an integer: + + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.FromInt_Float.begin] + :end-before: [Any_AnyView.FromInt_Float.end] + +Essentially, properly assign ``type_index`` from :cpp:enum:`TVMFFITypeIndex`, and then set the payload field accordingly. + +.. important:: + + Always zero the ``zero_padding`` field and any unused bytes in the value union. + This invariant enables direct byte comparison and hashing of :cpp:class:`TVMFFIAny` values. + +**Construct from object types**. The C code below constructs an :cpp:class:`TVMFFIAny` from a heap-allocated object: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.FromObjectPtr.begin] + :end-before: [Any_AnyView.FromObjectPtr.end] + +For an owning :cpp:class:`~tvm::ffi::Any` where ``IS_OWNING_ANY`` is ``true``, it increments the reference count of the heap-allocated object. + +Destruct Any +~~~~~~~~~~~~ + +The C code below destroys an :cpp:class:`TVMFFIAny`: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.Destroy.begin] + :end-before: [Any_AnyView.Destroy.end] + +For an owning :cpp:class:`~tvm::ffi::Any` where ``IS_OWNING_ANY`` is ``true``, it decrements the reference count of the heap-allocated object. + +Extract from Any +~~~~~~~~~~~~~~~~ + +**Extract an atomic POD**. The C code below extracts an integer or float from an :cpp:class:`TVMFFIAny`: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.GetInt_Float.begin] + :end-before: [Any_AnyView.GetInt_Float.end] + +It is possible that casting may happen, for example, in the code above, when trying to get a float and +:cpp:class:`TVMFFIAny` has an integer value, the integer is casted to a float. Review Comment:  The word 'casted' is grammatically incorrect; the past participle of 'cast' is 'cast'. Also, the sentence could be rephrased for better clarity. ```suggestion It is possible that casting may happen. For example, in the code above, when trying to get a float from a :cpp:class:`TVMFFIAny` that holds an integer value, the integer is cast to a float. ``` ########## docs/concepts/abi_overview.rst: ########## @@ -0,0 +1,466 @@ +.. 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. + +ABI Overview +============ + +.. hint:: + + Authoritative ABI specifications are defined in + + - C header `tvm/ffi/c_api.h <https://github.com/apache/tvm-ffi/blob/main/include/tvm/ffi/c_api.h>`_, which contains the core ABI, and + - C header `tvm/ffi/extra/c_env_api.h <https://github.com/apache/tvm-ffi/blob/main/include/tvm/ffi/extra/c_env_api.h>`_, which contains extra support features. + +Overall, TVM-FFI ABI is designed is around the following key principles: + +- **Minimal and efficient**. Keep things simple when possible and bring close-to-metal efficiency. +- **Stability guarantee**. The ABI is stable across compiler versions and independent of host languages or frameworks. +- **Expressive for machine learning** TBA. Review Comment:  This line contains a 'TBA' (To Be Added) placeholder. It's best to either fill this in with the relevant information or remove the line to avoid shipping incomplete documentation. ########## docs/concepts/abi_overview.rst: ########## @@ -0,0 +1,466 @@ +.. 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. + +ABI Overview +============ + +.. hint:: + + Authoritative ABI specifications are defined in + + - C header `tvm/ffi/c_api.h <https://github.com/apache/tvm-ffi/blob/main/include/tvm/ffi/c_api.h>`_, which contains the core ABI, and + - C header `tvm/ffi/extra/c_env_api.h <https://github.com/apache/tvm-ffi/blob/main/include/tvm/ffi/extra/c_env_api.h>`_, which contains extra support features. + +Overall, TVM-FFI ABI is designed is around the following key principles: + +- **Minimal and efficient**. Keep things simple when possible and bring close-to-metal efficiency. +- **Stability guarantee**. The ABI is stable across compiler versions and independent of host languages or frameworks. +- **Expressive for machine learning** TBA. +- **Extensible**. The ABI is extensible to support new types and features. + +This tutorial covers common concepts and usage patterns with TVM-FFI's ABI with low-level C code for precise reference. + +Any and AnyView +--------------- + +.. seealso:: + + :doc:`any` for :cpp:class:`~tvm::ffi::Any` and :cpp:class:`~tvm::ffi::AnyView` usage patterns. + +At the core of TVM-FFI is :cpp:class:`TVMFFIAny`, a 16-byte tagged union that can hold any value +recognized by the FFI system. It enables type-erased value passing across language boundaries. + +.. dropdown:: C ABI Reference: :cpp:class:`TVMFFIAny` + :icon: code + + .. literalinclude:: ../../include/tvm/ffi/c_api.h + :language: c + :start-after: [TVMFFIAny.begin] + :end-before: [TVMFFIAny.end] + :caption: tvm/ffi/c_api.h + +**Ownership**. :cpp:class:`TVMFFIAny` has two variants with exact same layout but different :ref:`ownership semantics <any-ownership>`: + +- Managed owning :cpp:class:`tvm::ffi::Any` +- Unmanaged borrowing :cpp:class:`tvm::ffi::AnyView` + +.. note:: + To switch a borrowing :cpp:class:`~tvm::ffi::AnyView` to an owning :cpp:class:`~tvm::ffi::Any`, use :cpp:func:`TVMFFIAnyViewToOwnedAny`. + +**Runtime Type Index**. The ``type_index`` field identifies what kind of value is stored. + +- :ref:`Atomic POD types <any-atomic-types>`, where ``type_index`` < :cpp:enumerator:`kTVMFFIStaticObjectBegin <TVMFFITypeIndex::kTVMFFIStaticObjectBegin>`. + They are stored in-place in payload union, without heap allocation or reference counting. +- :ref:`Object types <any-heap-allocated-objects>`, where ``type_index`` >= :cpp:enumerator:`kTVMFFIStaticObjectBegin <TVMFFITypeIndex::kTVMFFIStaticObjectBegin>`. + They are stored in a heap-allocated, reference-counted TVM-FFI object. + +.. important:: + Type index system in TVM-FFI does not rely on C++ features such as RTTI. + + +Construct Any +~~~~~~~~~~~~~ + +**Constructing from atomic POD types**. The C code below constructs an :cpp:class:`TVMFFIAny` from an integer: + + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.FromInt_Float.begin] + :end-before: [Any_AnyView.FromInt_Float.end] + +Essentially, properly assign ``type_index`` from :cpp:enum:`TVMFFITypeIndex`, and then set the payload field accordingly. + +.. important:: + + Always zero the ``zero_padding`` field and any unused bytes in the value union. + This invariant enables direct byte comparison and hashing of :cpp:class:`TVMFFIAny` values. + +**Construct from object types**. The C code below constructs an :cpp:class:`TVMFFIAny` from a heap-allocated object: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.FromObjectPtr.begin] + :end-before: [Any_AnyView.FromObjectPtr.end] + +For an owning :cpp:class:`~tvm::ffi::Any` where ``IS_OWNING_ANY`` is ``true``, it increments the reference count of the heap-allocated object. + +Destruct Any +~~~~~~~~~~~~ + +The C code below destroys an :cpp:class:`TVMFFIAny`: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.Destroy.begin] + :end-before: [Any_AnyView.Destroy.end] + +For an owning :cpp:class:`~tvm::ffi::Any` where ``IS_OWNING_ANY`` is ``true``, it decrements the reference count of the heap-allocated object. + +Extract from Any +~~~~~~~~~~~~~~~~ + +**Extract an atomic POD**. The C code below extracts an integer or float from an :cpp:class:`TVMFFIAny`: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.GetInt_Float.begin] + :end-before: [Any_AnyView.GetInt_Float.end] + +It is possible that casting may happen, for example, in the code above, when trying to get a float and +:cpp:class:`TVMFFIAny` has an integer value, the integer is casted to a float. + +**Extract a DLTensor**. A DLTensor may come from either a raw pointer or a heap-allocated object :cpp:class:`tvm::ffi::TensorObj`. + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.GetDLTensor.begin] + :end-before: [Any_AnyView.GetDLTensor.end] + +**Extract a TVM-FFI object**. A TVM-FFI object is always heap-allocated, reference-counted, and +its ``type_index`` >= :cpp:enumerator:`kTVMFFIStaticObjectBegin <TVMFFITypeIndex::kTVMFFIStaticObjectBegin>`. + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Any_AnyView.GetObject.begin] + :end-before: [Any_AnyView.GetObject.end] + +Note that if the caller owns the return value, it should increment the reference count via :cpp:func:`TVMFFIObjectIncRef`, +and release the ownership via :cpp:func:`TVMFFIObjectDecRef`. + +Object +------ + +.. seealso:: + + :doc:`object_and_class` for the object system and reflection. + +TVM-FFI Object (:cpp:class:`TVMFFIObject`) is the cornerstone of TVM-FFI's stable yet extensible type system. + +.. dropdown:: C ABI Reference: :cpp:class:`TVMFFIObject` + :icon: code + + .. literalinclude:: ../../include/tvm/ffi/c_api.h + :language: c + :start-after: [TVMFFIObject.begin] + :end-before: [TVMFFIObject.end] + :caption: tvm/ffi/c_api.h + +All objects in TVM-FFI share the following characteristics: + +- are heap-allocated and reference-counted; +- have a layout-stable 24-byte header that stores reference counts, type index, and a deleter callback; +- their type index is always >= :cpp:enumerator:`kTVMFFIStaticObjectBegin <TVMFFITypeIndex::kTVMFFIStaticObjectBegin>`; + +**Dynamic Type System.** Classes can be dynamically registered at runtime, and single inheritance is supported +between classes via :cpp:func:`TVMFFITypeGetOrAllocIndex`. See :ref:`type-checking-and-casting` for how to use the type system. + +Ownership Management +~~~~~~~~~~~~~~~~~~~~ + +Ownership is managed by reference counting. See :ref:`object-reference-counting` for details. + +The C code below manages the ownership of a TVM-FFI object via + +- :cpp:func:`TVMFFIObjectIncRef`: Grab ownership by incrementing the reference count. +- :cpp:func:`TVMFFIObjectDecRef`: Release ownership by decrementing the reference count. Its deleter callback (:cpp:member:`TVMFFIObject::deleter`) kicks in when the reference count reaches zero. + +**Move ownership from Any/AnyView**. The C code below moves ownership of a TVM-FFI object from an owning :cpp:class:`~tvm::ffi::Any` to an Object pointer. + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Object.MoveFromAny.begin] + :end-before: [Object.MoveFromAny.end] + +Note that because :cpp:class:`~tvm::ffi::AnyView` is a non-owning view (where ``IS_OWNING_ANY`` is ``false``), +obtaining ownership from it requires incrementing the reference count. + +**Release ownership**. The C code below releases ownership of a TVM-FFI object: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :name: ABI.Object.Destroy + :start-after: [Object.Destroy.begin] + :end-before: [Object.Destroy.end] + +Inheritance Checking +~~~~~~~~~~~~~~~~~~~~ + +Single inheritance relationship can be modeled as a tree, where each node points to its only parent. +TVM-FFI manages every type with a unique type index, their ancestors, their depths in the inheritance tree, etc., +and this information is available via :cpp:func:`TVMFFIGetTypeInfo`. + +The C code below checks if a type is a subclass of another type: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Object.IsInstance.begin] + :end-before: [Object.IsInstance.end] + +Tensor +------ + +.. seealso:: + + :doc:`tensor` for details about TVM-FFI tensors and DLPack interoperability. + +TVM-FFI provides a DLPack-native tensor class :cpp:class:`tvm::ffi::TensorObj`, which is a standard TVM-FFI object, +meaning it can be managed in the same way as other TVM-FFI objects. + +.. dropdown:: C ABI Reference: :cpp:class:`tvm::ffi::TensorObj` + :icon: code + + .. code-block:: cpp + :caption: tvm/ffi/container/tensor.h + + class TensorObj : public Object, public DLTensor { + // no other members besides those from Object and DLTensor + }; + + +Access Tensor Metadata +~~~~~~~~~~~~~~~~~~~~~~ + +The C code below accesses the :c:struct:`DLTensor` pointer from a :cpp:class:`~tvm::ffi::TensorObj`: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Tensor.AccessDLTensor.begin] + :end-before: [Tensor.AccessDLTensor.end] + +Tensor's shape, dtype, device, data pointer, etc., are accessible via the :c:struct:`DLTensor` pointer. + +Construct Tensor +~~~~~~~~~~~~~~~~ + +The C code below constructs a :cpp:class:`~tvm::ffi::TensorObj` from a :c:struct:`DLManagedTensorVersioned`: + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Tensor_FromDLPack.begin] + :end-before: [Tensor_FromDLPack.end] + +.. hint:: + TVM-FFI's Python API automatically wraps framework tensors (e.g. :py:class:`torch.Tensor`) to :cpp:class:`~tvm::ffi::TensorObj`, + meaning the method above is usually **unnecessary** because conversion is handled already. + +Destruct Tensor +~~~~~~~~~~~~~~~~ + +The :ref:`standard way <ABI.Object.Destroy>` applies here to release a :cpp:class:`~tvm::ffi::TensorObj` +because it is a standard TVM-FFI object. Once the reference count reaches zero, +the deleter callback (:cpp:member:`TVMFFIObject::deleter`) will be called. + +Export Tensor to DLPack +~~~~~~~~~~~~~~~~~~~~~~~ + +Occasionally, it could be useful to export a :cpp:class:`~tvm::ffi::TensorObj` to :c:struct:`DLManagedTensorVersioned`, +so that it could potentially be consumed by other frameworks. + +.. literalinclude:: ../../examples/abi_overview/example_code.c + :language: c + :start-after: [Tensor_ToDLPackVersioned.begin] + :end-before: [Tensor_ToDLPackVersioned.end] + +Function +-------- + +.. seealso:: + + :doc:`func_module` for function calling and module loading. + +Functions in TVM-FFI follow a unified C calling convention that enables type-erased, +cross-language function calls. + +.. dropdown:: C ABI Reference: :cpp:type:`TVMFFISafeCallType` + :icon: code + + .. literalinclude:: ../../include/tvm/ffi/c_api.h + :language: c + :start-after: [TVMFFISafeCallType.begin] + :end-before: [TVMFFISafeCallType.end] + :caption: tvm/ffi/c_api.h + +**Return Value Convention:** + +- ``0``: Success +- ``-1``: Error occurred, retrievable via :cpp:func:`TVMFFIErrorMoveFromRaised` +- ``-2``: Frontend error (e.g., Python exception) + +**Function Object Layout.** The :cpp:class:`~tvm::ffi::FunctionObj` stores call pointers after the object header. +Access the function cell by skipping the :cpp:class:`TVMFFIObject` header: +``TVMFFIFunctionCell* cell = (TVMFFIFunctionCell*)((char*)func_obj + sizeof(TVMFFIObject));`` + +.. dropdown:: C ABI Reference: :cpp:class:`TVMFFIFunctionCell` + :icon: code + + .. literalinclude:: ../../include/tvm/ffi/c_api.h + :language: c + :start-after: [TVMFFIFunctionCell.begin] + :end-before: [TVMFFIFunctionCell.end] + :caption: tvm/ffi/c_api.h + +**Calling a Function:** + +.. code-block:: cpp + + int CallFunction(TVMFFIObjectHandle func, int x, int y) { + TVMFFIAny args[2], result; + + // Set up arguments + args[0].type_index = kTVMFFIInt; + args[0].zero_padding = 0; + args[0].v_int64 = x; + + args[1].type_index = kTVMFFIInt; + args[1].zero_padding = 0; + args[1].v_int64 = y; + + // Initialize result (required!) + result.type_index = kTVMFFINone; + result.zero_padding = 0; + result.v_int64 = 0; + + int rc = TVMFFIFunctionCall(func, args, 2, &result); + if (rc != 0) { + // Handle error + TVMFFIObjectHandle err = NULL; + TVMFFIErrorMoveFromRaised(&err); + // ... process error ... + TVMFFIObjectDecRef(err); + return rc; + } + return result.v_int64; + } + +Exception +--------- + +Exceptions are stored as objects with a :cpp:class:`TVMFFIErrorCell` payload. +Access the error cell by skipping the :cpp:class:`TVMFFIObject` header: +``TVMFFIErrorCell* cell = (TVMFFIErrorCell*)((char*)err_obj + sizeof(TVMFFIObject));`` + +.. dropdown:: C ABI Reference: :cpp:class:`TVMFFIErrorCell` + :icon: code + + .. literalinclude:: ../../include/tvm/ffi/c_api.h + :language: c + :start-after: [TVMFFIErrorCell.begin] + :end-before: [TVMFFIErrorCell.end] + :caption: tvm/ffi/c_api.h + +**Raising an Exception:** + +.. code-block:: cpp + + int MyFunction(void* handle, const TVMFFIAny* args, + int32_t num_args, TVMFFIAny* result) { + if (num_args < 1) { + TVMFFIErrorSetRaisedFromCStr("ValueError", "Expected at least 1 argument"); + return -1; + } + // ... function implementation ... + return 0; + } + +Module +------ + +A :cpp:class:`~tvm::ffi::Module` is a namespace containing functions, typically loaded from a shared library +or bundled with the executable. + +**Loading Shared Libraries.** Functions exported with the ``__tvm_ffi_<name>`` symbol +convention can be loaded dynamically: + +.. code-block:: cpp + + // In shared library (C++): + TVM_FFI_DLL_EXPORT_TYPED_FUNC(my_func, MyFunctionImpl); + // Creates symbol: __tvm_ffi_my_func + +Use :py:func:`tvm_ffi.load_module` in Python or the corresponding C++ API to load. + +**System Library.** For statically linked symbols, register during initialization: + +.. code-block:: cpp + + #include <tvm/ffi/extra/c_env_api.h> + + // Register symbol for system library lookup + TVMFFIEnvModRegisterSystemLibSymbol("__tvm_ffi_my_prefix.my_func", my_func_ptr); + +**Looking Up Functions from Imports.** Use :cpp:func:`TVMFFIEnvModLookupFromImports` to +find functions in a module's import chain: + +.. code-block:: cpp + + TVMFFIObjectHandle func = NULL; + int rc = TVMFFIEnvModLookupFromImports(library_ctx, "my_function", &func); + +String and Byte +--------------- + +Strings and bytes have multiple representations identified by ``type_index``: + +- :cpp:enumerator:`kTVMFFIRawStr <TVMFFITypeIndex::kTVMFFIRawStr>`: Raw ``const char*`` in ``v_c_str`` (null-terminated, non-owning) +- :cpp:enumerator:`kTVMFFISmallStr <TVMFFITypeIndex::kTVMFFISmallStr>` / :cpp:enumerator:`kTVMFFISmallBytes <TVMFFITypeIndex::kTVMFFISmallBytes>`: Inline storage in ``v_bytes`` (≤7 bytes) +- :cpp:enumerator:`kTVMFFIStr <TVMFFITypeIndex::kTVMFFIStr>` / :cpp:enumerator:`kTVMFFIBytes <TVMFFITypeIndex::kTVMFFIBytes>`: Heap-allocated object with :cpp:class:`TVMFFIByteArray` payload + +.. dropdown:: C ABI Reference: :cpp:class:`TVMFFIByteArray` and :cpp:class:`TVMFFIShapeCell` Review Comment:  The dropdown title includes `:cpp:class:`TVMFFIShapeCell``, but this section is about 'String and Byte'. `TVMFFIShapeCell` is not directly related to strings or bytes, which might confuse readers. Consider making the dropdown more focused on `TVMFFIByteArray` or clarifying why `TVMFFIShapeCell` is included here. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
