diff --git a/python/tvm/_ffi/_ctypes/__init__.py b/python/tvm/_ffi/_ctypes/__init__.py deleted file mode 100644 index b2851f4b27f3..000000000000 --- a/python/tvm/_ffi/_ctypes/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# 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. -"""ctypes specific implementation of FFI""" diff --git a/python/tvm/_ffi/_ctypes/ndarray.py b/python/tvm/_ffi/_ctypes/ndarray.py deleted file mode 100644 index fc8768448dde..000000000000 --- a/python/tvm/_ffi/_ctypes/ndarray.py +++ /dev/null @@ -1,151 +0,0 @@ -# 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. -# pylint: disable=invalid-name -"""Runtime NDArray api""" -import ctypes -from ..base import _LIB, check_call, c_str -from ..runtime_ctypes import TVMArrayHandle -from .types import RETURN_SWITCH, C_TO_PY_ARG_SWITCH, _wrap_arg_func, _return_handle - - -TVMPyCapsuleDestructor = ctypes.CFUNCTYPE(None, ctypes.c_void_p) -_c_str_dltensor = c_str("dltensor") -_c_str_used_dltensor = c_str("used_dltensor") - - -# used for PyCapsule manipulation -if hasattr(ctypes, "pythonapi"): - ctypes.pythonapi.PyCapsule_GetName.restype = ctypes.c_char_p - ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p - ctypes.pythonapi.PyCapsule_New.restype = ctypes.py_object - - -def _from_dlpack(dltensor): - dltensor = ctypes.py_object(dltensor) - if ctypes.pythonapi.PyCapsule_IsValid(dltensor, _c_str_dltensor): - ptr = ctypes.pythonapi.PyCapsule_GetPointer(dltensor, _c_str_dltensor) - # enforce type to make sure it works for all ctypes - ptr = ctypes.cast(ptr, ctypes.c_void_p) - handle = TVMArrayHandle() - check_call(_LIB.TVMArrayFromDLPack(ptr, ctypes.byref(handle))) - ctypes.pythonapi.PyCapsule_SetName(dltensor, _c_str_used_dltensor) - ctypes.pythonapi.PyCapsule_SetDestructor(dltensor, TVMPyCapsuleDestructor(0)) - return _make_array(handle, False, False) - raise ValueError("Expect a dltensor field, PyCapsule can only be consumed once") - - -def _dlpack_deleter(pycapsule): - pycapsule = ctypes.cast(pycapsule, ctypes.py_object) - if ctypes.pythonapi.PyCapsule_IsValid(pycapsule, _c_str_dltensor): - ptr = ctypes.pythonapi.PyCapsule_GetPointer(pycapsule, _c_str_dltensor) - # enforce type to make sure it works for all ctypes - ptr = ctypes.cast(ptr, ctypes.c_void_p) - _LIB.TVMDLManagedTensorCallDeleter(ptr) - ctypes.pythonapi.PyCapsule_SetDestructor(pycapsule, None) - - -_c_dlpack_deleter = TVMPyCapsuleDestructor(_dlpack_deleter) - - -class NDArrayBase(object): - """A simple Device/CPU Array object in runtime.""" - - __slots__ = ["handle", "is_view"] - # pylint: disable=no-member - def __init__(self, handle, is_view=False): - """Initialize the function with handle - - Parameters - ---------- - handle : TVMArrayHandle - the handle to the underlying C++ TVMArray - """ - self.handle = handle - self.is_view = is_view - - def __del__(self): - if not self.is_view and _LIB: - check_call(_LIB.TVMArrayFree(self.handle)) - - @property - def _tvm_handle(self): - return ctypes.cast(self.handle, ctypes.c_void_p).value - - def _copyto(self, target_nd): - """Internal function that implements copy to target ndarray.""" - check_call(_LIB.TVMArrayCopyFromTo(self.handle, target_nd.handle, None)) - return target_nd - - @property - def shape(self): - """Shape of this array""" - return tuple(self.handle.contents.shape[i] for i in range(self.handle.contents.ndim)) - - def to_dlpack(self): - """Produce an array from a DLPack Tensor without copying memory - - Returns - ------- - dlpack : DLPack tensor view of the array data - """ - handle = ctypes.c_void_p() - check_call(_LIB.TVMArrayToDLPack(self.handle, ctypes.byref(handle))) - return ctypes.pythonapi.PyCapsule_New(handle, _c_str_dltensor, _c_dlpack_deleter) - - -def _make_array(handle, is_view, is_container): - global _TVM_ND_CLS - handle = ctypes.cast(handle, TVMArrayHandle) - if is_container: - tindex = ctypes.c_uint() - check_call(_LIB.TVMArrayGetTypeIndex(handle, ctypes.byref(tindex))) - cls = _TVM_ND_CLS.get(tindex.value, _CLASS_NDARRAY) - else: - cls = _CLASS_NDARRAY - - ret = cls.__new__(cls) - ret.handle = handle - ret.is_view = is_view - return ret - - -_TVM_COMPATS = () - - -def _reg_extension(cls, fcreate): - global _TVM_COMPATS - _TVM_COMPATS += (cls,) - if fcreate: - fret = lambda x: fcreate(_return_handle(x)) - RETURN_SWITCH[cls._tvm_tcode] = fret - C_TO_PY_ARG_SWITCH[cls._tvm_tcode] = _wrap_arg_func(fret, cls._tvm_tcode) - - -_TVM_ND_CLS = {} - - -def _register_ndarray(index, cls): - global _TVM_ND_CLS - _TVM_ND_CLS[index] = cls - - -_CLASS_NDARRAY = None - - -def _set_class_ndarray(cls): - global _CLASS_NDARRAY - _CLASS_NDARRAY = cls diff --git a/python/tvm/_ffi/_ctypes/object.py b/python/tvm/_ffi/_ctypes/object.py deleted file mode 100644 index 8f674eea2ec6..000000000000 --- a/python/tvm/_ffi/_ctypes/object.py +++ /dev/null @@ -1,189 +0,0 @@ -# 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. -# pylint: disable=invalid-name -"""Runtime Object api""" -import ctypes -from ..base import _LIB, check_call -from .types import ArgTypeCode, RETURN_SWITCH, C_TO_PY_ARG_SWITCH, _wrap_arg_func -from .ndarray import _register_ndarray, NDArrayBase - - -ObjectHandle = ctypes.c_void_p -__init_by_constructor__ = None - -"""Maps object type index to its constructor""" -OBJECT_TYPE = {} - -"""Maps object type to its type index""" -OBJECT_INDEX = {} - -_CLASS_OBJECT = None - - -def _set_class_object(object_class): - global _CLASS_OBJECT - _CLASS_OBJECT = object_class - - -def _register_object(index, cls): - """register object class""" - if issubclass(cls, NDArrayBase): - _register_ndarray(index, cls) - return - OBJECT_TYPE[index] = cls - OBJECT_INDEX[cls] = index - - -def _get_object_type_index(cls): - """get the type index of object class""" - return OBJECT_INDEX.get(cls) - - -def _return_object(x): - handle = x.v_handle - if not isinstance(handle, ObjectHandle): - handle = ObjectHandle(handle) - tindex = ctypes.c_uint() - check_call(_LIB.TVMObjectGetTypeIndex(handle, ctypes.byref(tindex))) - cls = OBJECT_TYPE.get(tindex.value, _CLASS_OBJECT) - - # Handle return values that subclass from both TVM objects and - # python native objects (e.g. runtime.String, a subclass of str). - if issubclass(cls, PyNativeObject): - obj = _CLASS_OBJECT.__new__(_CLASS_OBJECT) - obj.handle = handle - return cls.__from_tvm_object__(cls, obj) - - # Avoid calling __init__ of cls, instead directly call __new__ - # This allows child class to implement their own __init__ - obj = cls.__new__(cls) - obj.handle = handle - - # Handle return values that must be converted from the TVM object - # to a python native object. This should be used in cases where - # subclassing the python native object is forbidden. For example, - # `runtime.BoxBool` cannot be a subclass of `bool`, as `bool` does - # not allow any subclasses. - # - # The `hasattr` check is done on the object's class, not the - # object itself, to avoid edge cases that can result in invalid - # error messages. If a C++ `LOG(FATAL) << nested_obj;` statement - # requires C++ to Python conversions in order to print - # `nested_obj`, then the `AttributeError` used internally by - # `hasattr` may overwrite the text being collected by - # `LOG(FATAL)`. By checking for the method on the class instead - # of the instance, we avoid throwing the `AttributeError`. - # if hasattr(type(obj), "__into_pynative_object__"): - # return obj.__into_pynative_object__() - - return obj - - -RETURN_SWITCH[ArgTypeCode.OBJECT_HANDLE] = _return_object -C_TO_PY_ARG_SWITCH[ArgTypeCode.OBJECT_HANDLE] = _wrap_arg_func( - _return_object, ArgTypeCode.OBJECT_HANDLE -) - -C_TO_PY_ARG_SWITCH[ArgTypeCode.OBJECT_RVALUE_REF_ARG] = _wrap_arg_func( - _return_object, ArgTypeCode.OBJECT_RVALUE_REF_ARG -) - - -class PyNativeObject: - """Base class of all TVM objects that also subclass python's builtin types.""" - - __slots__ = [] - - def __init_tvm_object_by_constructor__(self, fconstructor, *args): - """Initialize the internal tvm_object by calling constructor function. - - Parameters - ---------- - fconstructor : Function - Constructor function. - - args: list of objects - The arguments to the constructor - - Note - ---- - We have a special calling convention to call constructor functions. - So the return object is directly set into the object - """ - # pylint: disable=assigning-non-slot - obj = _CLASS_OBJECT.__new__(_CLASS_OBJECT) - obj.__init_handle_by_constructor__(fconstructor, *args) - self.__tvm_object__ = obj - - -class ObjectBase(object): - """Base object for all object types""" - - __slots__ = ["handle"] - - def __del__(self): - if _LIB is not None: - try: - handle = self.handle - except AttributeError: - return - - check_call(_LIB.TVMObjectFree(handle)) - - def __init_handle_by_constructor__(self, fconstructor, *args): - """Initialize the handle by calling constructor function. - - Parameters - ---------- - fconstructor : Function - Constructor function. - - args: list of objects - The arguments to the constructor - - Note - ---- - We have a special calling convention to call constructor functions. - So the return handle is directly set into the Node object - instead of creating a new Node. - """ - # assign handle first to avoid error raising - # pylint: disable=not-callable - self.handle = None - handle = __init_by_constructor__(fconstructor, args) - if not isinstance(handle, ObjectHandle): - handle = ObjectHandle(handle) - self.handle = handle - - def same_as(self, other): - """Check object identity. - - Parameters - ---------- - other : object - The other object to compare against. - - Returns - ------- - result : bool - The comparison result. - """ - if not isinstance(other, ObjectBase): - return False - if self.handle is None: - return other.handle is None - return self.handle.value == other.handle.value diff --git a/python/tvm/_ffi/_ctypes/packed_func.py b/python/tvm/_ffi/_ctypes/packed_func.py deleted file mode 100644 index 6dab1a5db1f4..000000000000 --- a/python/tvm/_ffi/_ctypes/packed_func.py +++ /dev/null @@ -1,354 +0,0 @@ -# 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. -# coding: utf-8 -# pylint: disable=invalid-name, protected-access, too-many-branches -# pylint: disable=global-statement, unused-import, using-constant-test -"""Function configuration API.""" -import ctypes -import traceback -from numbers import Number, Integral - -from ..base import _LIB, get_last_ffi_error, py2cerror, check_call, raise_last_ffi_error -from ..base import c_str, string_types -from ..runtime_ctypes import DataType, TVMByteArray, Device, ObjectRValueRef -from . import ndarray as _nd -from .ndarray import NDArrayBase, _make_array -from .types import TVMValue, ArgTypeCode -from .types import TVMPackedCFunc, TVMCFuncFinalizer -from .types import RETURN_SWITCH, C_TO_PY_ARG_SWITCH, _wrap_arg_func, _device_to_int64 -from .object import ObjectBase, PyNativeObject, _set_class_object -from . import object as _object - -PackedFuncHandle = ctypes.c_void_p -ModuleHandle = ctypes.c_void_p -ObjectHandle = ctypes.c_void_p -TVMRetValueHandle = ctypes.c_void_p - - -def _ctypes_free_resource(rhandle): - """callback to free resources when it is not needed.""" - pyobj = ctypes.cast(rhandle, ctypes.py_object) - ctypes.pythonapi.Py_DecRef(pyobj) - - -# Global callback that is always alive -TVM_FREE_PYOBJ = TVMCFuncFinalizer(_ctypes_free_resource) -ctypes.pythonapi.Py_IncRef(ctypes.py_object(TVM_FREE_PYOBJ)) - - -def _make_packed_func(handle, is_global): - """Make a packed function class""" - obj = _CLASS_PACKED_FUNC.__new__(_CLASS_PACKED_FUNC) - obj.is_global = is_global - obj.handle = handle - return obj - - -def convert_to_tvm_func(pyfunc): - """Convert a python function to TVM function - - Parameters - ---------- - pyfunc : python function - The python function to be converted. - - Returns - ------- - tvmfunc: tvm.nd.Function - The converted tvm function. - """ - local_pyfunc = pyfunc - - def cfun(args, type_codes, num_args, ret, _): - """ctypes function""" - num_args = num_args.value if isinstance(num_args, ctypes.c_int) else num_args - pyargs = (C_TO_PY_ARG_SWITCH[type_codes[i]](args[i]) for i in range(num_args)) - # pylint: disable=broad-except - try: - rv = local_pyfunc(*pyargs) - except Exception as err: - msg = traceback.format_exc() - msg = py2cerror(msg) - _LIB.TVMAPISetLastPythonError(ctypes.py_object(err)) - - return -1 - - if rv is not None: - if isinstance(rv, tuple): - raise ValueError("PackedFunction can only support one return value") - temp_args = [] - values, tcodes, _ = _make_tvm_args((rv,), temp_args) - if not isinstance(ret, TVMRetValueHandle): - ret = TVMRetValueHandle(ret) - if _LIB.TVMCFuncSetReturn(ret, values, tcodes, ctypes.c_int(1)) != 0: - raise_last_ffi_error() - _ = temp_args - _ = rv - return 0 - - handle = PackedFuncHandle() - f = TVMPackedCFunc(cfun) - # NOTE: We will need to use python-api to increase ref count of the f - # TVM_FREE_PYOBJ will be called after it is no longer needed. - pyobj = ctypes.py_object(f) - ctypes.pythonapi.Py_IncRef(pyobj) - if _LIB.TVMFuncCreateFromCFunc(f, pyobj, TVM_FREE_PYOBJ, ctypes.byref(handle)) != 0: - raise_last_ffi_error() - return _make_packed_func(handle, False) - - -def _make_tvm_args(args, temp_args): - """Pack arguments into c args tvm call accept""" - num_args = len(args) - values = (TVMValue * num_args)() - type_codes = (ctypes.c_int * num_args)() - for i, arg in enumerate(args): - if isinstance(arg, ObjectBase): - values[i].v_handle = arg.handle - type_codes[i] = ArgTypeCode.OBJECT_HANDLE - elif arg is None: - values[i].v_handle = None - type_codes[i] = ArgTypeCode.NULL - elif isinstance(arg, NDArrayBase): - values[i].v_handle = ctypes.cast(arg.handle, ctypes.c_void_p) - type_codes[i] = ( - ArgTypeCode.NDARRAY_HANDLE if not arg.is_view else ArgTypeCode.DLTENSOR_HANDLE - ) - elif isinstance(arg, PyNativeObject): - values[i].v_handle = arg.__tvm_object__.handle - type_codes[i] = ArgTypeCode.OBJECT_HANDLE - elif isinstance(arg, _nd._TVM_COMPATS): - values[i].v_handle = ctypes.c_void_p(arg._tvm_handle) - type_codes[i] = arg.__class__._tvm_tcode - elif isinstance(arg, bool): - # A python `bool` is a subclass of `int`, so this check - # must occur before `Integral`. - values[i].v_bool = arg - type_codes[i] = ArgTypeCode.BOOL - elif isinstance(arg, Integral): - values[i].v_int64 = arg - type_codes[i] = ArgTypeCode.INT - elif isinstance(arg, Number): - values[i].v_float64 = arg - type_codes[i] = ArgTypeCode.FLOAT - elif isinstance(arg, DataType): - values[i].v_str = c_str(str(arg)) - type_codes[i] = ArgTypeCode.STR - elif isinstance(arg, Device): - values[i].v_int64 = _device_to_int64(arg) - type_codes[i] = ArgTypeCode.DLDEVICE - elif isinstance(arg, (bytearray, bytes)): - # from_buffer only takes in bytearray. - if isinstance(arg, bytes): - byte_arr = bytearray(arg) - temp_args.append(byte_arr) - arg = byte_arr - - arr = TVMByteArray() - arr.data = ctypes.cast( - (ctypes.c_byte * len(arg)).from_buffer(arg), ctypes.POINTER(ctypes.c_byte) - ) - arr.size = len(arg) - values[i].v_handle = ctypes.c_void_p(ctypes.addressof(arr)) - temp_args.append(arr) - type_codes[i] = ArgTypeCode.BYTES - elif isinstance(arg, string_types): - values[i].v_str = c_str(arg) - type_codes[i] = ArgTypeCode.STR - elif isinstance(arg, (list, tuple, dict, _CLASS_OBJECT_GENERIC)): - arg = _FUNC_CONVERT_TO_OBJECT(arg) - values[i].v_handle = arg.handle - type_codes[i] = ArgTypeCode.OBJECT_HANDLE - temp_args.append(arg) - elif isinstance(arg, _CLASS_MODULE): - values[i].v_handle = arg.handle - type_codes[i] = ArgTypeCode.MODULE_HANDLE - elif isinstance(arg, PackedFuncBase): - values[i].v_handle = arg.handle - type_codes[i] = ArgTypeCode.PACKED_FUNC_HANDLE - elif isinstance(arg, ctypes.c_void_p): - values[i].v_handle = arg - type_codes[i] = ArgTypeCode.HANDLE - elif isinstance(arg, ObjectRValueRef): - values[i].v_handle = ctypes.cast(ctypes.byref(arg.obj.handle), ctypes.c_void_p) - type_codes[i] = ArgTypeCode.OBJECT_RVALUE_REF_ARG - elif callable(arg): - arg = convert_to_tvm_func(arg) - values[i].v_handle = arg.handle - type_codes[i] = ArgTypeCode.PACKED_FUNC_HANDLE - temp_args.append(arg) - else: - raise TypeError("Don't know how to handle type %s" % type(arg)) - return values, type_codes, num_args - - -class PackedFuncBase(object): - """Function base.""" - - __slots__ = ["handle", "is_global"] - - # pylint: disable=no-member - def __init__(self, handle, is_global): - """Initialize the function with handle - - Parameters - ---------- - handle : PackedFuncHandle - the handle to the underlying function. - - is_global : bool - Whether this is a global function in python - """ - self.handle = handle - self.is_global = is_global - - def __del__(self): - if not self.is_global and _LIB is not None: - if _LIB.TVMFuncFree(self.handle) != 0: - raise_last_ffi_error() - - def __call__(self, *args): - """Call the function with positional arguments - - args : list - The positional arguments to the function call. - """ - temp_args = [] - values, tcodes, num_args = _make_tvm_args(args, temp_args) - ret_val = TVMValue() - ret_tcode = ctypes.c_int() - if ( - _LIB.TVMFuncCall( - self.handle, - values, - tcodes, - ctypes.c_int(num_args), - ctypes.byref(ret_val), - ctypes.byref(ret_tcode), - ) - != 0 - ): - raise_last_ffi_error() - _ = temp_args - _ = args - return RETURN_SWITCH[ret_tcode.value](ret_val) - - -def __init_handle_by_constructor__(fconstructor, args): - """Initialize handle by constructor""" - temp_args = [] - values, tcodes, num_args = _make_tvm_args(args, temp_args) - ret_val = TVMValue() - ret_tcode = ctypes.c_int() - if ( - _LIB.TVMFuncCall( - fconstructor.handle, - values, - tcodes, - ctypes.c_int(num_args), - ctypes.byref(ret_val), - ctypes.byref(ret_tcode), - ) - != 0 - ): - raise_last_ffi_error() - _ = temp_args - _ = args - assert ret_tcode.value == ArgTypeCode.OBJECT_HANDLE - handle = ret_val.v_handle - return handle - - -def _return_module(x): - """Return function""" - handle = x.v_handle - if not isinstance(handle, ModuleHandle): - handle = ModuleHandle(handle) - return _CLASS_MODULE(handle) - - -def _handle_return_func(x): - """Return function""" - handle = x.v_handle - if not isinstance(handle, PackedFuncHandle): - handle = PackedFuncHandle(handle) - return _CLASS_PACKED_FUNC(handle, False) - - -def _get_global_func(name, allow_missing=False): - handle = PackedFuncHandle() - check_call(_LIB.TVMFuncGetGlobal(c_str(name), ctypes.byref(handle))) - - if handle.value: - return _make_packed_func(handle, False) - - if allow_missing: - return None - - raise ValueError("Cannot find global function %s" % name) - - -# setup return handle for function type -_object.__init_by_constructor__ = __init_handle_by_constructor__ -RETURN_SWITCH[ArgTypeCode.PACKED_FUNC_HANDLE] = _handle_return_func -RETURN_SWITCH[ArgTypeCode.MODULE_HANDLE] = _return_module -RETURN_SWITCH[ArgTypeCode.NDARRAY_HANDLE] = lambda x: _make_array(x.v_handle, False, True) -C_TO_PY_ARG_SWITCH[ArgTypeCode.PACKED_FUNC_HANDLE] = _wrap_arg_func( - _handle_return_func, ArgTypeCode.PACKED_FUNC_HANDLE -) -C_TO_PY_ARG_SWITCH[ArgTypeCode.MODULE_HANDLE] = _wrap_arg_func( - _return_module, ArgTypeCode.MODULE_HANDLE -) -C_TO_PY_ARG_SWITCH[ArgTypeCode.DLTENSOR_HANDLE] = lambda x: _make_array(x.v_handle, True, False) -C_TO_PY_ARG_SWITCH[ArgTypeCode.NDARRAY_HANDLE] = _wrap_arg_func( - lambda x: _make_array(x.v_handle, False, True), ArgTypeCode.NDARRAY_HANDLE -) - -_CLASS_MODULE = None -_CLASS_PACKED_FUNC = None -_CLASS_OBJECT_GENERIC = None -_FUNC_CONVERT_TO_OBJECT = None - - -def _set_class_module(module_class): - """Initialize the module.""" - global _CLASS_MODULE - _CLASS_MODULE = module_class - - -def _set_class_packed_func(packed_func_class): - global _CLASS_PACKED_FUNC - _CLASS_PACKED_FUNC = packed_func_class - - -def _set_class_object_generic(object_generic_class, func_convert_to_object): - global _CLASS_OBJECT_GENERIC - global _FUNC_CONVERT_TO_OBJECT - _CLASS_OBJECT_GENERIC = object_generic_class - _FUNC_CONVERT_TO_OBJECT = func_convert_to_object - - -def _init_pythonapi_inc_def_ref(): - register_func = _LIB.TVMBackendRegisterEnvCAPI - register_func(c_str("Py_IncRef"), ctypes.pythonapi.Py_IncRef) - register_func(c_str("Py_DecRef"), ctypes.pythonapi.Py_DecRef) - register_func(c_str("PyGILState_Ensure"), ctypes.pythonapi.PyGILState_Ensure) - register_func(c_str("PyGILState_Release"), ctypes.pythonapi.PyGILState_Release) - register_func(c_str("PyErr_CheckSignals"), ctypes.pythonapi.PyErr_CheckSignals) - - -_init_pythonapi_inc_def_ref() diff --git a/python/tvm/_ffi/_ctypes/types.py b/python/tvm/_ffi/_ctypes/types.py deleted file mode 100644 index 45f36eafd78a..000000000000 --- a/python/tvm/_ffi/_ctypes/types.py +++ /dev/null @@ -1,116 +0,0 @@ -# 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. -"""The C Types used in API.""" -# pylint: disable=invalid-name -import ctypes -import struct -from ..base import py_str, check_call, _LIB -from ..runtime_ctypes import TVMByteArray, ArgTypeCode, Device - - -class TVMValue(ctypes.Union): - """TVMValue in C API""" - - _fields_ = [ - ("v_int64", ctypes.c_int64), - ("v_bool", ctypes.c_bool), - ("v_float64", ctypes.c_double), - ("v_handle", ctypes.c_void_p), - ("v_str", ctypes.c_char_p), - ] - - -TVMPackedCFunc = ctypes.CFUNCTYPE( - ctypes.c_int, - ctypes.POINTER(TVMValue), - ctypes.POINTER(ctypes.c_int), - ctypes.c_int, - ctypes.c_void_p, - ctypes.c_void_p, -) - - -TVMCFuncFinalizer = ctypes.CFUNCTYPE(None, ctypes.c_void_p) - - -def _return_handle(x): - """return handle""" - handle = x.v_handle - if not isinstance(handle, ctypes.c_void_p): - handle = ctypes.c_void_p(handle) - return handle - - -def _return_bytes(x): - """return bytes""" - handle = x.v_handle - if not isinstance(handle, ctypes.c_void_p): - handle = ctypes.c_void_p(handle) - arr = ctypes.cast(handle, ctypes.POINTER(TVMByteArray))[0] - size = arr.size - res = bytearray(size) - rptr = (ctypes.c_byte * size).from_buffer(res) - if not ctypes.memmove(rptr, arr.data, size): - raise RuntimeError("memmove failed") - return res - - -def _return_device(value): - """return Device""" - # use bit unpacking from int64 view - # We use this to get around ctypes issue on Union of Structure - data = struct.pack("=q", value.v_int64) - arr = struct.unpack("=ii", data) - return Device(arr[0], arr[1]) - - -def _wrap_arg_func(return_f, type_code): - def _wrap_func(x): - tcode = ctypes.c_int(type_code) - check_call(_LIB.TVMCbArgToReturn(ctypes.byref(x), ctypes.byref(tcode))) - return return_f(x) - - return _wrap_func - - -def _device_to_int64(dev): - """Pack context into int64 in native endian""" - data = struct.pack("=ii", dev.device_type, dev.device_id) - return struct.unpack("=q", data)[0] - - -RETURN_SWITCH = { - ArgTypeCode.INT: lambda x: x.v_int64, - ArgTypeCode.BOOL: lambda x: x.v_bool, - ArgTypeCode.FLOAT: lambda x: x.v_float64, - ArgTypeCode.HANDLE: _return_handle, - ArgTypeCode.NULL: lambda x: None, - ArgTypeCode.STR: lambda x: py_str(x.v_str), - ArgTypeCode.BYTES: _return_bytes, - ArgTypeCode.DLDEVICE: _return_device, -} - -C_TO_PY_ARG_SWITCH = { - ArgTypeCode.INT: lambda x: x.v_int64, - ArgTypeCode.BOOL: lambda x: x.v_bool, - ArgTypeCode.FLOAT: lambda x: x.v_float64, - ArgTypeCode.HANDLE: _return_handle, - ArgTypeCode.NULL: lambda x: None, - ArgTypeCode.STR: lambda x: py_str(x.v_str), - ArgTypeCode.BYTES: _return_bytes, - ArgTypeCode.DLDEVICE: _return_device, -} diff --git a/python/tvm/_ffi/_cy2/__init__.py b/python/tvm/_ffi/_cy2/__init__.py deleted file mode 100644 index 4d0a864416b3..000000000000 --- a/python/tvm/_ffi/_cy2/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# 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. -"""cython2 namespace""" diff --git a/python/tvm/_ffi/base.py b/python/tvm/_ffi/base.py index 263ab0bdb3fe..f2add9d1e46e 100644 --- a/python/tvm/_ffi/base.py +++ b/python/tvm/_ffi/base.py @@ -83,6 +83,9 @@ def _load_lib(): # The FFI mode of TVM _FFI_MODE = os.environ.get("TVM_FFI", "auto") +if _FFI_MODE == "ctypes": + raise ImportError("We have phased out ctypes support in favor of cython on wards") + # ---------------------------- # helper function in ctypes. diff --git a/python/tvm/_ffi/registry.py b/python/tvm/_ffi/registry.py index 1b6b1dec9acc..cbc8dbaebf41 100644 --- a/python/tvm/_ffi/registry.py +++ b/python/tvm/_ffi/registry.py @@ -15,27 +15,16 @@ # specific language governing permissions and limitations # under the License. -# pylint: disable=invalid-name, unused-import +# pylint: disable=invalid-name, unused-import, wrong-import-position """FFI registry to register function and objects.""" import sys import ctypes -from .base import _LIB, check_call, py_str, c_str, string_types, _FFI_MODE, _RUNTIME_ONLY - -try: - # pylint: disable=wrong-import-position,unused-import - if _FFI_MODE == "ctypes": - raise ImportError() - from ._cy3.core import _register_object, _get_object_type_index - from ._cy3.core import _reg_extension - from ._cy3.core import convert_to_tvm_func, _get_global_func, PackedFuncBase -except (RuntimeError, ImportError) as error: - # pylint: disable=wrong-import-position,unused-import - if _FFI_MODE == "cython": - raise error - from ._ctypes.object import _register_object, _get_object_type_index - from ._ctypes.ndarray import _reg_extension - from ._ctypes.packed_func import convert_to_tvm_func, _get_global_func, PackedFuncBase +from .base import _LIB, check_call, py_str, c_str, string_types, _RUNTIME_ONLY + +from ._cy3.core import _register_object, _get_object_type_index +from ._cy3.core import _reg_extension +from ._cy3.core import convert_to_tvm_func, _get_global_func, PackedFuncBase def register_object(type_key=None): diff --git a/python/tvm/runtime/ndarray.py b/python/tvm/runtime/ndarray.py index 47fcccf52bac..f8dfe8d51169 100644 --- a/python/tvm/runtime/ndarray.py +++ b/python/tvm/runtime/ndarray.py @@ -27,7 +27,7 @@ except ImportError: ml_dtypes = None import tvm._ffi -from tvm._ffi.base import _FFI_MODE, _LIB, c_array, check_call, string_types +from tvm._ffi.base import _LIB, c_array, check_call, string_types from tvm._ffi.runtime_ctypes import ( DataType, DataTypeCode, @@ -36,30 +36,15 @@ TVMArrayHandle, tvm_shape_index_t, ) +from tvm._ffi._cy3.core import ( + NDArrayBase, + _from_dlpack, + _make_array, + _set_class_ndarray, +) from . import _ffi_api -try: - # pylint: disable=wrong-import-position - if _FFI_MODE == "ctypes": - raise ImportError() - from tvm._ffi._cy3.core import ( - NDArrayBase, - _from_dlpack, - _make_array, - _set_class_ndarray, - ) -except (RuntimeError, ImportError) as error: - # pylint: disable=wrong-import-position - if _FFI_MODE == "cython": - raise error - from tvm._ffi._ctypes.ndarray import ( - NDArrayBase, - _from_dlpack, - _make_array, - _set_class_ndarray, - ) - @tvm._ffi.register_object("runtime.NDArray") class NDArray(NDArrayBase): diff --git a/python/tvm/runtime/object.py b/python/tvm/runtime/object.py index b57276ebd2e1..4892a54f7591 100644 --- a/python/tvm/runtime/object.py +++ b/python/tvm/runtime/object.py @@ -18,28 +18,17 @@ """Runtime Object API""" import ctypes -from tvm._ffi.base import _FFI_MODE, _LIB, _RUNTIME_ONLY, c_str, check_call +from tvm._ffi.base import _LIB, _RUNTIME_ONLY, c_str, check_call from tvm._ffi.runtime_ctypes import ObjectRValueRef +from tvm._ffi._cy3.core import ( + ObjectBase, + PyNativeObject, + _set_class_object, + _set_class_object_generic, +) from . import _ffi_api, _ffi_node_api -try: - # pylint: disable=wrong-import-position,unused-import - if _FFI_MODE == "ctypes": - raise ImportError() - from tvm._ffi._cy3.core import ( - ObjectBase, - PyNativeObject, - _set_class_object, - _set_class_object_generic, - ) -except (RuntimeError, ImportError) as error: - # pylint: disable=wrong-import-position,unused-import - if _FFI_MODE == "cython": - raise error - from tvm._ffi._ctypes.object import ObjectBase, PyNativeObject - from tvm._ffi._ctypes.packed_func import _set_class_object, _set_class_object_generic - def _new_object(cls): """Helper function for pickle""" diff --git a/python/tvm/runtime/packed_func.py b/python/tvm/runtime/packed_func.py index bcd3cd733dc6..7f481148781d 100644 --- a/python/tvm/runtime/packed_func.py +++ b/python/tvm/runtime/packed_func.py @@ -18,22 +18,10 @@ # pylint: disable=invalid-name, unused-import """Packed Function namespace.""" import ctypes -from tvm._ffi.base import _LIB, check_call, c_str, string_types, _FFI_MODE - -try: - # pylint: disable=wrong-import-position - if _FFI_MODE == "ctypes": - raise ImportError() - from tvm._ffi._cy3.core import _set_class_packed_func, _set_class_module - from tvm._ffi._cy3.core import PackedFuncBase - from tvm._ffi._cy3.core import convert_to_tvm_func -except (RuntimeError, ImportError) as error: - # pylint: disable=wrong-import-position - if _FFI_MODE == "cython": - raise error - from tvm._ffi._ctypes.packed_func import _set_class_packed_func, _set_class_module - from tvm._ffi._ctypes.packed_func import PackedFuncBase - from tvm._ffi._ctypes.packed_func import convert_to_tvm_func +from tvm._ffi.base import _LIB, check_call, c_str, string_types +from tvm._ffi._cy3.core import _set_class_packed_func, _set_class_module +from tvm._ffi._cy3.core import PackedFuncBase +from tvm._ffi._cy3.core import convert_to_tvm_func PackedFuncHandle = ctypes.c_void_p diff --git a/tests/lint/pylintrc b/tests/lint/pylintrc index 90900b9e005a..81e6a9c68837 100644 --- a/tests/lint/pylintrc +++ b/tests/lint/pylintrc @@ -122,7 +122,8 @@ disable= useless-object-inheritance, useless-suppression, use-list-literal, - arguments-renamed + arguments-renamed, + super-init-not-called [REPORTS] diff --git a/tests/python/runtime/test_runtime_module_load.py b/tests/python/runtime/test_runtime_module_load.py index 130a274c354b..71f6a793877d 100644 --- a/tests/python/runtime/test_runtime_module_load.py +++ b/tests/python/runtime/test_runtime_module_load.py @@ -28,7 +28,6 @@ import sys os.environ["TVM_USE_RUNTIME_LIB"] = "1" -os.environ["TVM_FFI"] = "ctypes" import tvm from tvm import te import numpy as np diff --git a/tests/python/tvmscript/test_tvmscript_roundtrip.py b/tests/python/tvmscript/test_tvmscript_roundtrip.py index f29c03c640ab..140136f74198 100644 --- a/tests/python/tvmscript/test_tvmscript_roundtrip.py +++ b/tests/python/tvmscript/test_tvmscript_roundtrip.py @@ -3895,6 +3895,7 @@ def undefined_data_ptr_in_decl_buffer(): Allocate/DeclBuffer pair, performing a round-trip through TVMScript should not introduce an Allocate node. """ + # uninitialized var @T.prim_func(check_well_formed=False) def func():