26double getMinScale(
Type expressedType) {
27 auto floatType = cast<FloatType>(expressedType);
28 return APFloat::getSmallest(floatType.getFloatSemantics()).convertToDouble();
32double getMaxScale(
Type expressedType) {
33 auto floatType = cast<FloatType>(expressedType);
34 return APFloat::getLargest(floatType.getFloatSemantics()).convertToDouble();
51 unsigned flags,
Type storageType,
54 if (
auto quantStorageTypeInterface =
55 llvm::dyn_cast<QuantStorageTypeInterface>(storageType)) {
56 unsigned integralWidth = quantStorageTypeInterface.getStorageWidth();
60 return emitError() <<
"illegal storage type size: " << integralWidth;
63 int64_t defaultMin = quantStorageTypeInterface.getDefaultMinimum(
isSigned);
64 int64_t defaultMax = quantStorageTypeInterface.getDefaultMaximum(
isSigned);
66 if (storageTypeMax - storageTypeMin <= 0 || storageTypeMin < defaultMin ||
67 storageTypeMax > defaultMax) {
68 return emitError() <<
"illegal storage min and storage max: ("
69 << storageTypeMin <<
":" << storageTypeMax <<
")";
75 return emitError() <<
"storage type must implement QuantStorageTypeInterface";
92 auto quantStorageTypeInterface =
93 llvm::dyn_cast<QuantStorageTypeInterface>(storageType);
95 int64_t defaultMin = quantStorageTypeInterface.getDefaultMinimum(
isSigned());
96 int64_t defaultMax = quantStorageTypeInterface.getDefaultMaximum(
isSigned());
103 auto quantStorageTypeInterface =
104 llvm::dyn_cast<QuantStorageTypeInterface>(storageType);
106 return quantStorageTypeInterface.getStorageWidth();
114 if (llvm::isa<ShapedType>(candidateExpressedType)) {
115 return llvm::cast<ShapedType>(candidateExpressedType).getElementType() ==
123 if (llvm::isa<ShapedType>(primitiveOrContainerType)) {
125 llvm::cast<ShapedType>(primitiveOrContainerType).getElementType();
126 return llvm::dyn_cast<QuantizedType>(elementType);
128 return llvm::dyn_cast<QuantizedType>(primitiveOrContainerType);
136 if (llvm::isa<RankedTensorType>(candidateType)) {
138 return RankedTensorType::get(
139 llvm::cast<RankedTensorType>(candidateType).
getShape(),
142 if (llvm::isa<UnrankedTensorType>(candidateType)) {
146 if (llvm::isa<VectorType>(candidateType)) {
148 return VectorType::get(llvm::cast<VectorType>(candidateType).
getShape(),
156 if (llvm::isa<QuantizedType>(quantizedType)) {
158 return llvm::cast<QuantizedType>(quantizedType).getStorageType();
160 if (llvm::isa<ShapedType>(quantizedType)) {
162 ShapedType sType = llvm::cast<ShapedType>(quantizedType);
163 if (!llvm::isa<QuantizedType>(sType.getElementType())) {
167 llvm::cast<QuantizedType>(sType.getElementType()).getStorageType();
168 if (llvm::isa<RankedTensorType>(quantizedType)) {
169 return RankedTensorType::get(sType.getShape(), storageType);
171 if (llvm::isa<UnrankedTensorType>(quantizedType)) {
172 return UnrankedTensorType::get(storageType);
174 if (llvm::isa<VectorType>(quantizedType)) {
175 return VectorType::get(sType.getShape(), storageType);
187 if (llvm::isa<ShapedType>(candidateType)) {
188 ShapedType candidateShapedType = llvm::cast<ShapedType>(candidateType);
193 if (llvm::isa<RankedTensorType>(candidateType)) {
195 return RankedTensorType::get(candidateShapedType.getShape(), *
this);
197 if (llvm::isa<UnrankedTensorType>(candidateType)) {
199 return UnrankedTensorType::get(*
this);
201 if (llvm::isa<VectorType>(candidateType)) {
203 return VectorType::get(candidateShapedType.getShape(), *
this);
211 if (llvm::isa<QuantizedType>(quantizedType)) {
213 return llvm::cast<QuantizedType>(quantizedType).getExpressedType();
215 if (llvm::isa<ShapedType>(quantizedType)) {
217 ShapedType sType = llvm::cast<ShapedType>(quantizedType);
218 if (!llvm::isa<QuantizedType>(sType.getElementType())) {
222 llvm::cast<QuantizedType>(sType.getElementType()).getExpressedType();
223 if (llvm::isa<RankedTensorType>(quantizedType)) {
224 return RankedTensorType::get(sType.getShape(), expressedType);
226 if (llvm::isa<UnrankedTensorType>(quantizedType)) {
227 return UnrankedTensorType::get(expressedType);
229 if (llvm::isa<VectorType>(quantizedType)) {
230 return VectorType::get(sType.getShape(), expressedType);
239 if (!expressedQuantizedType) {
250 storageTypeMin, storageTypeMax);
255 unsigned flags,
Type storageType,
259 storageType, expressedType, storageTypeMin,
265 unsigned flags,
Type storageType,
269 expressedType, storageTypeMin,
277 if (expressedType && !llvm::isa<FloatType>(expressedType))
278 return emitError() <<
"expressed type must be floating point";
284 Type expressedType,
double scale,
289 scale, zeroPoint, storageTypeMin, storageTypeMax);
297 storageType, expressedType, scale, zeroPoint,
298 storageTypeMin, storageTypeMax);
306 expressedType, storageTypeMin,
314 return emitError() <<
"uniform quantization requires expressed type";
319 if (!llvm::isa<FloatType>(expressedType))
320 return emitError() <<
"expressed type must be floating point";
323 double minScale = getMinScale(expressedType);
324 double maxScale = getMaxScale(expressedType);
325 if (scale < minScale || scale > maxScale)
326 return emitError() <<
"scale out of expressed type range [" << minScale
327 <<
", " << maxScale <<
"]";
339 unsigned flags,
Type storageType,
Type expressedType,
341 int32_t quantizedDimension,
int64_t storageTypeMin,
344 scales, zeroPoints, quantizedDimension, storageTypeMin,
354 storageType, expressedType, scales, zeroPoints,
355 quantizedDimension, storageTypeMin, storageTypeMax);
364 expressedType, storageTypeMin,
372 return emitError() <<
"uniform quantization requires expressed type";
377 if (!llvm::isa<FloatType>(expressedType))
378 return emitError() <<
"expressed type must be floating point";
381 if (scales.size() != zeroPoints.size())
382 return emitError() <<
"illegal number of scales and zeroPoints: "
383 << scales.size() <<
", " << zeroPoints.size();
386 double minScale = getMinScale(expressedType);
387 double maxScale = getMaxScale(expressedType);
388 for (
double scale : scales) {
389 if (scale < minScale || scale > maxScale)
390 return emitError() <<
"scale out of expressed type range [" << minScale
391 <<
", " << maxScale <<
"]";
395 if (quantizedDimension < 0)
396 return emitError() <<
"illegal quantized dimension: " << quantizedDimension;
406 return getImpl()->getZeroPoints();
410 return getImpl()->quantizedDimension;
414 unsigned flags,
Type storageType,
Type expressedType,
419 scales, zeroPoints, quantizedDimensions, blockSizes,
420 storageTypeMin, storageTypeMax);
430 storageType, expressedType, scales, zeroPoints,
431 quantizedDimensions, blockSizes, storageTypeMin,
442 expressedType, storageTypeMin,
450 return emitError() <<
"uniform quantization requires expressed type";
455 if (!llvm::isa<FloatType>(expressedType))
456 return emitError() <<
"expressed type must be floating point";
459 if (scales.
getType().getElementType() != expressedType) {
460 return emitError() <<
"type of scale values "
461 << scales.
getType().getElementType()
462 <<
" must match the expressed type " << expressedType;
466 if (zeroPoints.
getType().getElementType() != storageType) {
467 return emitError() <<
"type of zero point values "
468 << zeroPoints.
getType().getElementType()
469 <<
" must match the storage type " << storageType;
473 if (scales.
getType().getShape() != zeroPoints.
getType().getShape())
474 return emitError() <<
"shape of scales and zeroPoints ("
475 << scales.
getType().getShape() <<
" vs "
476 << zeroPoints.
getType().getShape() <<
") does not match";
479 if (quantizedDimensions.size() != blockSizes.size())
480 return emitError() <<
"number of quantized dimensions and block sizes ("
481 << scales.
size() <<
" vs " << zeroPoints.
size()
482 <<
") does not match";
485 for (
auto quantizedDimension : quantizedDimensions) {
486 if (quantizedDimension < 0)
487 return emitError() <<
"illegal quantized dimension: "
488 << quantizedDimension;
492 for (
auto blockSize : blockSizes) {
494 return emitError() <<
"illegal block size: " << blockSize;
505 return getImpl()->getZeroPoints();
510 return getImpl()->getQuantizedDimensions();
514 return getImpl()->getBlockSizes();
522 for (
auto [dim, size] :
524 result.push_back({dim, size});
548 if (!llvm::isa<FloatType>(expressedType))
549 return emitError() <<
"expressed type must be floating point";
551 return emitError() <<
"illegal min and max: (" <<
min <<
":" <<
max <<
")";
563 std::optional<int64_t> storageMin,
564 std::optional<int64_t> storageMax) {
565 return Base::get(ctx, storageType, quantileType, quantiles, storageMin,
572 std::optional<int64_t> storageMin, std::optional<int64_t> storageMax) {
574 storageMin, storageMax);
580 std::optional<int64_t> storageMin, std::optional<int64_t> storageMax) {
582 return emitError() <<
"storage type must be an integer or float type";
583 if (!llvm::isa<mlir::FloatType>(quantileType) &&
584 !llvm::isa<mlir::IntegerType>(quantileType))
585 return emitError() <<
"quantile type must be a float or integer type";
586 if (quantiles.empty())
587 return emitError() <<
"quantile values must not be empty";
588 if (storageMin.has_value() != storageMax.has_value())
590 <<
"storage min and max must both be specified or both omitted";
591 if (storageMin && storageMax && *storageMin >= *storageMax)
592 return emitError() <<
"storage min must be less than storage max";
595 bool isSigned = !llvm::isa<mlir::IntegerType>(storageType) ||
596 llvm::cast<mlir::IntegerType>(storageType).isSigned();
598 storageMin.value_or(isSigned ? -(1LL << (width - 1)) : 0LL);
599 auto effectiveMax = storageMax.value_or(isSigned ? (1LL << (width - 1)) - 1
600 : (1LL << width) - 1);
601 auto expectedSize = effectiveMax - effectiveMin + 1;
602 if (
static_cast<decltype(expectedSize)
>(quantiles.size()) != expectedSize)
603 return emitError() <<
"quantile LUT size (" << quantiles.size()
604 <<
") must equal the number of representable storage "
606 << expectedSize <<
")";
608 for (
double v : quantiles)
609 if (std::isnan(v) || std::isinf(v))
611 <<
"quantile values must be finite (no NaN or infinity)";
641 if (
auto intType = mlir::dyn_cast<mlir::IntegerType>(
getStorageType()))
642 return intType.isSigned();
668 std::string
result =
"!quant.quantile<";
669 llvm::raw_string_ostream os(
result);
673 llvm::seq<size_t>(0, quantiles.size()), os,
674 [&](
size_t index) { os << quantiles[index]; },
",");
678 os <<
", <" << *minVal <<
":" << *maxVal <<
">";
690 return width > 0 ? 8 / width : 0;
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
An attribute that represents a reference to a dense vector or tensor object.
int64_t size() const
Returns the number of elements held by this attribute.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
This class represents a diagnostic that is inflight and set to be reported.
MLIRContext is the top-level object for a collection of MLIR operations.
static TypeID get()
Construct a type info object for the given type T.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
TypeID getTypeID()
Return a unique identifier for the concrete type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
static ConcreteType get(MLIRContext *ctx, Args &&...args)
static ConcreteType getChecked(const Location &loc, Args &&...args)
ImplType * getImpl() const
A quantized type that maps storage to/from expressed types in an unspecified way.
static AnyQuantizedType get(unsigned flags, Type storageType, Type expressedType, int64_t storageTypeMin, int64_t storageTypeMax)
Gets an instance of the type with all parameters specified but not checked.
static LogicalResult verifyInvariants(function_ref< InFlightDiagnostic()> emitError, unsigned flags, Type storageType, Type expressedType, int64_t storageTypeMin, int64_t storageTypeMax)
Verifies construction invariants and issues errors/warnings.
static AnyQuantizedType getChecked(function_ref< InFlightDiagnostic()> emitError, unsigned flags, Type storageType, Type expressedType, int64_t storageTypeMin, int64_t storageTypeMax)
Gets an instance of the type with all specified parameters checked.
A quantized type that infers its range from given min/max values.
static LogicalResult verifyInvariants(function_ref< InFlightDiagnostic()> emitError, Type expressedType, double min, double max)
Verifies construction invariants and issues errors/warnings.
static CalibratedQuantizedType get(Type expressedType, double min, double max)
Gets an instance of the type with all parameters specified but not checked.
static CalibratedQuantizedType getChecked(function_ref< InFlightDiagnostic()> emitError, Type expressedType, double min, double max)
Gets an instance of the type with all specified parameters checked.
unsigned getLogicalBitWidth() const
static QuantileType getChecked(function_ref< InFlightDiagnostic()> emitError, mlir::MLIRContext *ctx, Type storageType, Type quantileType, ArrayRef< double > quantiles, std::optional< int64_t > storageMin=std::nullopt, std::optional< int64_t > storageMax=std::nullopt)
static bool classof(mlir::Type type)
Methods for support type inquiry through isa, cast, and dyn_cast.
unsigned getStorageWidth() const
std::optional< int64_t > getStorageMin() const
Return the explicit storage minimum, if set.
int64_t getDefaultMinimum(bool isSigned) const
unsigned getElementsPerByte() const
std::string getStorageTypeName(bool isSigned) const
detail::QuantileTypeStorage ImplType
bool shouldDefaultToSigned() const
Type getQuantileType() const
int64_t getDefaultMaximum(bool isSigned) const
static QuantileType get(mlir::MLIRContext *ctx, Type storageType, Type quantileType, ArrayRef< double > quantiles={}, std::optional< int64_t > storageMin=std::nullopt, std::optional< int64_t > storageMax=std::nullopt)
ArrayRef< double > getQuantiles() const
Return the quantile table of this float type.
std::optional< unsigned > getPreferredAlignmentBytes() const
static LogicalResult verifyInvariants(function_ref< InFlightDiagnostic()> emitError, Type storageType, Type quantileType, ArrayRef< double > quantiles, std::optional< int64_t > storageMin, std::optional< int64_t > storageMax)
std::optional< int64_t > getStorageMax() const
Return the explicit storage maximum, if set.
Type getStorageType() const
Base class for all quantized types known to this dialect.
Type getExpressedType() const
Gets the original expressed type that this quantized type approximates.
static constexpr unsigned MaxStorageBits
The maximum number of bits supported for storage types.
bool hasStorageTypeBounds() const
Return whether the storage type has explicit min or max boundaries different from the minimum and max...
static Type castToStorageType(Type quantizedType)
Casts from a type based on a QuantizedType to a corresponding type based on the storageType (returns ...
Type castExpressedToStorageType(Type candidateType)
Casts from a type based on the expressedType to the equivalent type based on storageType by way of th...
detail::QuantizedTypeStorage ImplType
static Type castToExpressedType(Type quantizedType)
Casts from a type based on QuantizedType to a corresponding type based on the expressedType (returns ...
bool isSigned() const
Whether the storage type should be interpreted as a signed quantity (true) or an unsigned value (fals...
static QuantizedType getQuantizedElementType(Type primitiveOrContainerType)
Returns the element type as a QuantizedType or nullptr if it is not a quantized type.
unsigned getFlags() const
Gets the flags associated with this type.
int64_t getStorageTypeMax() const
The maximum value that storageType can take.
unsigned getStorageTypeIntegralWidth() const
Gets the integral bit width that the underlying storage type can exactly represent.
static bool classof(Type type)
Support method to enable LLVM-style type casting.
Type castFromStorageType(Type candidateType)
Casts from a type based on the storageType to a corresponding type based on this type (returns nullpt...
int64_t getStorageTypeMin() const
The minimum value that storageType can take.
Type getStorageType() const
Gets the underlying type used for to store values.
Type castFromExpressedType(Type candidateType)
Casts from a type based on the expressedType to a corresponding type based on this type (returns null...
bool isCompatibleExpressedType(Type candidateExpressedType)
Returns whether the candidateExpressedType is a match for this QuantizedType.
static LogicalResult verifyInvariants(function_ref< InFlightDiagnostic()> emitError, unsigned flags, Type storageType, Type expressedType, int64_t storageTypeMin, int64_t storageTypeMax)
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::function_ref< Fn > function_ref