xref: /llvm-project/mlir/lib/Dialect/Tosa/Utils/QuantUtils.cpp (revision 3745e7080746b73377a479b6ceba2dbf25f245e2)
1b2812113SSuraj Sudhir //===- QuantUtils.cpp -----------------------------------------------------===//
2b2812113SSuraj Sudhir //
3b2812113SSuraj Sudhir // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b2812113SSuraj Sudhir // See https://llvm.org/LICENSE.txt for license information.
5b2812113SSuraj Sudhir // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b2812113SSuraj Sudhir //
7b2812113SSuraj Sudhir //===----------------------------------------------------------------------===//
8b2812113SSuraj Sudhir //
9b2812113SSuraj Sudhir // This file contains TOSA numerical support functions and quantization
10b2812113SSuraj Sudhir // attribute builders.
11b2812113SSuraj Sudhir //
12b2812113SSuraj Sudhir //===----------------------------------------------------------------------===//
13b2812113SSuraj Sudhir 
14b2812113SSuraj Sudhir #include "mlir/Dialect/Tosa/Utils/QuantUtils.h"
15b2812113SSuraj Sudhir 
16b2812113SSuraj Sudhir using namespace mlir;
17b2812113SSuraj Sudhir using namespace mlir::tosa;
18b2812113SSuraj Sudhir 
19b2812113SSuraj Sudhir /// From a scale value, generates multiplier and shift values where
20b2812113SSuraj Sudhir /// mantissa is in [-1.0,-0.5] or [0.5, 1.0] such that
21b2812113SSuraj Sudhir /// multiplier = mantissa*2^shift for 16-bit scaling.
computeMultiplierAndShiftTosaScale16(double scale,int32_t & multiplier,int32_t & shift)22ac3587f2SStella Laurenzo static void computeMultiplierAndShiftTosaScale16(double scale,
23ac3587f2SStella Laurenzo                                                  int32_t &multiplier,
24b2812113SSuraj Sudhir                                                  int32_t &shift) {
25b2812113SSuraj Sudhir 
26b2812113SSuraj Sudhir   const double mantissa = std::frexp(scale, &shift);
27b2812113SSuraj Sudhir   auto shiftedM = std::round(mantissa * (int64_t(1) << 15));
28b2812113SSuraj Sudhir 
29b2812113SSuraj Sudhir   // Can't be greater than 1.0.
30b2812113SSuraj Sudhir   assert(shiftedM <= (int64_t(1) << 15) &&
31b2812113SSuraj Sudhir          "Shifted mantissa exceeds 16 signed bits");
32b2812113SSuraj Sudhir 
33b2812113SSuraj Sudhir   if (shiftedM == (int64_t(1) << 15)) {
34b2812113SSuraj Sudhir     shiftedM /= 2;
35b2812113SSuraj Sudhir     shift++;
36b2812113SSuraj Sudhir   }
37b2812113SSuraj Sudhir 
38b2812113SSuraj Sudhir   // TOSA expects right shift to be positive and embed (1 << 15) into right
39b2812113SSuraj Sudhir   // shift bits.
40b2812113SSuraj Sudhir   shift = (-shift) + 15;
41b2812113SSuraj Sudhir 
42b2812113SSuraj Sudhir   assert(shiftedM <= std::numeric_limits<int32_t>::max() &&
43b2812113SSuraj Sudhir          "Shifted mantissa exceeds 32-bit signed output type");
44b2812113SSuraj Sudhir 
45b2812113SSuraj Sudhir   multiplier = static_cast<int32_t>(shiftedM);
460763f122SRob Suderman 
47a383a481SPeng Sun   // Shifting tops out at 62 bits. Right shift to make 62 bits the max.
48a383a481SPeng Sun   // The limit of 62 on shift allows the shift to be decomposed as
49a383a481SPeng Sun   // two right shifts of 31.
50a383a481SPeng Sun   if (shift > 62) {
51cd2d7369SRob Suderman     // Shifting the multiplier by more than 31-bits is unnecessary.
52a383a481SPeng Sun     multiplier = multiplier >> std::min<int32_t>(31, shift - 62);
53a383a481SPeng Sun     shift = 62;
540763f122SRob Suderman   }
55b2812113SSuraj Sudhir }
56b2812113SSuraj Sudhir 
57b2812113SSuraj Sudhir /// From a scale value, generates multiplier and shift values where
58b2812113SSuraj Sudhir /// mantissa is in [-1.0,-0.5] or [0.5, 1.0] such that
59b2812113SSuraj Sudhir /// multiplier = mantissa*2^shift for 32-bit scaling.
computeMultiplierAndShiftTosaScale32(double scale,int32_t & multiplier,int32_t & shift)60ac3587f2SStella Laurenzo static void computeMultiplierAndShiftTosaScale32(double scale,
61ac3587f2SStella Laurenzo                                                  int32_t &multiplier,
62b2812113SSuraj Sudhir                                                  int32_t &shift) {
63b2812113SSuraj Sudhir 
64b2812113SSuraj Sudhir   const double mantissa = std::frexp(scale, &shift);
65b2812113SSuraj Sudhir   auto shiftedM = std::round(mantissa * (int64_t(1) << 31));
66b2812113SSuraj Sudhir 
67b2812113SSuraj Sudhir   // Can't be greater than 1.0.
68b2812113SSuraj Sudhir   assert(shiftedM <= (int64_t(1) << 31) &&
69b2812113SSuraj Sudhir          "Shifted mantissa exceeds 32 signed bits");
70b2812113SSuraj Sudhir   if (shiftedM == (int64_t(1) << 31)) {
71b2812113SSuraj Sudhir     shiftedM /= 2;
72b2812113SSuraj Sudhir     shift++;
73b2812113SSuraj Sudhir   }
74b2812113SSuraj Sudhir 
75b2812113SSuraj Sudhir   // TOSA expects right shift to be positive, and embed (1 << 31) into right
76b2812113SSuraj Sudhir   // shift bits.
77b2812113SSuraj Sudhir   shift = (-shift) + 31;
78b2812113SSuraj Sudhir 
79b2812113SSuraj Sudhir   assert(shiftedM <= std::numeric_limits<int32_t>::max() &&
80b2812113SSuraj Sudhir          "Shifted mantissa exceeds 32-bit signed output type");
81b2812113SSuraj Sudhir 
82b2812113SSuraj Sudhir   multiplier = static_cast<int32_t>(shiftedM);
830763f122SRob Suderman 
84a383a481SPeng Sun   // Shifting tops out at 62 bits. Right shift to make 62 bits the max.
85a383a481SPeng Sun   // The limit of 62 on shift allows the shift to be decomposed as
86a383a481SPeng Sun   // two right shifts of 31.
87a383a481SPeng Sun   if (shift > 62) {
880763f122SRob Suderman     // Shifting the multiplier by more than 32-bits is unnecessary.
89a383a481SPeng Sun     multiplier = multiplier >> std::min<int32_t>(31, shift - 62);
90a383a481SPeng Sun     shift = 62;
910763f122SRob Suderman   }
92b2812113SSuraj Sudhir }
93b2812113SSuraj Sudhir 
94b2812113SSuraj Sudhir /// Generates a quantized multiplier/shift from double.
computeMultiplierAndShift(double scale,int32_t & multiplier,int32_t & shift,int32_t scaleWidth)95ac3587f2SStella Laurenzo void mlir::tosa::computeMultiplierAndShift(double scale, int32_t &multiplier,
96b2812113SSuraj Sudhir                                            int32_t &shift, int32_t scaleWidth) {
97b2812113SSuraj Sudhir 
98b2812113SSuraj Sudhir   switch (scaleWidth) {
99b2812113SSuraj Sudhir   case 16:
100b2812113SSuraj Sudhir     computeMultiplierAndShiftTosaScale16(scale, multiplier, shift);
101b2812113SSuraj Sudhir     return;
102b2812113SSuraj Sudhir   case 32:
103b2812113SSuraj Sudhir     computeMultiplierAndShiftTosaScale32(scale, multiplier, shift);
104b2812113SSuraj Sudhir     return;
105b2812113SSuraj Sudhir   default:
106b2812113SSuraj Sudhir     assert(0 && "Unsupported Tosa quantized_scale regime specified!");
107b2812113SSuraj Sudhir   }
108b2812113SSuraj Sudhir }
109b2812113SSuraj Sudhir 
110*3745e708STai Ly #define GET_UQTYPE(inputType)                                                  \
111*3745e708STai Ly   (llvm::dyn_cast<quant::UniformQuantizedType>((inputType).getElementType()))
112*3745e708STai Ly #define GET_QTYPE(inputType)                                                   \
113*3745e708STai Ly   (llvm::dyn_cast<quant::QuantizedType>((inputType).getElementType()))
114b2812113SSuraj Sudhir 
115b2812113SSuraj Sudhir /// Method to build ConvOpQuantizationAttr, called from
116b2812113SSuraj Sudhir /// ConvOpQuantInfoBuilder/TransConvOpQuantInfoBuilder:
117b2812113SSuraj Sudhir /// input_zp: input zeropoint
118b2812113SSuraj Sudhir /// weight_zp: weight zeropoint.
119ac3587f2SStella Laurenzo ConvOpQuantizationAttr
buildConvOpQuantizationAttr(OpBuilder & builder,Value input,Value weight)120ac3587f2SStella Laurenzo mlir::tosa::buildConvOpQuantizationAttr(OpBuilder &builder, Value input,
121ac3587f2SStella Laurenzo                                         Value weight) {
122b2812113SSuraj Sudhir 
1235550c821STres Popp   auto inputType = dyn_cast<ShapedType>(input.getType());
1245550c821STres Popp   auto weightType = dyn_cast<ShapedType>(weight.getType());
125b2812113SSuraj Sudhir 
126b2812113SSuraj Sudhir   if (!inputType || !weightType)
127b2812113SSuraj Sudhir     return nullptr;
128b2812113SSuraj Sudhir 
129b2812113SSuraj Sudhir   auto inputQType = GET_UQTYPE(inputType);
130b2812113SSuraj Sudhir   auto weightPerTensorQType = GET_UQTYPE(weightType);
1315550c821STres Popp   auto weightPerAxisQType =
1325550c821STres Popp       dyn_cast<quant::UniformQuantizedPerAxisType>(weightType.getElementType());
133b2812113SSuraj Sudhir 
134b2812113SSuraj Sudhir   // Weights must be either per-tensor quantized or per-axis quantized.
135b2812113SSuraj Sudhir   assert(!((bool)weightPerTensorQType && (bool)weightPerAxisQType) &&
136b2812113SSuraj Sudhir          "Weights must be either per-tensor or per-axis quantized");
137b2812113SSuraj Sudhir 
138b2812113SSuraj Sudhir   // Either all quantized or all not quantized.
139b2812113SSuraj Sudhir   assert(!((bool)inputQType ^
140b2812113SSuraj Sudhir            ((bool)weightPerTensorQType || (bool)weightPerAxisQType)) &&
141b2812113SSuraj Sudhir          "Inputs and weights must be all quantized or all not quantized");
142b2812113SSuraj Sudhir 
143b2812113SSuraj Sudhir   if (inputQType) {
144b2812113SSuraj Sudhir     int64_t inputZp = inputQType.getZeroPoint();
145b2812113SSuraj Sudhir     int64_t weightZp = 0;
146b2812113SSuraj Sudhir 
147b2812113SSuraj Sudhir     if (weightPerTensorQType) {
148b2812113SSuraj Sudhir       weightZp = weightPerTensorQType.getZeroPoint();
149b2812113SSuraj Sudhir     } else if (weightPerAxisQType) {
150b2812113SSuraj Sudhir       weightZp = weightPerAxisQType.getZeroPoints().front();
151b2812113SSuraj Sudhir     }
152b2812113SSuraj Sudhir 
153f1182bd6SMogball     return builder.getAttr<tosa::ConvOpQuantizationAttr>(inputZp, weightZp);
154b2812113SSuraj Sudhir   }
155b2812113SSuraj Sudhir 
156b2812113SSuraj Sudhir   return nullptr;
157b2812113SSuraj Sudhir }
158b2812113SSuraj Sudhir 
159b2812113SSuraj Sudhir /// Builds MatMulOpQuantizationAttr, called from
160b2812113SSuraj Sudhir /// MatMulOpQuantInfoBuilder:
161b2812113SSuraj Sudhir /// aZp: input a zeropoint
162b2812113SSuraj Sudhir /// bZp: input b zeropoint.
163ac3587f2SStella Laurenzo MatMulOpQuantizationAttr
buildMatMulOpQuantizationAttr(OpBuilder & builder,Value a,Value b)164ac3587f2SStella Laurenzo mlir::tosa::buildMatMulOpQuantizationAttr(OpBuilder &builder, Value a,
165ac3587f2SStella Laurenzo                                           Value b) {
166b2812113SSuraj Sudhir 
1675550c821STres Popp   auto aType = dyn_cast<ShapedType>(a.getType());
1685550c821STres Popp   auto bType = dyn_cast<ShapedType>(b.getType());
169b2812113SSuraj Sudhir 
170b2812113SSuraj Sudhir   if (!aType || !bType)
171b2812113SSuraj Sudhir     return nullptr;
172b2812113SSuraj Sudhir 
173b2812113SSuraj Sudhir   auto aQType = GET_UQTYPE(aType);
174b2812113SSuraj Sudhir   auto bQType = GET_UQTYPE(bType);
175b2812113SSuraj Sudhir 
176b2812113SSuraj Sudhir   // A and B are either all quantized or all not quantized.
177b2812113SSuraj Sudhir   assert(!((bool)aQType ^ (bool)bQType) &&
178b2812113SSuraj Sudhir          "Matmul operands must be all quantized or all not quantized");
179b2812113SSuraj Sudhir 
180b2812113SSuraj Sudhir   if (aQType) {
181f1182bd6SMogball     return builder.getAttr<tosa::MatMulOpQuantizationAttr>(
182f1182bd6SMogball         aQType.getZeroPoint(), bQType.getZeroPoint());
183b2812113SSuraj Sudhir   }
184b2812113SSuraj Sudhir 
185b2812113SSuraj Sudhir   return nullptr;
186b2812113SSuraj Sudhir }
187b2812113SSuraj Sudhir 
188b2812113SSuraj Sudhir /// Builds UnaryOpQuantizationAttr
189b2812113SSuraj Sudhir /// UnaryOpQuantInfoBuilder:
190b2812113SSuraj Sudhir /// inputZp: input zeropoint
191b2812113SSuraj Sudhir /// outputZp: output zeropoint.
192ac3587f2SStella Laurenzo UnaryOpQuantizationAttr
buildUnaryOpQuantizationAttr(OpBuilder & builder,Value input,Type outputRawType)193ac3587f2SStella Laurenzo mlir::tosa::buildUnaryOpQuantizationAttr(OpBuilder &builder, Value input,
194b2812113SSuraj Sudhir                                          Type outputRawType) {
195b2812113SSuraj Sudhir 
1965550c821STres Popp   auto inputType = dyn_cast<ShapedType>(input.getType());
1975550c821STres Popp   auto outputType = dyn_cast<ShapedType>(outputRawType);
198b2812113SSuraj Sudhir 
199b2812113SSuraj Sudhir   if (!inputType || !outputType)
200b2812113SSuraj Sudhir     return nullptr;
201b2812113SSuraj Sudhir 
202b2812113SSuraj Sudhir   auto inputQType = GET_UQTYPE(inputType);
203b2812113SSuraj Sudhir   auto outputQType = GET_UQTYPE(outputType);
204b2812113SSuraj Sudhir 
205b2812113SSuraj Sudhir   // Either all quantized or all not quantized.
206b2812113SSuraj Sudhir   assert(!((bool)inputQType ^ (bool)outputQType) &&
207b2812113SSuraj Sudhir          "Unary inputs/outputs must be all quantized or all not quantized");
208b2812113SSuraj Sudhir 
209b2812113SSuraj Sudhir   if (inputQType) {
210f1182bd6SMogball     return builder.getAttr<UnaryOpQuantizationAttr>(inputQType.getZeroPoint(),
211f1182bd6SMogball                                                     outputQType.getZeroPoint());
212b2812113SSuraj Sudhir   }
213b2812113SSuraj Sudhir 
214b2812113SSuraj Sudhir   return nullptr;
215b2812113SSuraj Sudhir }
216b2812113SSuraj Sudhir 
217b2812113SSuraj Sudhir /// Builds PadOpQuantizationAttr, called from PadOpQuantInfoBuilder:
218b2812113SSuraj Sudhir /// inputZp: input zeropoint.
buildPadOpQuantizationAttr(OpBuilder & builder,Value input)219ac3587f2SStella Laurenzo PadOpQuantizationAttr mlir::tosa::buildPadOpQuantizationAttr(OpBuilder &builder,
220b2812113SSuraj Sudhir                                                              Value input) {
221b2812113SSuraj Sudhir 
2225550c821STres Popp   auto inputType = dyn_cast<ShapedType>(input.getType());
223b2812113SSuraj Sudhir 
224b2812113SSuraj Sudhir   if (!inputType)
225b2812113SSuraj Sudhir     return nullptr;
226b2812113SSuraj Sudhir 
227b2812113SSuraj Sudhir   auto inputQType = GET_UQTYPE(inputType);
228b2812113SSuraj Sudhir 
229b2812113SSuraj Sudhir   if (inputQType) {
230f1182bd6SMogball     return builder.getAttr<tosa::PadOpQuantizationAttr>(
231f1182bd6SMogball         inputQType.getZeroPoint());
232b2812113SSuraj Sudhir   }
233b2812113SSuraj Sudhir 
234b2812113SSuraj Sudhir   return nullptr;
235b2812113SSuraj Sudhir }
236b2812113SSuraj Sudhir 
237b2812113SSuraj Sudhir /// Builds output type for a quantized ConvOp with the right bitwidth.
238b2812113SSuraj Sudhir /// This is called by the builder when dealing with quantized content.
buildConvOpResultTypeInfo(OpBuilder & builder,Type outputType,Value input,Value weight)239ac3587f2SStella Laurenzo Type mlir::tosa::buildConvOpResultTypeInfo(OpBuilder &builder, Type outputType,
240ac3587f2SStella Laurenzo                                            Value input, Value weight) {
241b2812113SSuraj Sudhir 
2425550c821STres Popp   auto inputType = dyn_cast<ShapedType>(input.getType());
2435550c821STres Popp   auto weightType = dyn_cast<ShapedType>(weight.getType());
244b2812113SSuraj Sudhir 
245b2812113SSuraj Sudhir   assert(inputType && weightType &&
246b2812113SSuraj Sudhir          "Could not extract input or weight tensors from Conv op");
247b2812113SSuraj Sudhir 
248b2812113SSuraj Sudhir   auto inputQType = GET_QTYPE(inputType);
249b2812113SSuraj Sudhir   auto weightQType = GET_QTYPE(weightType);
250b2812113SSuraj Sudhir 
251b2812113SSuraj Sudhir   assert(inputQType && weightQType &&
252b2812113SSuraj Sudhir          "Could not extract input or weight tensor types from Conv op");
253b2812113SSuraj Sudhir 
254b2812113SSuraj Sudhir   unsigned inputBits = inputQType.getStorageTypeIntegralWidth();
255b2812113SSuraj Sudhir   unsigned weightBits = weightQType.getStorageTypeIntegralWidth();
256b2812113SSuraj Sudhir 
2575550c821STres Popp   auto outputShapedType = dyn_cast<ShapedType>(outputType);
258b2812113SSuraj Sudhir   assert(outputShapedType &&
259b2812113SSuraj Sudhir          "Could not extract output shape type from Conv op");
260b2812113SSuraj Sudhir 
261b2812113SSuraj Sudhir   IntegerType accElementType;
262b2812113SSuraj Sudhir   if (inputBits == 16 && weightBits == 8)
263b2812113SSuraj Sudhir     accElementType = builder.getIntegerType(48);
264b2812113SSuraj Sudhir   else
265b2812113SSuraj Sudhir     accElementType = builder.getI32Type();
2668662a2f2SRob Suderman   auto accType = outputShapedType.clone(accElementType);
267b2812113SSuraj Sudhir   return accType;
268b2812113SSuraj Sudhir }
269b2812113SSuraj Sudhir 
270b2812113SSuraj Sudhir /// Builds Tosa quantization attributes from min/max values.
buildQTypeFromMinMax(OpBuilder builder,Type inputDType,Attribute minAttr,Attribute maxAttr,IntegerAttr quantBits,int filterQuantDim,bool isSigned,BoolAttr narrowRange)271ac3587f2SStella Laurenzo Type mlir::tosa::buildQTypeFromMinMax(OpBuilder builder, Type inputDType,
272ac3587f2SStella Laurenzo                                       Attribute minAttr, Attribute maxAttr,
273ac3587f2SStella Laurenzo                                       IntegerAttr quantBits, int filterQuantDim,
274ac3587f2SStella Laurenzo                                       bool isSigned, BoolAttr narrowRange) {
275b2812113SSuraj Sudhir 
276b2812113SSuraj Sudhir   quant::QuantizedType retType;
277b2812113SSuraj Sudhir 
278b2812113SSuraj Sudhir   auto convfunc =
279b2812113SSuraj Sudhir       quant::ExpressedToQuantizedConverter::forInputType(inputDType);
280b2812113SSuraj Sudhir 
2815550c821STres Popp   auto minElems = dyn_cast<DenseFPElementsAttr>(minAttr);
2825550c821STres Popp   auto maxElems = dyn_cast<DenseFPElementsAttr>(maxAttr);
283b2812113SSuraj Sudhir 
284b2812113SSuraj Sudhir   SmallVector<double, 2> min, max;
285b2812113SSuraj Sudhir 
286b2812113SSuraj Sudhir   // At least one is per-axis quantized elementsattr.
287b2812113SSuraj Sudhir   if (minElems || maxElems) {
288b2812113SSuraj Sudhir     // Must have the same number of elements.
289b2812113SSuraj Sudhir     if (minElems.getNumElements() != maxElems.getNumElements())
290b2812113SSuraj Sudhir       return {};
291b2812113SSuraj Sudhir     min.reserve(minElems.getNumElements());
292b2812113SSuraj Sudhir     max.reserve(maxElems.getNumElements());
293b2812113SSuraj Sudhir     for (auto i : minElems)
294b2812113SSuraj Sudhir       min.push_back(FloatAttr::getValueAsDouble(i));
295b2812113SSuraj Sudhir     for (auto i : maxElems)
296b2812113SSuraj Sudhir       max.push_back(FloatAttr::getValueAsDouble(i));
297b2812113SSuraj Sudhir   } else { // Just a single FP value.
2985550c821STres Popp     auto minVal = dyn_cast<FloatAttr>(minAttr);
299b2812113SSuraj Sudhir     if (minVal)
300b2812113SSuraj Sudhir       min.push_back(minVal.getValueAsDouble());
301b2812113SSuraj Sudhir     else
302b2812113SSuraj Sudhir       return {};
3035550c821STres Popp     auto maxVal = dyn_cast<FloatAttr>(maxAttr);
304b2812113SSuraj Sudhir     if (maxVal)
305b2812113SSuraj Sudhir       max.push_back(maxVal.getValueAsDouble());
306b2812113SSuraj Sudhir     else
307b2812113SSuraj Sudhir       return {};
308b2812113SSuraj Sudhir   }
309b2812113SSuraj Sudhir 
310b2812113SSuraj Sudhir   if (min.size() == max.size()) {
311b2812113SSuraj Sudhir     if (min.size() == 1) { // Per-tensor quantization with one min/max pair.
312b2812113SSuraj Sudhir       retType = quant::fakeQuantAttrsToType(
313b2812113SSuraj Sudhir           builder.getUnknownLoc(), quantBits.getInt(), min[0], max[0],
314b2812113SSuraj Sudhir           narrowRange.getValue(), convfunc.expressedType, isSigned);
315b2812113SSuraj Sudhir     } else if (min.size() > 1) { // Per-axis quant on filterQuantDim.
3165550c821STres Popp       auto shape = dyn_cast<ShapedType>(inputDType);
317b2812113SSuraj Sudhir       if (!shape)
318b2812113SSuraj Sudhir         return {};
319b2812113SSuraj Sudhir       if ((filterQuantDim) >= 0 && (shape.getRank() > filterQuantDim)) {
320b2812113SSuraj Sudhir         retType = quant::fakeQuantAttrsToType(
321b2812113SSuraj Sudhir             builder.getUnknownLoc(), quantBits.getInt(), filterQuantDim, min[0],
322b2812113SSuraj Sudhir             max[0], narrowRange.getValue(), convfunc.expressedType, isSigned);
323b2812113SSuraj Sudhir       }
324b2812113SSuraj Sudhir     } else {
325b2812113SSuraj Sudhir       return {};
326b2812113SSuraj Sudhir     }
327b2812113SSuraj Sudhir   } else {
328b2812113SSuraj Sudhir     return {};
329b2812113SSuraj Sudhir   }
330b2812113SSuraj Sudhir 
331b2812113SSuraj Sudhir   if (!retType)
332b2812113SSuraj Sudhir     return {};
333b2812113SSuraj Sudhir 
334b2812113SSuraj Sudhir   return convfunc.convert(retType);
335b2812113SSuraj Sudhir }
336b2812113SSuraj Sudhir 
337b2812113SSuraj Sudhir /// Builds Tosa quantization attributes from min/max values.
338ac3587f2SStella Laurenzo TypeAttr
buildQTypeAttrFromMinMax(OpBuilder builder,Type inputDtype,Attribute minAttr,Attribute maxAttr,IntegerAttr quantBits,int filterQuantDim,bool isSigned,BoolAttr narrowRange)339ac3587f2SStella Laurenzo mlir::tosa::buildQTypeAttrFromMinMax(OpBuilder builder, Type inputDtype,
340b2812113SSuraj Sudhir                                      Attribute minAttr, Attribute maxAttr,
341b2812113SSuraj Sudhir                                      IntegerAttr quantBits, int filterQuantDim,
342b2812113SSuraj Sudhir                                      bool isSigned, BoolAttr narrowRange) {
343b2812113SSuraj Sudhir 
344b2812113SSuraj Sudhir   return TypeAttr::get(buildQTypeFromMinMax(builder, inputDtype, minAttr,
345b2812113SSuraj Sudhir                                             maxAttr, quantBits, filterQuantDim,
346b2812113SSuraj Sudhir                                             isSigned, narrowRange));
347b2812113SSuraj Sudhir }
348