MLIR 24.0.0git
UniformSupport.h
Go to the documentation of this file.
1//===- UniformSupport.h - Support utilities for uniform quant ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef MLIR_DIALECT_QUANT_UTILS_UNIFORMSUPPORT_H_
10#define MLIR_DIALECT_QUANT_UTILS_UNIFORMSUPPORT_H_
11
12#include <cmath>
13#include <utility>
14
17#include "mlir/IR/Types.h"
18#include "llvm/ADT/APFloat.h"
19#include "llvm/ADT/APInt.h"
20#include "llvm/ADT/APSInt.h"
21
22namespace mlir {
23namespace quant {
24
25/// Performs type conversion from an arbitrary input type to a type
26/// that is expressed by a QuantizedType.
27///
28/// This handles cases where the inputType is a supported primitive type
29/// (i.e. f32, bf16, etc) or a vector/tensor type based on a supported
30/// elemental type.
31///
32/// Since conversion often involves introspecting some attributes of the
33/// input type in order to determine how to represent it, this is a two step
34/// process.
36 /// Creates a converter for the given input type.
38
39 /// Converts the inputType to be based on the given elemental type,
40 /// returning the new type (or nullptr and emit an error on failure).
41 Type convert(QuantizedType elementalType) const;
42
43 /// Whether the conversion is legal.
44 explicit operator bool() const { return (bool)expressedType; }
45
46 /// The input type that is being converted from.
47 /// This may be an elemental or composite type.
49
50 /// Supported, elemental expressed type (i.e. f32).
51 /// Will be nullptr if conversion is not supported.
53};
54
55/// Reference implementation of converting between real numbers and values
56/// represented by a UniformQuantizedType.
57/// Note that this is not expected to be speedy and may be superseded eventually
58/// by a more optimal implementation.
59/// Also, the interface assumes that quantization is done per-layer and will
60/// need to be wider for various per-channel schemes. As such, this is a
61/// placeholder.
63public:
66 uniformType.getScale(),
67 static_cast<double>(uniformType.getZeroPoint()),
68 static_cast<double>(uniformType.getStorageTypeMin()),
69 static_cast<double>(uniformType.getStorageTypeMax()),
70 uniformType.getStorageTypeIntegralWidth(), uniformType.isSigned()) {
71 assert(isa<FloatType>(uniformType.getExpressedType()));
72 assert(uniformType.getStorageType().isSignlessInteger());
73 }
74
75 UniformQuantizedValueConverter(double scale, double zeroPoint,
76 double clampMin, double clampMax,
77 uint32_t storageBitWidth, bool isSigned)
78 : scale(scale), zeroPoint(zeroPoint), clampMin(clampMin),
79 clampMax(clampMax), scaleDouble(scale), zeroPointDouble(zeroPoint),
80 clampMinDouble(clampMin), clampMaxDouble(clampMax),
81 storageBitWidth(storageBitWidth), isSigned(isSigned),
82 roundMode(APFloat::rmNearestTiesToAway) {}
83
84 UniformQuantizedValueConverter(double scale, double zeroPoint,
85 const APFloat &clampMin,
86 const APFloat &clampMax,
87 uint32_t storageBitWidth, bool isSigned)
88 : scale(scale), zeroPoint(zeroPoint), clampMin(clampMin),
89 clampMax(clampMax), scaleDouble(scale), zeroPointDouble(zeroPoint),
90 clampMinDouble(clampMin.convertToDouble()),
91 clampMaxDouble(clampMax.convertToDouble()),
92 storageBitWidth(storageBitWidth), isSigned(isSigned),
93 roundMode(APFloat::rmNearestTiesToAway) {}
94
95 virtual APInt quantizeFloatToInt(APFloat expressedValue) const {
96 // This function is a performance critical code path in quantization
97 // since it runs for each single float parameter value.
98
99 // Specialize f32->u8/i8 case to optimize performance.
100 if (&expressedValue.getSemantics() == &APFloat::IEEEsingle() &&
101 storageBitWidth == 8 &&
102 roundMode == llvm::APFloatBase::rmNearestTiesToAway) {
103 return quantizeF32ToInt8(expressedValue);
104 }
105
106 bool lossy;
107 expressedValue.convert(scale.getSemantics(), roundMode, &lossy);
108 // fixedpoint = clamp(clampMin, clampMax, (
109 // roundHalfToEven(expressed / scale) + zeroPoint))
110 APFloat scaled = (expressedValue / scale);
111 scaled.roundToIntegral(roundMode);
112 scaled.add(zeroPoint, roundMode);
113 APFloat fixedpoint = llvm::minimum(scaled, clampMax);
114 fixedpoint = llvm::maximum(fixedpoint, clampMin);
115
116 llvm::APSInt result(storageBitWidth, !isSigned);
117 fixedpoint.convertToInteger(result, roundMode, &lossy);
118
119 return std::move(result);
120 }
121
122 int64_t quantizeFloatToInt64(APFloat expressedValue) const {
123 APInt qValue = quantizeFloatToInt(std::move(expressedValue));
124 return isSigned ? qValue.getSExtValue() : qValue.getZExtValue();
125 }
126
128
129private:
130 // An optimized implementation to quantize f32 to i8/u8 with C++ native
131 // arithmetic.
132 virtual APInt quantizeF32ToInt8(APFloat expressedValue) const {
133 assert(&expressedValue.getSemantics() == &APFloat::IEEEsingle());
134 assert(storageBitWidth == 8);
135 assert(roundMode == llvm::APFloatBase::rmNearestTiesToAway);
136
137 const float realValue = expressedValue.convertToFloat();
138
139 const double scaled = realValue / scaleDouble + zeroPointDouble;
140 // Round to nearest integer with halfway cases rounded away from zero.
141 const double scaledRounded = std::round(scaled);
142 const double clamped =
143 std::min(std::max(scaledRounded, clampMinDouble), clampMaxDouble);
144
145 uint64_t signlessResult;
146 if (isSigned) {
147 int64_t clampedInt = static_cast<int8_t>(clamped);
148 memcpy(&signlessResult, &clampedInt, sizeof(clampedInt));
149 } else {
150 signlessResult = static_cast<uint8_t>(clamped);
151 }
152 return APInt(storageBitWidth, signlessResult);
153 }
154
155 // Keep both APFloat and double versions of the quantization parameters
156 // around since they will be used in generic and specialized arithmetic,
157 // respectively.
158 const APFloat scale;
159 const APFloat zeroPoint;
160 const APFloat clampMin;
161 const APFloat clampMax;
162
163 const double scaleDouble;
164 const double zeroPointDouble;
165 const double clampMinDouble;
166 const double clampMaxDouble;
167
168 const uint32_t storageBitWidth;
169 const bool isSigned;
170 const llvm::APFloat::roundingMode roundMode;
171};
172
173/// An utility class to quantize an attribute by the per-axis quantization
174/// parameters. The size of the quantization dim in the converted elements
175/// attribute should match the size of scales/zeroPoints vectors in the
176/// quantization parameters.
178public:
180 UniformQuantizedPerAxisType uniformType)
181 : scales(uniformType.getScales()),
182 zeroPoints(uniformType.getZeroPoints()),
183 clampMin(static_cast<double>(uniformType.getStorageTypeMin())),
184 clampMax(static_cast<double>(uniformType.getStorageTypeMax())),
185 storageBitWidth(uniformType.getStorageTypeIntegralWidth()),
186 isSigned(uniformType.isSigned()),
187 quantizationDim(uniformType.getQuantizedDimension()) {
188 assert(isa<FloatType>(uniformType.getExpressedType()));
189 assert(uniformType.getStorageType().isSignlessInteger());
190 assert(scales.size() == zeroPoints.size());
191 }
192
193 /// Quantize an Attribute by the quantization parameters. Return nullptr if
194 /// the conversion fails or the input array isn't an ElementsAttr.
195 ElementsAttr convert(Attribute realValue);
196
197private:
198 /// Quantize an DenseFPElementsAttr by the quantization parameters.
200
201 /// Get a uniform converter for the index-th chunk along the quantizationDim.
202 /// All the elements in this chunk is quantized by the returned converter.
203 UniformQuantizedValueConverter getPerChunkConverter(int index) const {
204 UniformQuantizedValueConverter converter(scales[index], zeroPoints[index],
205 clampMin, clampMax,
206 storageBitWidth, isSigned);
207 return converter;
208 }
209
210 const ArrayRef<double> scales;
211 const ArrayRef<int64_t> zeroPoints;
212 const APFloat clampMin;
213 const APFloat clampMax;
214 const uint32_t storageBitWidth;
215 const bool isSigned;
216 int32_t quantizationDim;
217};
218
219} // namespace quant
220} // namespace mlir
221
222#endif // MLIR_DIALECT_QUANT_UTILS_UNIFORMSUPPORT_H_
static FailureOr< int64_t > getZeroPoint(Value val, bool signExtend)
Definition TosaOps.cpp:3386
Attributes are known-constant values of operations.
Definition Attributes.h:25
An attribute that represents a reference to a dense vector or tensor object.
An attribute that represents a reference to a dense float vector or tensor object.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
Base class for all quantized types known to this dialect.
Definition QuantTypes.h:51
Represents per-axis (also known as per-channel quantization).
Definition QuantTypes.h:325
ElementsAttr convert(Attribute realValue)
Quantize an Attribute by the quantization parameters.
UniformQuantizedPerAxisValueConverter(UniformQuantizedPerAxisType uniformType)
Represents a family of uniform, quantized types.
Definition QuantTypes.h:265
Reference implementation of converting between real numbers and values represented by a UniformQuanti...
UniformQuantizedValueConverter(double scale, double zeroPoint, const APFloat &clampMin, const APFloat &clampMax, uint32_t storageBitWidth, bool isSigned)
int64_t quantizeFloatToInt64(APFloat expressedValue) const
virtual APInt quantizeFloatToInt(APFloat expressedValue) const
UniformQuantizedValueConverter(double scale, double zeroPoint, double clampMin, double clampMax, uint32_t storageBitWidth, bool isSigned)
UniformQuantizedValueConverter(UniformQuantizedType uniformType)
Include the generated interface declarations.
Performs type conversion from an arbitrary input type to a type that is expressed by a QuantizedType.
static ExpressedToQuantizedConverter forInputType(Type inputType)
Creates a converter for the given input type.
const Type inputType
The input type that is being converted from.
Type convert(QuantizedType elementalType) const
Converts the inputType to be based on the given elemental type, returning the new type (or nullptr an...
const Type expressedType
Supported, elemental expressed type (i.e.