This PR fixed [issues](https://github.com/iree-org/iree/actions/runs/21956878131/job/63423389868#step:7:211) caused by dropping `LLVMSupport` in PR #180986, dropped the remaining direct llvm dependencies from mlir-python binding files. Previously `LLVMSupport` was dropped while some uncleaned `mlir/CAPI/*` sources were still being pulled into mlir-py, and those files still directly depended on LLVM headers. The issue was masked via a global `include_directories(${LLVM_INCLUDE_DIRS})` in `mlir/CMakeLists.txt`, out-of-tree builds (e.g., IREE) that define Python module targets outside the mlir/ directory tree would fail with "no such llvm file" errors.
520 lines
21 KiB
C++
520 lines
21 KiB
C++
//===- DialectQuant.cpp - 'quant' dialect submodule -----------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <vector>
|
|
|
|
#include "mlir-c/Dialect/Quant.h"
|
|
#include "mlir-c/IR.h"
|
|
#include "mlir/Bindings/Python/IRCore.h"
|
|
#include "mlir/Bindings/Python/Nanobind.h"
|
|
#include "mlir/Bindings/Python/NanobindAdaptors.h"
|
|
|
|
#include <mlir/Bindings/Python/IRAttributes.h>
|
|
|
|
namespace nb = nanobind;
|
|
using namespace mlir::python::nanobind_adaptors;
|
|
|
|
namespace mlir {
|
|
namespace python {
|
|
namespace MLIR_BINDINGS_PYTHON_DOMAIN {
|
|
namespace quant {
|
|
//===-------------------------------------------------------------------===//
|
|
// QuantizedType
|
|
//===-------------------------------------------------------------------===//
|
|
|
|
struct QuantizedType : PyConcreteType<QuantizedType> {
|
|
static constexpr IsAFunctionTy isaFunction = mlirTypeIsAQuantizedType;
|
|
static constexpr const char *pyClassName = "QuantizedType";
|
|
using Base::Base;
|
|
|
|
static void bindDerived(ClassTy &c) {
|
|
c.def_static(
|
|
"default_minimum_for_integer",
|
|
[](bool isSigned, unsigned integralWidth) {
|
|
return mlirQuantizedTypeGetDefaultMinimumForInteger(isSigned,
|
|
integralWidth);
|
|
},
|
|
"Default minimum value for the integer with the specified signedness "
|
|
"and "
|
|
"bit width.",
|
|
nb::arg("is_signed"), nb::arg("integral_width"));
|
|
c.def_static(
|
|
"default_maximum_for_integer",
|
|
[](bool isSigned, unsigned integralWidth) {
|
|
return mlirQuantizedTypeGetDefaultMaximumForInteger(isSigned,
|
|
integralWidth);
|
|
},
|
|
"Default maximum value for the integer with the specified signedness "
|
|
"and "
|
|
"bit width.",
|
|
nb::arg("is_signed"), nb::arg("integral_width"));
|
|
c.def_prop_ro(
|
|
"expressed_type",
|
|
[](QuantizedType &type) {
|
|
return PyType(type.getContext(),
|
|
mlirQuantizedTypeGetExpressedType(type))
|
|
.maybeDownCast();
|
|
},
|
|
"Type expressed by this quantized type.");
|
|
c.def_prop_ro(
|
|
"flags",
|
|
[](const QuantizedType &type) {
|
|
return mlirQuantizedTypeGetFlags(type);
|
|
},
|
|
"Flags of this quantized type (named accessors should be preferred to "
|
|
"this)");
|
|
c.def_prop_ro(
|
|
"is_signed",
|
|
[](const QuantizedType &type) {
|
|
return mlirQuantizedTypeIsSigned(type);
|
|
},
|
|
"Signedness of this quantized type.");
|
|
c.def_prop_ro(
|
|
"storage_type",
|
|
[](QuantizedType &type) {
|
|
return PyType(type.getContext(),
|
|
mlirQuantizedTypeGetStorageType(type))
|
|
.maybeDownCast();
|
|
},
|
|
"Storage type backing this quantized type.");
|
|
c.def_prop_ro(
|
|
"storage_type_min",
|
|
[](const QuantizedType &type) {
|
|
return mlirQuantizedTypeGetStorageTypeMin(type);
|
|
},
|
|
"The minimum value held by the storage type of this quantized type.");
|
|
c.def_prop_ro(
|
|
"storage_type_max",
|
|
[](const QuantizedType &type) {
|
|
return mlirQuantizedTypeGetStorageTypeMax(type);
|
|
},
|
|
"The maximum value held by the storage type of this quantized type.");
|
|
c.def_prop_ro(
|
|
"storage_type_integral_width",
|
|
[](const QuantizedType &type) {
|
|
return mlirQuantizedTypeGetStorageTypeIntegralWidth(type);
|
|
},
|
|
"The bitwidth of the storage type of this quantized type.");
|
|
c.def(
|
|
"is_compatible_expressed_type",
|
|
[](const QuantizedType &type, const PyType &candidate) {
|
|
return mlirQuantizedTypeIsCompatibleExpressedType(type, candidate);
|
|
},
|
|
"Checks whether the candidate type can be expressed by this quantized "
|
|
"type.",
|
|
nb::arg("candidate"));
|
|
c.def_prop_ro(
|
|
"quantized_element_type",
|
|
[](QuantizedType &type) {
|
|
return PyType(type.getContext(),
|
|
mlirQuantizedTypeGetQuantizedElementType(type))
|
|
.maybeDownCast();
|
|
},
|
|
"Element type of this quantized type expressed as quantized type.");
|
|
c.def(
|
|
"cast_from_storage_type",
|
|
[](QuantizedType &type, const PyType &candidate) {
|
|
MlirType castResult =
|
|
mlirQuantizedTypeCastFromStorageType(type, candidate);
|
|
if (!mlirTypeIsNull(castResult))
|
|
return QuantizedType(type.getContext(), castResult);
|
|
throw nb::type_error("Invalid cast.");
|
|
},
|
|
"Casts from a type based on the storage type of this quantized type to "
|
|
"a "
|
|
"corresponding type based on the quantized type. Raises TypeError if "
|
|
"the "
|
|
"cast is not valid.",
|
|
nb::arg("candidate"));
|
|
c.def_static(
|
|
"cast_to_storage_type",
|
|
[](PyType &type) {
|
|
MlirType castResult = mlirQuantizedTypeCastToStorageType(type);
|
|
if (!mlirTypeIsNull(castResult))
|
|
return PyType(type.getContext(), castResult).maybeDownCast();
|
|
throw nb::type_error("Invalid cast.");
|
|
},
|
|
"Casts from a type based on a quantized type to a corresponding type "
|
|
"based on the storage type of this quantized type. Raises TypeError if "
|
|
"the cast is not valid.",
|
|
nb::arg("type"));
|
|
c.def(
|
|
"cast_from_expressed_type",
|
|
[](QuantizedType &type, const PyType &candidate) {
|
|
MlirType castResult =
|
|
mlirQuantizedTypeCastFromExpressedType(type, candidate);
|
|
if (!mlirTypeIsNull(castResult))
|
|
return PyType(type.getContext(), castResult).maybeDownCast();
|
|
throw nb::type_error("Invalid cast.");
|
|
},
|
|
"Casts from a type based on the expressed type of this quantized type "
|
|
"to "
|
|
"a corresponding type based on the quantized type. Raises TypeError if "
|
|
"the cast is not valid.",
|
|
nb::arg("candidate"));
|
|
c.def_static(
|
|
"cast_to_expressed_type",
|
|
[](PyType &type) {
|
|
MlirType castResult = mlirQuantizedTypeCastToExpressedType(type);
|
|
if (!mlirTypeIsNull(castResult))
|
|
return PyType(type.getContext(), castResult).maybeDownCast();
|
|
throw nb::type_error("Invalid cast.");
|
|
},
|
|
"Casts from a type based on a quantized type to a corresponding type "
|
|
"based on the expressed type of this quantized type. Raises TypeError "
|
|
"if "
|
|
"the cast is not valid.",
|
|
nb::arg("type"));
|
|
c.def(
|
|
"cast_expressed_to_storage_type",
|
|
[](QuantizedType &type, const PyType &candidate) {
|
|
MlirType castResult =
|
|
mlirQuantizedTypeCastExpressedToStorageType(type, candidate);
|
|
if (!mlirTypeIsNull(castResult))
|
|
return PyType(type.getContext(), castResult).maybeDownCast();
|
|
throw nb::type_error("Invalid cast.");
|
|
},
|
|
"Casts from a type based on the expressed type of this quantized type "
|
|
"to "
|
|
"a corresponding type based on the storage type. Raises TypeError if "
|
|
"the "
|
|
"cast is not valid.",
|
|
nb::arg("candidate"));
|
|
}
|
|
};
|
|
|
|
//===-------------------------------------------------------------------===//
|
|
// AnyQuantizedType
|
|
//===-------------------------------------------------------------------===//
|
|
|
|
struct AnyQuantizedType : PyConcreteType<AnyQuantizedType, QuantizedType> {
|
|
static constexpr IsAFunctionTy isaFunction = mlirTypeIsAAnyQuantizedType;
|
|
static constexpr GetTypeIDFunctionTy getTypeIdFunction =
|
|
mlirAnyQuantizedTypeGetTypeID;
|
|
static constexpr const char *pyClassName = "AnyQuantizedType";
|
|
static inline const MlirStringRef name = mlirAnyQuantizedTypeGetName();
|
|
using Base::Base;
|
|
|
|
static void bindDerived(ClassTy &c) {
|
|
c.def_static(
|
|
"get",
|
|
[](unsigned flags, const PyType &storageType,
|
|
const PyType &expressedType, int64_t storageTypeMin,
|
|
int64_t storageTypeMax, DefaultingPyMlirContext context) {
|
|
return AnyQuantizedType(
|
|
context->getRef(),
|
|
mlirAnyQuantizedTypeGet(flags, storageType, expressedType,
|
|
storageTypeMin, storageTypeMax));
|
|
},
|
|
"Gets an instance of AnyQuantizedType in the same context as the "
|
|
"provided storage type.",
|
|
nb::arg("flags"), nb::arg("storage_type"), nb::arg("expressed_type"),
|
|
nb::arg("storage_type_min"), nb::arg("storage_type_max"),
|
|
nb::arg("context") = nb::none());
|
|
}
|
|
};
|
|
|
|
//===-------------------------------------------------------------------===//
|
|
// UniformQuantizedType
|
|
//===-------------------------------------------------------------------===//
|
|
|
|
struct UniformQuantizedType
|
|
: PyConcreteType<UniformQuantizedType, QuantizedType> {
|
|
static constexpr IsAFunctionTy isaFunction = mlirTypeIsAUniformQuantizedType;
|
|
static constexpr GetTypeIDFunctionTy getTypeIdFunction =
|
|
mlirUniformQuantizedTypeGetTypeID;
|
|
static constexpr const char *pyClassName = "UniformQuantizedType";
|
|
static inline const MlirStringRef name = mlirUniformQuantizedTypeGetName();
|
|
using Base::Base;
|
|
|
|
static void bindDerived(ClassTy &c) {
|
|
c.def_static(
|
|
"get",
|
|
[](unsigned flags, const PyType &storageType,
|
|
const PyType &expressedType, double scale, int64_t zeroPoint,
|
|
int64_t storageTypeMin, int64_t storageTypeMax,
|
|
DefaultingPyMlirContext context) {
|
|
return UniformQuantizedType(
|
|
context->getRef(),
|
|
mlirUniformQuantizedTypeGet(flags, storageType, expressedType,
|
|
scale, zeroPoint, storageTypeMin,
|
|
storageTypeMax));
|
|
},
|
|
"Gets an instance of UniformQuantizedType in the same context as the "
|
|
"provided storage type.",
|
|
nb::arg("flags"), nb::arg("storage_type"), nb::arg("expressed_type"),
|
|
nb::arg("scale"), nb::arg("zero_point"), nb::arg("storage_type_min"),
|
|
nb::arg("storage_type_max"), nb::arg("context") = nb::none());
|
|
c.def_prop_ro(
|
|
"scale",
|
|
[](const UniformQuantizedType &type) {
|
|
return mlirUniformQuantizedTypeGetScale(type);
|
|
},
|
|
"The scale designates the difference between the real values "
|
|
"corresponding to consecutive quantized values differing by 1.");
|
|
c.def_prop_ro(
|
|
"zero_point",
|
|
[](const UniformQuantizedType &type) {
|
|
return mlirUniformQuantizedTypeGetZeroPoint(type);
|
|
},
|
|
"The storage value corresponding to the real value 0 in the affine "
|
|
"equation.");
|
|
c.def_prop_ro(
|
|
"is_fixed_point",
|
|
[](const UniformQuantizedType &type) {
|
|
return mlirUniformQuantizedTypeIsFixedPoint(type);
|
|
},
|
|
"Fixed point values are real numbers divided by a scale.");
|
|
}
|
|
};
|
|
|
|
//===-------------------------------------------------------------------===//
|
|
// UniformQuantizedPerAxisType
|
|
//===-------------------------------------------------------------------===//
|
|
|
|
struct UniformQuantizedPerAxisType
|
|
: PyConcreteType<UniformQuantizedPerAxisType, QuantizedType> {
|
|
static constexpr IsAFunctionTy isaFunction =
|
|
mlirTypeIsAUniformQuantizedPerAxisType;
|
|
static constexpr GetTypeIDFunctionTy getTypeIdFunction =
|
|
mlirUniformQuantizedPerAxisTypeGetTypeID;
|
|
static constexpr const char *pyClassName = "UniformQuantizedPerAxisType";
|
|
static inline const MlirStringRef name =
|
|
mlirUniformQuantizedPerAxisTypeGetName();
|
|
using Base::Base;
|
|
|
|
static void bindDerived(ClassTy &c) {
|
|
c.def_static(
|
|
"get",
|
|
[](unsigned flags, const PyType &storageType,
|
|
const PyType &expressedType, std::vector<double> scales,
|
|
std::vector<int64_t> zeroPoints, int32_t quantizedDimension,
|
|
int64_t storageTypeMin, int64_t storageTypeMax,
|
|
DefaultingPyMlirContext context) {
|
|
if (scales.size() != zeroPoints.size())
|
|
throw nb::value_error(
|
|
"Mismatching number of scales and zero points.");
|
|
auto nDims = static_cast<intptr_t>(scales.size());
|
|
return UniformQuantizedPerAxisType(
|
|
context->getRef(),
|
|
mlirUniformQuantizedPerAxisTypeGet(
|
|
flags, storageType, expressedType, nDims, scales.data(),
|
|
zeroPoints.data(), quantizedDimension, storageTypeMin,
|
|
storageTypeMax));
|
|
},
|
|
"Gets an instance of UniformQuantizedPerAxisType in the same context "
|
|
"as "
|
|
"the provided storage type.",
|
|
nb::arg("flags"), nb::arg("storage_type"), nb::arg("expressed_type"),
|
|
nb::arg("scales"), nb::arg("zero_points"),
|
|
nb::arg("quantized_dimension"), nb::arg("storage_type_min"),
|
|
nb::arg("storage_type_max"), nb::arg("context") = nb::none());
|
|
c.def_prop_ro(
|
|
"scales",
|
|
[](const UniformQuantizedPerAxisType &type) {
|
|
intptr_t nDim = mlirUniformQuantizedPerAxisTypeGetNumDims(type);
|
|
std::vector<double> scales;
|
|
scales.reserve(nDim);
|
|
for (intptr_t i = 0; i < nDim; ++i) {
|
|
double scale = mlirUniformQuantizedPerAxisTypeGetScale(type, i);
|
|
scales.push_back(scale);
|
|
}
|
|
return scales;
|
|
},
|
|
"The scales designate the difference between the real values "
|
|
"corresponding to consecutive quantized values differing by 1. The ith "
|
|
"scale corresponds to the ith slice in the quantized_dimension.");
|
|
c.def_prop_ro(
|
|
"zero_points",
|
|
[](const UniformQuantizedPerAxisType &type) {
|
|
intptr_t nDim = mlirUniformQuantizedPerAxisTypeGetNumDims(type);
|
|
std::vector<int64_t> zeroPoints;
|
|
zeroPoints.reserve(nDim);
|
|
for (intptr_t i = 0; i < nDim; ++i) {
|
|
int64_t zeroPoint =
|
|
mlirUniformQuantizedPerAxisTypeGetZeroPoint(type, i);
|
|
zeroPoints.push_back(zeroPoint);
|
|
}
|
|
return zeroPoints;
|
|
},
|
|
"the storage values corresponding to the real value 0 in the affine "
|
|
"equation. The ith zero point corresponds to the ith slice in the "
|
|
"quantized_dimension.");
|
|
c.def_prop_ro(
|
|
"quantized_dimension",
|
|
[](const UniformQuantizedPerAxisType &type) {
|
|
return mlirUniformQuantizedPerAxisTypeGetQuantizedDimension(type);
|
|
},
|
|
"Specifies the dimension of the shape that the scales and zero points "
|
|
"correspond to.");
|
|
c.def_prop_ro(
|
|
"is_fixed_point",
|
|
[](const UniformQuantizedPerAxisType &type) {
|
|
return mlirUniformQuantizedPerAxisTypeIsFixedPoint(type);
|
|
},
|
|
"Fixed point values are real numbers divided by a scale.");
|
|
}
|
|
};
|
|
|
|
//===-------------------------------------------------------------------===//
|
|
// UniformQuantizedSubChannelType
|
|
//===-------------------------------------------------------------------===//
|
|
|
|
struct UniformQuantizedSubChannelType
|
|
: PyConcreteType<UniformQuantizedSubChannelType, QuantizedType> {
|
|
static constexpr IsAFunctionTy isaFunction =
|
|
mlirTypeIsAUniformQuantizedSubChannelType;
|
|
static constexpr GetTypeIDFunctionTy getTypeIdFunction =
|
|
mlirUniformQuantizedSubChannelTypeGetTypeID;
|
|
static constexpr const char *pyClassName = "UniformQuantizedSubChannelType";
|
|
static inline const MlirStringRef name =
|
|
mlirUniformQuantizedSubChannelTypeGetName();
|
|
using Base::Base;
|
|
|
|
static void bindDerived(ClassTy &c) {
|
|
c.def_static(
|
|
"get",
|
|
[](unsigned flags, const PyType &storageType,
|
|
const PyType &expressedType, PyAttribute scales,
|
|
PyAttribute zeroPoints, std::vector<int32_t> quantizedDimensions,
|
|
std::vector<int64_t> blockSizes, int64_t storageTypeMin,
|
|
int64_t storageTypeMax, DefaultingPyMlirContext context) {
|
|
return UniformQuantizedSubChannelType(
|
|
context->getRef(),
|
|
mlirUniformQuantizedSubChannelTypeGet(
|
|
flags, storageType, expressedType, scales, zeroPoints,
|
|
static_cast<intptr_t>(blockSizes.size()),
|
|
quantizedDimensions.data(), blockSizes.data(), storageTypeMin,
|
|
storageTypeMax));
|
|
},
|
|
"Gets an instance of UniformQuantizedSubChannel in the same context as "
|
|
"the provided storage type.",
|
|
nb::arg("flags"), nb::arg("storage_type"), nb::arg("expressed_type"),
|
|
nb::arg("scales"), nb::arg("zero_points"),
|
|
nb::arg("quantized_dimensions"), nb::arg("block_sizes"),
|
|
nb::arg("storage_type_min"), nb::arg("storage_type_max"),
|
|
nb::arg("context") = nb::none());
|
|
c.def_prop_ro(
|
|
"quantized_dimensions",
|
|
[](const UniformQuantizedSubChannelType &type) {
|
|
intptr_t nDim =
|
|
mlirUniformQuantizedSubChannelTypeGetNumBlockSizes(type);
|
|
std::vector<int32_t> quantizedDimensions;
|
|
quantizedDimensions.reserve(nDim);
|
|
for (intptr_t i = 0; i < nDim; ++i) {
|
|
quantizedDimensions.push_back(
|
|
mlirUniformQuantizedSubChannelTypeGetQuantizedDimension(type,
|
|
i));
|
|
}
|
|
return quantizedDimensions;
|
|
},
|
|
"Gets the quantized dimensions. Each element in the returned list "
|
|
"represents an axis of the quantized data tensor that has a specified "
|
|
"block size. The order of elements corresponds to the order of block "
|
|
"sizes returned by 'block_sizes' method. It means that the data tensor "
|
|
"is quantized along the i-th dimension in the returned list using the "
|
|
"i-th block size from block_sizes method.");
|
|
c.def_prop_ro(
|
|
"block_sizes",
|
|
[](const UniformQuantizedSubChannelType &type) {
|
|
intptr_t nDim =
|
|
mlirUniformQuantizedSubChannelTypeGetNumBlockSizes(type);
|
|
std::vector<int64_t> blockSizes;
|
|
blockSizes.reserve(nDim);
|
|
for (intptr_t i = 0; i < nDim; ++i) {
|
|
blockSizes.push_back(
|
|
mlirUniformQuantizedSubChannelTypeGetBlockSize(type, i));
|
|
}
|
|
return blockSizes;
|
|
},
|
|
"Gets the block sizes for the quantized dimensions. The i-th element "
|
|
"in "
|
|
"the returned list corresponds to the block size for the i-th "
|
|
"dimension "
|
|
"in the list returned by quantized_dimensions method.");
|
|
c.def_prop_ro(
|
|
"scales",
|
|
[](UniformQuantizedSubChannelType &type) {
|
|
return PyDenseElementsAttribute(
|
|
type.getContext(),
|
|
mlirUniformQuantizedSubChannelTypeGetScales(type));
|
|
},
|
|
"The scales of the quantized type.");
|
|
c.def_prop_ro(
|
|
"zero_points",
|
|
[](UniformQuantizedSubChannelType &type) {
|
|
return PyDenseElementsAttribute(
|
|
type.getContext(),
|
|
mlirUniformQuantizedSubChannelTypeGetZeroPoints(type));
|
|
},
|
|
"The zero points of the quantized type.");
|
|
}
|
|
};
|
|
|
|
//===-------------------------------------------------------------------===//
|
|
// CalibratedQuantizedType
|
|
//===-------------------------------------------------------------------===//
|
|
|
|
struct CalibratedQuantizedType
|
|
: PyConcreteType<CalibratedQuantizedType, QuantizedType> {
|
|
static constexpr IsAFunctionTy isaFunction =
|
|
mlirTypeIsACalibratedQuantizedType;
|
|
static constexpr GetTypeIDFunctionTy getTypeIdFunction =
|
|
mlirCalibratedQuantizedTypeGetTypeID;
|
|
static constexpr const char *pyClassName = "CalibratedQuantizedType";
|
|
static inline const MlirStringRef name = mlirCalibratedQuantizedTypeGetName();
|
|
using Base::Base;
|
|
|
|
static void bindDerived(ClassTy &c) {
|
|
c.def_static(
|
|
"get",
|
|
[](const PyType &expressedType, double min, double max,
|
|
DefaultingPyMlirContext context) {
|
|
return CalibratedQuantizedType(
|
|
context->getRef(),
|
|
mlirCalibratedQuantizedTypeGet(expressedType, min, max));
|
|
},
|
|
"Gets an instance of CalibratedQuantizedType in the same context as "
|
|
"the "
|
|
"provided expressed type.",
|
|
nb::arg("expressed_type"), nb::arg("min"), nb::arg("max"),
|
|
nb::arg("context") = nb::none());
|
|
c.def_prop_ro("min", [](const PyType &type) {
|
|
return mlirCalibratedQuantizedTypeGetMin(type);
|
|
});
|
|
c.def_prop_ro("max", [](const PyType &type) {
|
|
return mlirCalibratedQuantizedTypeGetMax(type);
|
|
});
|
|
}
|
|
};
|
|
|
|
static void populateDialectQuantSubmodule(nb::module_ &m) {
|
|
QuantizedType::bind(m);
|
|
|
|
// Set the FLAG_SIGNED class attribute after binding QuantizedType
|
|
auto quantizedTypeClass = m.attr("QuantizedType");
|
|
quantizedTypeClass.attr("FLAG_SIGNED") = mlirQuantizedTypeGetSignedFlag();
|
|
|
|
AnyQuantizedType::bind(m);
|
|
UniformQuantizedType::bind(m);
|
|
UniformQuantizedPerAxisType::bind(m);
|
|
UniformQuantizedSubChannelType::bind(m);
|
|
CalibratedQuantizedType::bind(m);
|
|
}
|
|
} // namespace quant
|
|
} // namespace MLIR_BINDINGS_PYTHON_DOMAIN
|
|
} // namespace python
|
|
} // namespace mlir
|
|
|
|
NB_MODULE(_mlirDialectsQuant, m) {
|
|
m.doc() = "MLIR Quantization dialect";
|
|
|
|
mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::quant::
|
|
populateDialectQuantSubmodule(m);
|
|
}
|