30#include "llvm/ADT/APFloat.h"
31#include "llvm/ADT/SmallVectorExtras.h"
32#include "llvm/ADT/TypeSwitch.h"
40#include "mlir/Dialect/Tosa/IR/TosaOpsDialect.cpp.inc"
47#include "mlir/Dialect/Tosa/IR/TosaEnums.cpp.inc"
48#include "mlir/Dialect/Tosa/IR/TosaInterfaces.cpp.inc"
51#include "mlir/Dialect/Tosa/IR/TosaDialectBytecode.cpp.inc"
56struct TosaInlinerInterface :
public DialectInlinerInterface {
57 using DialectInlinerInterface::DialectInlinerInterface;
65 IRMapping &map)
const final {
71 IRMapping &map)
const final {
72 return (isa<tosa::IfOp>(dest->getParentOp()) ||
73 isa<tosa::WhileOp>(dest->getParentOp()));
78struct TosaDialectBytecodeInterface :
public BytecodeDialectInterface {
79 TosaDialectBytecodeInterface(Dialect *dialect)
80 : BytecodeDialectInterface(dialect) {}
85 Attribute readAttribute(DialectBytecodeReader &reader)
const override {
89 LogicalResult writeAttribute(Attribute attr,
90 DialectBytecodeWriter &writer)
const override {
91 return ::writeAttribute(attr, writer);
97 Type readType(DialectBytecodeReader &reader)
const override {
101 LogicalResult writeType(Type type,
102 DialectBytecodeWriter &writer)
const override {
103 return ::writeType(type, writer);
106 void writeVersion(DialectBytecodeWriter &writer)
const final {
110 std::unique_ptr<DialectVersion>
111 readVersion(DialectBytecodeReader &reader)
const final {
113 reader.
emitError(
"Dialect does not support versioning");
117 LogicalResult upgradeFromVersion(Operation *topLevelOp,
118 const DialectVersion &version)
const final {
131 return {&getBodyGraph()};
140 return dim == -1 ? ShapedType::kDynamic : dim;
146 Type elementType = variableOp.getType();
149 return RankedTensorType::get(
shape, elementType);
156void TosaDialect::initialize() {
158#define GET_TYPEDEF_LIST
159#include "mlir/Dialect/Tosa/IR/TosaOpsTypesBase.cpp.inc"
163#include "mlir/Dialect/Tosa/IR/TosaOps.cpp.inc"
166#define GET_ATTRDEF_LIST
167#include "mlir/Dialect/Tosa/IR/TosaAttributes.cpp.inc"
169 addInterfaces<TosaDialectBytecodeInterface, TosaInlinerInterface>();
170 declarePromisedInterfaces<
171 shard::ShardingInterface, ClampOp, SigmoidOp, TanhOp, AddOp,
172 ArithmeticRightShiftOp, BitwiseAndOp, BitwiseOrOp, BitwiseXorOp, IntDivOp,
173 LogicalAndOp, LogicalLeftShiftOp, LogicalRightShiftOp, LogicalOrOp,
174 LogicalXorOp, MaximumOp, MinimumOp, MulOp, PowOp, SubOp, AbsOp,
175 BitwiseNotOp, CeilOp, ClzOp, ExpOp, FloorOp, LogOp, LogicalNotOp,
176 NegateOp, ReciprocalOp, RsqrtOp, SelectOp, EqualOp, GreaterOp,
177 GreaterEqualOp, MatMulOp>();
184 if (llvm::isa<shapeType>(type) && llvm::isa<DenseIntElementsAttr>(value)) {
185 return tosa::ConstShapeOp::create(builder, loc, type,
186 llvm::cast<DenseIntElementsAttr>(value));
188 if (llvm::isa<ElementsAttr>(value))
189 return tosa::ConstOp::create(builder, loc, type,
190 llvm::cast<ElementsAttr>(value));
200ParseResult getShapeAndElementType(
OpAsmParser &parser,
Type parsedType,
202 TypeAttr &typeAttr) {
203 if (
auto shapedType = dyn_cast<ShapedType>(parsedType)) {
204 if (!shapedType.hasRank())
206 <<
"expected ranked type";
208 auto elementType = shapedType.getElementType();
209 typeAttr = TypeAttr::get(elementType);
216 <<
"expected shaped type";
233 <<
"expected attribute";
235 if (
auto typedAttr = dyn_cast<TypedAttr>(initialValueAttr)) {
236 return getShapeAndElementType(parser, typedAttr.getType(), varShapeAttr,
240 <<
"expected Typed attr";
243 initialValueAttr =
nullptr;
247 <<
"expected type after colon";
249 return getShapeAndElementType(parser, parsedType, varShapeAttr, typeAttr);
254 TypeAttr typeAttr,
Attribute initialValueAttr) {
255 bool needsSpace =
false;
256 if (!dyn_cast_or_null<TypedAttr>(initialValueAttr)) {
259 Type elementType = typeAttr.getValue();
260 RankedTensorType tensorType =
262 auto tensorTypeAttr = TypeAttr::get(tensorType);
267 if (initialValueAttr) {
287 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(srcType))
297 Value valZp, StringRef name) {
302 mlir::isa<IntegerType>(eType) && mlir::isa<IntegerType>(eZpType);
306 if (!bothInts || !sameBitWidth) {
308 <<
"expected " << name <<
" and " << name
309 <<
"_zp to both be integer of the same bitwidth, but got " << eType
310 <<
" vs. " << eZpType;
317 Value src, int32_t val) {
320 const auto padConstType = mlir::RankedTensorType::get({1}, srcType);
321 const auto padConstEType = mlir::RankedTensorType::get({1}, srcElemType);
322 const auto padConstAttr{
323 llvm::isa<FloatType>(srcElemType)
328 return tosa::ConstOp::create(builder, loc, padConstType, padConstAttr);
332 if (
auto blockScaledTy = dyn_cast<tosa::BlockScaledType>(type))
334 if (dyn_cast<tosa::mxint8Type>(type))
343 const StringRef operandName,
344 const StringRef dimName) {
345 if (ShapedType::isDynamic(currDim)) {
348 }
else if (ShapedType::isStatic(newDim) && currDim != newDim) {
350 << dimName <<
" of " << operandName <<
" to match size " << currDim
351 <<
", got " << newDim;
358 auto printDim = [&](
int64_t dim) {
359 if (ShapedType::isDynamic(dim))
365 llvm::interleaveComma(
shape,
diag, printDim);
371 StringRef outputName =
"output") {
372 assert(outputType.hasRank() &&
"expected output type to be ranked");
378 diag << outputName <<
" shape ";
380 diag <<
" to be compatible with inferred shape ";
388 const int64_t stride,
const int64_t dilation,
const llvm::StringRef dimName,
389 const llvm::StringRef dimAxis,
const llvm::StringRef padBeforeName,
390 const llvm::StringRef padAfterName) {
391 if (inputSize == ShapedType::kDynamic || kernelSize == ShapedType::kDynamic)
396 const std::optional<int64_t> calculatedOutSizeMinusOne =
idivCheck(
397 inputSize - 1 + padBefore + padAfter - (kernelSize - 1) * dilation,
399 if (!calculatedOutSizeMinusOne.has_value())
401 << dimName <<
" - 1 + pad_" << padBeforeName <<
" + pad_"
402 << padAfterName <<
" - (kernel_" << dimName <<
" - 1) * dilation_"
403 << dimAxis <<
" to be wholly divisible by stride_" << dimAxis
404 <<
", got (" << inputSize <<
" - 1 + " << padBefore <<
" + "
405 << padAfter <<
" - (" << kernelSize <<
" - 1) * " << dilation
408 const int64_t calculatedOutSize = calculatedOutSizeMinusOne.value() + 1;
409 if (outputSize != ShapedType::kDynamic && calculatedOutSize != outputSize)
411 << dimName <<
" did not match expected: "
412 <<
"calculated=" << calculatedOutSize <<
", expected=" << outputSize;
420size_t mlir::tosa::mxint8Type::getDenseElementBitSize()
const {
return 8; }
423mlir::tosa::mxint8Type::convertToAttribute(
ArrayRef<char> rawData)
const {
424 assert(rawData.size() == 1 &&
"expected 1 byte for tosa.mxint8 element");
425 const auto intType = IntegerType::get(
getContext(), 8);
426 return intType.convertToAttribute(rawData);
429LogicalResult mlir::tosa::mxint8Type::convertFromAttribute(
431 const auto intAttr = dyn_cast<IntegerAttr>(attr);
434 const Type attrType = intAttr.getType();
437 return cast<IntegerType>(attrType).convertFromAttribute(attr,
result);
446 bool allowScaleValues) {
447 const auto tensorType = llvm::cast<ShapedType>(type);
448 const BlockScaledType elemType =
449 llvm::dyn_cast<BlockScaledType>(tensorType.getElementType());
453 if (!allowScaleValues && elemType.hasScaleValues()) {
456 <<
"block scaled tensor type with scale values is not allowed";
460 if (!tensorType.hasRank())
463 if (tensorType.getRank() == 0) {
465 emitError() <<
"block scaled tensor type must have rank greater than "
471 const uint32_t blockSize =
472 BlockShapeAttr::getBlockShapeValue(elemType.getBlockShape());
474 if (allowScaleValues && elemType.hasScaleValues() &&
475 tensorType.hasStaticShape()) {
476 const size_t numBlocks = tensorType.getNumElements() / blockSize;
477 if (elemType.getScaleValues().size() != numBlocks) {
479 emitError() <<
"block scaled tensor type with scale values must have "
480 "scale values for each block, expected "
481 << numBlocks <<
", got "
482 << elemType.getScaleValues().size();
487 const int64_t blockedDimension = tensorShape.back();
488 if (ShapedType::isDynamic(blockedDimension))
491 if (blockedDimension % blockSize != 0) {
493 emitError() <<
"last dimension of block scaled tensor type ("
494 << blockedDimension <<
") must be divisible by block size ("
510 type, [ctx] {
return emitError(UnknownLoc::get(ctx)); })) &&
512 return ": " + message;
521 const auto parseScaleValue = [&]() -> ParseResult {
528 if (floatValue < 0.0)
529 return parser.
emitError(loc,
"scale value must be non-negative, got ")
532 Type attrType = scaleType;
536 if (attrType != scaleType)
537 return parser.
emitError(loc,
"parsed attribute type ")
538 << attrType <<
" does not match expected scale type " << scaleType;
540 scaleValues.push_back(FloatAttr::get(attrType, floatValue));
549 llvm::interleaveComma(scaleValues, printer, [&](
Attribute scaleValue) {
554size_t mlir::tosa::BlockScaledType::getDenseElementBitSize()
const {
556 if (isa<tosa::mxint8Type>(valueType))
562mlir::tosa::BlockScaledType::convertToAttribute(
ArrayRef<char> rawData)
const {
566 assert(rawData.size() == 1 &&
"expected 1 byte for block_scaled element");
568 if (
const auto mxint8Value = dyn_cast<tosa::mxint8Type>(valueType))
569 return mxint8Value.convertToAttribute(rawData);
570 if (!isa<FloatType>(valueType))
575LogicalResult mlir::tosa::BlockScaledType::convertFromAttribute(
578 if (
const auto mxint8Value = dyn_cast<tosa::mxint8Type>(valueType))
579 return mxint8Value.convertFromAttribute(attr,
result);
581 const auto floatAttr = dyn_cast<FloatAttr>(attr);
582 if (!floatAttr || floatAttr.getType() != valueType)
593template <
typename A, std::enable_if_t<std::is_same_v<A, ArgMaxOp::Adaptor> ||
594 std::is_same_v<A, ArgMinOp::Adaptor>,
597 MLIRContext *context, ::std::optional<Location> location, A adaptor,
600 IntegerAttr axis = adaptor.getProperties().axis;
601 int32_t axisVal = axis.getValue().getSExtValue();
608 const auto inputRank = inputShape.
getRank();
610 outShape.reserve(inputRank - 1);
611 for (
int i = 0, s = inputRank; i < s; i++) {
626 const ShapedType resultType = llvm::cast<ShapedType>(op.getType());
628 if (
const auto resultETy = resultType.getElementType();
629 !resultETy.isIntOrIndex())
630 return op.emitOpError(
"result tensor is not of integer type");
632 const auto inputType = llvm::cast<ShapedType>(op.getInput().getType());
633 if (!inputType.hasRank())
637 const int64_t axis = op.getAxisAttr().getInt();
638 if (((axis < 0) || axis >= inputType.getRank()))
639 return op.emitOpError(
"specified axis is outside the rank of the tensor");
641 if (!resultType.hasRank())
647 expectedOutputShape.erase(expectedOutputShape.begin() + axis);
649 return op.emitOpError(
"expected output shape '")
650 << expectedOutputShape <<
"', got '" << outputShape <<
"'";
657 const auto inputType = llvm::dyn_cast<TensorType>(op.getInput().getType());
658 const auto weightType = llvm::dyn_cast<TensorType>(op.getWeight().getType());
660 auto inputEType = inputType.getElementType();
661 auto weightEType = weightType.getElementType();
663 llvm::cast<ShapedType>(op.getBias().getType()).getElementType();
665 llvm::cast<ShapedType>(op.getResult().getType()).getElementType();
666 bool biasIsFloat = llvm::isa<FloatType>(biasEType);
667 bool resultIsFloat = llvm::isa<FloatType>(resultEType);
669 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(inputEType))
672 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(weightEType))
675 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(biasEType))
678 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(resultEType))
681 if (biasIsFloat && resultIsFloat && (biasEType != resultEType)) {
685 "expect both bias and result to have same element type, got ")
686 << biasEType <<
" and " << resultEType;
690 const bool isInputBlockScaled = llvm::isa<BlockScaledType>(inputEType);
691 const bool isWeightBlockScaled = llvm::isa<BlockScaledType>(weightEType);
692 const bool isInputFloat = llvm::isa<FloatType>(inputEType);
693 const bool isWeightFloat = llvm::isa<FloatType>(weightEType);
695 const bool isInputBSorFloat = isInputBlockScaled || isInputFloat;
696 const bool isWeightBSorFloat = isWeightBlockScaled || isWeightFloat;
699 if (isInputBSorFloat != isWeightBSorFloat) {
701 "expect both input and weight to be float or not together, got ")
702 << inputEType <<
" and " << weightEType;
707 if (!isInputBlockScaled && inputEType != inputZpEType) {
708 return op.emitOpError(
"expect both input and its zero point are the same "
709 "element type, got ")
710 << inputEType <<
" and " << inputZpEType;
712 if (isInputBlockScaled && !llvm::isa<Float32Type>(inputZpEType)) {
713 return op.emitOpError(
714 "expect block scaled input to have fp32 zero point, got ")
715 << inputEType <<
" and " << inputZpEType;
719 if (!isWeightBlockScaled && weightEType != weightZpEType) {
720 return op.emitOpError(
"expect both weight and its zero point are the same "
721 "element type, got ")
722 << weightEType <<
" and " << weightZpEType;
724 if (isWeightBlockScaled && !llvm::isa<Float32Type>(weightZpEType)) {
725 return op.emitOpError(
726 "expect block scaled weight to have fp32 zero point, got ")
727 << weightEType <<
" and " << weightZpEType;
730 FailureOr<int64_t> maybeIZp = op.getInputZeroPoint();
731 if (succeeded(maybeIZp) && op.verifyInputZeroPoint(*maybeIZp).failed())
734 FailureOr<int64_t> maybeWZp = op.getWeightZeroPoint();
735 if (succeeded(maybeWZp) && op.verifyWeightZeroPoint(*maybeWZp).failed())
741LogicalResult tosa::ConstOp::verify() {
743 auto attrType = llvm::dyn_cast<TensorType>(getValuesAttr().
getType());
744 auto outputType = llvm::dyn_cast<TensorType>(getOutput().
getType());
746 if (!attrType || !outputType) {
747 emitOpError(
"expected tensors for attr/result type");
751 const Type attrElemType = attrType.getElementType();
752 const Type resultElemType = outputType.getElementType();
755 llvm::dyn_cast<mlir::quant::QuantizedType>(resultElemType)) {
760 if (
auto attrBlockScaledType =
761 llvm::dyn_cast<mlir::tosa::BlockScaledType>(attrElemType)) {
762 if (!attrBlockScaledType.hasScaleValues())
764 "attribute block scaled type must have scale values");
766 const auto emitAttributeError = [&op]() {
767 return op.
emitOpError(
"attribute block scaled type is invalid: ");
773 const BlockScaledType resultBlockScaledType =
774 llvm::dyn_cast<mlir::tosa::BlockScaledType>(resultElemType);
775 if (!resultBlockScaledType)
777 "result type must be block scaled type if attribute is block "
780 if (attrBlockScaledType.getValueType() !=
781 resultBlockScaledType.getValueType() ||
782 attrBlockScaledType.getScaleType() !=
783 resultBlockScaledType.getScaleType() ||
784 attrBlockScaledType.getBlockShape() !=
785 resultBlockScaledType.getBlockShape())
787 "expected block scaled element type to be compatible "
788 "between attr and result, got ")
789 << attrBlockScaledType <<
" vs. " << resultBlockScaledType;
794 if (attrElemType != resultElemType)
795 return emitOpError(
"expected same attr/result element types");
808 if (llvm::any_of(padding, [](
int64_t p) {
return p < 0; }))
809 return op.emitOpError(
"expect all padding values to be >= 0, got ")
813 if (llvm::any_of(strides, [](
int64_t s) {
return s < 1; }))
814 return op.emitOpError(
"expect all stride values to be >= 1, got ")
818 if (llvm::any_of(dilations, [](
int64_t d) {
return d < 1; }))
819 return op.emitOpError(
"expect all dilation values to be >= 1, got ")
822 const RankedTensorType outputType =
823 llvm::dyn_cast<RankedTensorType>(op.getOutput().getType());
828 const RankedTensorType inputType =
829 llvm::dyn_cast<RankedTensorType>(op.getInput().getType());
830 const RankedTensorType weightType =
831 llvm::dyn_cast<RankedTensorType>(op.getWeight().getType());
833 if (inputType && weightType) {
835 if constexpr (std::is_same<T, tosa::Conv2DOp>::value) {
837 op, inputType.getDimSize(1), weightType.getDimSize(1),
838 outputType.getDimSize(1), padding[0], padding[1], strides[0],
839 dilations[0],
"height",
"y",
"top",
"bottom")))
843 op, inputType.getDimSize(2), weightType.getDimSize(2),
844 outputType.getDimSize(2), padding[2], padding[3], strides[1],
845 dilations[1],
"width",
"x",
"left",
"right")))
850 if constexpr (std::is_same<T, tosa::DepthwiseConv2DOp>::value) {
852 op, inputType.getDimSize(1), weightType.getDimSize(0),
853 outputType.getDimSize(1), padding[0], padding[1], strides[0],
854 dilations[0],
"height",
"y",
"top",
"bottom")))
858 op, inputType.getDimSize(2), weightType.getDimSize(1),
859 outputType.getDimSize(2), padding[2], padding[3], strides[1],
860 dilations[1],
"width",
"x",
"left",
"right")))
865 if constexpr (std::is_same<T, tosa::Conv3DOp>::value) {
867 op, inputType.getDimSize(1), weightType.getDimSize(1),
868 outputType.getDimSize(1), padding[0], padding[1], strides[0],
869 dilations[0],
"depth",
"d",
"front",
"back")))
873 op, inputType.getDimSize(2), weightType.getDimSize(2),
874 outputType.getDimSize(2), padding[2], padding[3], strides[1],
875 dilations[1],
"height",
"y",
"top",
"bottom")))
879 op, inputType.getDimSize(3), weightType.getDimSize(3),
880 outputType.getDimSize(3), padding[4], padding[5], strides[2],
881 dilations[2],
"width",
"x",
"left",
"right")))
886 const RankedTensorType biasType =
887 llvm::dyn_cast<RankedTensorType>(op.getBias().getType());
892 const int64_t biasChannels = biasType.getDimSize(0);
894 outputType.getDimSize(outputType.getRank() - 1);
895 if (biasChannels == ShapedType::kDynamic ||
896 outputChannels == ShapedType::kDynamic)
900 if (biasChannels != outputChannels && biasChannels != 1)
901 return op.emitOpError(
902 "bias channels expected to be equal to output channels (")
903 << outputChannels <<
") or 1, got " << biasChannels;
910 StringRef name1,
Type type2,
912 auto shapeType1 = dyn_cast<ShapedType>(type1);
913 auto shapeType2 = dyn_cast<ShapedType>(type2);
914 if (!shapeType1 || !shapeType2)
917 auto elemType1 = shapeType1.getElementType();
918 auto elemType2 = shapeType2.getElementType();
919 if (elemType1 != elemType2)
921 <<
"require same element type for " << name1 <<
" (" << elemType1
922 <<
") and " << name2 <<
" (" << elemType2 <<
")";
926 <<
"require same shapes for " << name1 <<
" (" << type1 <<
") and "
927 << name2 <<
" (" << type2 <<
")";
937 if (list1.size() != list2.size())
939 <<
"require same number of values in " << name1 <<
" ("
940 << list1.size() <<
") and " << name2 <<
" (" << list2.size() <<
")";
942 for (
auto [type1, type2] :
962 op->template getParentWithTrait<OpTrait::SymbolTable>();
969 const auto varOp = symTable.
lookup<tosa::VariableOp>(op.getName());
973 return op->emitOpError(
"'")
974 << op.getName() <<
"' has not been declared by 'tosa.variable'";
988 StringRef aName =
"input",
989 StringRef bName =
"output") {
990 auto aTType = llvm::dyn_cast<TensorType>(aType);
991 auto bTType = llvm::dyn_cast<TensorType>(bType);
993 op->
emitOpError(
"expect shaped tensor for") << aName <<
", got " << aType;
997 op->
emitOpError(
"expect shaped tensor for") << bName <<
", got" << bType;
1000 auto aElementType = aTType.getElementType();
1001 auto bElementType = bTType.getElementType();
1003 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(aElementType);
1005 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(bElementType);
1006 if ((aElementType.isIntOrIndexOrFloat() || aQuantType) &&
1007 (bElementType.isIntOrIndexOrFloat() || bQuantType) &&
1008 aElementType != bElementType) {
1014 << aName <<
" and " << bName <<
" to have same element type, got "
1015 << aElementType <<
" and " << bElementType;
1021LogicalResult tosa::ArgMaxOp::verify() {
return argMaxMinVerify(*
this); }
1023LogicalResult tosa::ArgMinOp::verify() {
return argMaxMinVerify(*
this); }
1033 const bool hasKernel = kernel.size() > 0;
1034 const bool hasStrides = strides.size() > 0;
1035 const bool hasPad = padding.size() > 0;
1037 if (hasKernel && llvm::any_of(kernel, [](
int64_t s) {
return s < 1; }))
1038 return op->
emitOpError(
"expect all kernel values to be >= 1, got ")
1041 if (hasStrides && llvm::any_of(strides, [](
int64_t s) {
return s < 1; }))
1042 return op->
emitOpError(
"expect all stride values to be >= 1, got ")
1045 if (hasPad && llvm::any_of(padding, [](
int64_t p) {
return p < 0; }))
1046 return op->
emitOpError(
"expect all padding values to be >= 0, got ")
1049 if (hasKernel && hasPad) {
1051 const int64_t kernelX = kernel[1];
1052 const int64_t padLeft = padding[2];
1053 const int64_t padRight = padding[3];
1054 if (padRight >= kernelX || padLeft >= kernelX)
1055 return op->
emitOpError(
"expected left/right padding to be less than the "
1056 "width of the kernel, got pad_left=")
1057 << padLeft <<
", pad_right=" << padRight
1058 <<
", kernel_x=" << kernelX;
1060 const int64_t kernelY = kernel[0];
1061 const int64_t padTop = padding[0];
1062 const int64_t padBottom = padding[1];
1063 if (padTop >= kernelY || padBottom >= kernelY)
1064 return op->
emitOpError(
"expected top/bottom padding to be less than the "
1065 "height of the kernel, got pad_top=")
1066 << padTop <<
", pad_bottom=" << padBottom
1067 <<
", kernel_y=" << kernelY;
1070 const auto inputType = llvm::dyn_cast<RankedTensorType>(input.
getType());
1071 const auto outputType = llvm::dyn_cast<RankedTensorType>(output.
getType());
1072 if (!inputType || !outputType)
1075 if (hasKernel && hasStrides && hasPad) {
1076 const auto verifyOutputSize =
1080 const llvm::StringRef dimName,
const llvm::StringRef dimAxis,
1081 const llvm::StringRef padBeforeName,
1082 const llvm::StringRef padAfterName) -> LogicalResult {
1083 if (ShapedType::isDynamic(inputSize))
1086 const std::optional<int64_t> calculatedOutSizeMinusOne =
1087 idivCheck(inputSize + padBefore + padAfter - kernelSize, strideSize);
1088 if (!calculatedOutSizeMinusOne.has_value())
1090 << dimName <<
" + pad_" << padBeforeName <<
" + pad_"
1091 << padAfterName <<
" - kernel_" << dimAxis
1092 <<
" to be wholly divisible by stride_" << dimAxis <<
", got ("
1093 << inputSize <<
" + " << padBefore <<
" + " << padAfter <<
" - "
1094 << kernelSize <<
") / " << strideSize;
1096 const int64_t calculatedOutSize = calculatedOutSizeMinusOne.value() + 1;
1097 if (ShapedType::isStatic(outputSize) && calculatedOutSize != outputSize)
1099 << dimName <<
" did not match expected: " <<
"calculated="
1100 << calculatedOutSize <<
", expected=" << outputSize;
1105 if (failed(verifyOutputSize(inputType.getDimSize(1),
1106 outputType.getDimSize(1), kernel[0], strides[0],
1107 padding[0], padding[1],
"height",
"y",
"top",
1111 if (failed(verifyOutputSize(
1112 inputType.getDimSize(2), outputType.getDimSize(2), kernel[1],
1113 strides[1], padding[2], padding[3],
"width",
"x",
"left",
"right")))
1119template <
typename T>
1122 op.getPad(), op.getInput(), op.getOutput());
1125template <
typename T>
1129 const Type inputZpETy =
1131 const Type outputZpETy =
1134 auto accType = op.getAccType();
1135 if (llvm::isa<IntegerType>(inputETy) && !accType.isInteger(32))
1136 return op.emitOpError(
"accumulator type for integer tensor is not i32");
1138 if (inputETy.
isF16() && !(accType.isF16() || accType.isF32()))
1139 return op.emitOpError(
"accumulator type for f16 tensor is not f16/f32");
1141 if (inputETy.
isBF16() && !accType.isF32())
1142 return op.emitOpError(
"accumulator type for bf16 tensor is not f32");
1144 if (inputETy.
isF32() && !accType.isF32())
1145 return op.emitOpError(
"accumulator type for f32 tensor is not f32");
1147 if (inputETy != inputZpETy)
1148 return op.emitOpError(
"expect both input and its zero point are the same "
1149 "element type, got ")
1150 << inputETy <<
" and " << inputZpETy;
1152 if (resultETy != outputZpETy)
1153 return op.emitOpError(
"expect both output and its zero point are the same "
1154 "element type, got ")
1155 << resultETy <<
" and " << outputZpETy;
1157 FailureOr<int64_t> maybeIZp = op.getInputZeroPoint();
1158 if (succeeded(maybeIZp) && op.verifyInputZeroPoint(*maybeIZp).failed())
1161 FailureOr<int64_t> maybeOZp = op.getOutputZeroPoint();
1162 if (succeeded(maybeOZp) && op.verifyOutputZeroPoint(*maybeOZp).failed())
1169struct AdaptivePoolingConstShapeValues {
1170 llvm::SmallVector<int64_t> kernel;
1171 llvm::SmallVector<int64_t> stride;
1172 llvm::SmallVector<int64_t> pad;
1176template <
typename T>
1178 std::is_same_v<T, tosa::AvgPool2dAdaptiveOp> ||
1179 std::is_same_v<T, tosa::MaxPool2dAdaptiveOp>;
1181template <
typename T,
1182 typename std::enable_if<IsSupportedAdaptivePoolConstShapeVerifyOp<T>,
1185 T op, AdaptivePoolingConstShapeValues &values) {
1191LogicalResult tosa::AvgPool2dOp::verify() {
1199LogicalResult tosa::AvgPool2dAdaptiveOp::verify() {
1200 AdaptivePoolingConstShapeValues values;
1209 values.pad, getInput(), getOutput())))
1218LogicalResult tosa::ClampOp::verify() {
1220 llvm::cast<ShapedType>(getInput().
getType()).getElementType();
1221 if (
auto quantType =
1222 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(inputETy)) {
1226 llvm::cast<ShapedType>(getOutput().
getType()).getElementType();
1227 if (
auto quantType =
1228 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(outputETy)) {
1231 if (inputETy != outputETy)
1232 return emitOpError(
"input/output element types are incompatible.");
1234 auto maxValAttr = getMaxValAttr();
1235 auto minValAttr = getMinValAttr();
1239 if (inputETy.
isInteger(dataTypeBitWidth)) {
1243 auto intMaxValAttr = mlir::dyn_cast<mlir::IntegerAttr>(maxValAttr);
1244 auto intMinValAttr = mlir::dyn_cast<mlir::IntegerAttr>(minValAttr);
1245 if (!intMaxValAttr || !intMinValAttr ||
1246 (intMaxValAttr.getType() != intMinValAttr.getType()) ||
1247 (intMaxValAttr.getType() != inputETy))
1248 return emitOpError(
"min/max attributes types are incompatible with "
1249 "input/output element types.");
1252 const bool isBoolean = inputETy.
isInteger(1);
1253 const APInt minVal = intMinValAttr.getValue();
1254 const APInt maxVal = intMaxValAttr.getValue();
1255 if ((isUnsigned || isBoolean) ? maxVal.ult(minVal) : maxVal.slt(minVal))
1256 return emitOpError(
"expected min_val <= max_val, got min_val=")
1257 << minValAttr <<
", max_val=" << maxValAttr;
1262 auto floatMaxValAttr = mlir::dyn_cast<mlir::FloatAttr>(maxValAttr);
1263 auto floatMinValAttr = mlir::dyn_cast<mlir::FloatAttr>(minValAttr);
1264 if (!floatMaxValAttr || !floatMinValAttr ||
1265 (floatMaxValAttr.getType() != floatMinValAttr.getType()) ||
1266 (floatMaxValAttr.getType() != inputETy))
1267 return emitOpError(
"min/max attributes types are incompatible with "
1268 "input/output element types.");
1270 const APFloat minVal = floatMinValAttr.getValue();
1271 const APFloat maxVal = floatMaxValAttr.getValue();
1272 if (minVal.isNaN() || maxVal.isNaN())
1273 return emitOpError(
"min/max attributes should not be 'NaN', got min_val=")
1274 << minValAttr <<
", max_val=" << maxValAttr;
1276 if (maxVal < minVal)
1277 return emitOpError(
"expected min_val <= max_val, got min_val=")
1278 << minValAttr <<
", max_val=" << maxValAttr;
1298 result.addOperands({input, weight, bias, zps.first, zps.second});
1299 result.addAttribute(
"pad", pad);
1300 result.addAttribute(
"stride", stride);
1301 result.addAttribute(
"dilation", dilation);
1302 result.addAttribute(
"acc_type", accType);
1303 Type finalOutputType = outputType;
1309 result.addTypes(finalOutputType);
1320 result.addOperands({input, weight, bias, zps.first, zps.second});
1321 result.addAttribute(
"out_pad", outpad);
1322 result.addAttribute(
"stride", stride);
1323 result.addAttribute(
"acc_type", accType);
1324 Type finalOutputType = outputType;
1330 result.addTypes(finalOutputType);
1337 result.addOperands({a,
b, zps.first, zps.second});
1339 Type finalOutputType{outputType};
1342 auto inputBits = eType.getIntOrFloatBitWidth();
1344 auto outputShapedType = llvm::dyn_cast<ShapedType>(outputType);
1345 assert(outputShapedType &&
"Output must be a shaped type");
1347 IntegerType accElementType;
1348 if (inputBits == 16)
1353 finalOutputType = outputShapedType.clone(accElementType);
1355 result.addTypes(finalOutputType);
1376 DenseArrayAttr kernel, DenseArrayAttr stride,
1377 DenseArrayAttr pad, TypeAttr accType) {
1382 if (
auto quantAttr =
1384 inputZp = quantAttr.getInputZp();
1385 outputZp = quantAttr.getOutputZp();
1387 const std::optional<Value> inputZpOp =
1392 "Failed to create input zero point tensor for quantized AVG_POOL2D op");
1394 const std::optional<Value> outputZpOp =
1397 (
void)
emitError(loc,
"Failed to create output zero point tensor for "
1398 "quantized AVG_POOL2D op");
1401 if (inputZpOp && outputZpOp) {
1402 result.addOperands({input, inputZpOp.value(), outputZpOp.value()});
1407 result.addOperands({input});
1409 result.addAttribute(
"kernel", kernel);
1410 result.addAttribute(
"stride", stride);
1411 result.addAttribute(
"pad", pad);
1412 result.addAttribute(
"acc_type", accType);
1413 result.types.push_back(outputType);
1426 if (
auto quantAttr =
1428 inputZp = quantAttr.getInputZp();
1429 outputZp = quantAttr.getOutputZp();
1431 const std::optional<Value> inputZpOp =
1435 "Failed to create input zero point tensor for quantized "
1436 "AVG_POOL2D_ADAPTIVE op");
1438 const std::optional<Value> outputZpOp =
1441 (
void)
emitError(loc,
"Failed to create output zero point tensor for "
1442 "quantized AVG_POOL2D_ADAPTIVE op");
1445 if (inputZpOp && outputZpOp) {
1450 result.addOperands({input, inputZpOp.value(), outputZpOp.value(),
1451 kernelShape, strideShape, padShape});
1456 result.addOperands({input});
1458 result.addAttribute(
"acc_type", accType);
1459 result.types.push_back(outputType);
1473 input1Zp = quantAttr.getInputZp();
1474 outputZp = quantAttr.getOutputZp();
1476 const std::optional<Value> input1ZpOp =
1480 loc,
"Failed to create input1 zero point for quantized NEGATE op");
1483 const std::optional<Value> outputZpOp =
1487 loc,
"Failed to create output zero point for quantized NEGATE op");
1490 if (input1ZpOp && outputZpOp) {
1491 result.addOperands({input, input1ZpOp.value(), outputZpOp.value()});
1496 result.addOperands({input});
1499 result.types.push_back(outputType);
1512 zp =
static_cast<int32_t
>(quantAttr.getInputZp());
1515 result.addOperands({input, paddings, padConstOp});
1516 result.types.push_back(outputType);
1520 StringRef name,
Type variableType,
1525 auto shapedType = dyn_cast<ShapedType>(variableType);
1527 (
void)
emitError(loc,
"variable type must be a shaped type");
1530 if (!shapedType.hasRank()) {
1531 (
void)
emitError(loc,
"variable type must be a ranked type");
1535 auto elementType = shapedType.getElementType();
1536 auto elementTypeAttr = TypeAttr::get(elementType);
1540 result.addAttribute(
"sym_name", nameAttr);
1541 result.addAttribute(
"var_shape", varShapeAttr);
1542 result.addAttribute(
"type", elementTypeAttr);
1543 result.addAttribute(
"initial_value", initialValue);
1556 if (ShapedType::isStatic(dim1) && ShapedType::isStatic(dim2) && dim1 != dim2)
1560 return ShapedType::isDynamic(dim1) ? dim2 : dim1;
1566 for (
int i = 0, e = operands.size(); i != e; ++i) {
1568 if (!
shape.hasRank()) {
1573 outRank = std::max<int64_t>(outRank,
shape.getRank());
1576 outShape.resize(outRank, 1);
1578 for (
int i = 0, e = operands.size(); i != e; ++i) {
1580 auto rankDiff = outShape.size() -
shape.getRank();
1582 for (
size_t i = 0, e =
shape.getRank(); i < e; ++i) {
1583 auto dim1 = outShape[i + rankDiff];
1584 auto dim2 =
shape.getDimSize(i);
1586 const FailureOr<int64_t> maybeResolvedDim =
1588 if (failed(maybeResolvedDim))
1590 const int64_t resolvedDim = *maybeResolvedDim;
1591 outShape[i + rankDiff] = resolvedDim;
1598LogicalResult tosa::ArgMaxOp::inferReturnTypeComponents(
1599 MLIRContext *context, ::std::optional<Location> location,
1600 ArgMaxOp::Adaptor adaptor,
1603 inferredReturnShapes);
1606LogicalResult tosa::ArgMinOp::inferReturnTypeComponents(
1607 MLIRContext *context, ::std::optional<Location> location,
1608 ArgMinOp::Adaptor adaptor,
1611 inferredReturnShapes);
1614LogicalResult tosa::RFFT2dOp::inferReturnTypeComponents(
1615 MLIRContext *context, ::std::optional<Location> location,
1616 RFFT2dOp::Adaptor adaptor,
1618 ShapeAdaptor inputShape(adaptor.getInputReal().getType());
1620 if (!inputShape.hasRank())
1624 outputShape.resize(3, ShapedType::kDynamic);
1625 outputShape[0] = inputShape.getDimSize(0);
1626 outputShape[1] = inputShape.getDimSize(1);
1627 int64_t inWidth = inputShape.getDimSize(2);
1631 if (inWidth != ShapedType::kDynamic)
1632 outputShape[2] = inWidth / 2 + 1;
1641 const llvm::StringRef dimName) {
1642 const bool isPowerOfTwo = (dimSize & (dimSize - 1)) == 0 && dimSize > 0;
1645 << dimName <<
" to be a power of two, got " << dimSize;
1650LogicalResult tosa::RFFT2dOp::verify() {
1651 const auto outputTypes = getResultTypes();
1653 return emitOpError(
"expected output shapes to match, got ") << outputTypes;
1655 const auto inputType =
1656 llvm::dyn_cast<RankedTensorType>(getInputReal().
getType());
1660 const int64_t height = inputType.getDimSize(1);
1661 if (ShapedType::isStatic(height) &&
1665 const int64_t width = inputType.getDimSize(2);
1666 if (ShapedType::isStatic(width) &&
1670 const auto outputType = llvm::dyn_cast<RankedTensorType>(outputTypes[0]);
1676 outputType.getShape().drop_back())))
1677 return emitOpError(
"expected batch and height dimensions of input/output "
1678 "to match, got input=")
1679 << inputType <<
" output=" << outputType;
1682 const int64_t outputWidth = outputType.getDimSize(2);
1683 if (ShapedType::isStatic(width) && ShapedType::isStatic(outputWidth) &&
1684 (outputWidth != (width / 2) + 1))
1686 "expected output width to be equal to input_width / 2 + 1, got ")
1692LogicalResult tosa::FFT2dOp::inferReturnTypeComponents(
1693 MLIRContext *context, ::std::optional<Location> location,
1694 FFT2dOp::Adaptor adaptor,
1696 inferredReturnShapes.push_back(
1698 inferredReturnShapes.push_back(
1703LogicalResult tosa::FFT2dOp::verify() {
1704 const auto inputRealType =
1705 llvm::dyn_cast<RankedTensorType>(getInputReal().
getType());
1706 const auto inputImagType =
1707 llvm::dyn_cast<RankedTensorType>(getInputImag().
getType());
1708 if (!inputRealType || !inputImagType)
1711 const auto trySelectStaticDim = [](
const int64_t a,
const int64_t b) {
1712 return ShapedType::isDynamic(a) ? a :
b;
1715 const int64_t height = trySelectStaticDim(inputRealType.getDimSize(1),
1716 inputImagType.getDimSize(1));
1717 if (ShapedType::isStatic(height) &&
1721 const int64_t width = trySelectStaticDim(inputRealType.getDimSize(2),
1722 inputImagType.getDimSize(2));
1723 if (ShapedType::isStatic(width) &&
1730LogicalResult tosa::ConcatOp::inferReturnTypeComponents(
1731 MLIRContext *context, ::std::optional<Location> location,
1732 ConcatOp::Adaptor adaptor,
1735 const Properties &prop = adaptor.getProperties();
1736 int32_t axis = prop.axis.getValue().getSExtValue();
1738 bool hasRankedInput =
false;
1739 for (
auto operand : adaptor.getOperands()) {
1741 if (!operandShape.hasRank())
1745 if (!hasRankedInput)
1746 outputShape.resize(operandShape.getRank(), ShapedType::kDynamic);
1749 for (
int i = 0, s = operandShape.getRank(); i < s; i++) {
1750 if (i == axis || operandShape.isDynamicDim(i))
1752 if (outputShape[i] == ShapedType::kDynamic)
1753 outputShape[i] = operandShape.getDimSize(i);
1754 if (outputShape[i] != operandShape.getDimSize(i))
1756 "Cannot concat tensors with different sizes"
1757 " on the non-axis dimension ",
1761 hasRankedInput =
true;
1764 if (adaptor.getInput1().empty())
1768 llvm::cast<TensorType>(adaptor.getInput1().getType()[0]).getElementType();
1769 if (!hasRankedInput) {
1776 for (
auto operand : adaptor.getOperands()) {
1781 if (!operandShape.hasRank() || operandShape.isDynamicDim(axis)) {
1782 concatDimSize = ShapedType::kDynamic;
1786 concatDimSize += operandShape.getDimSize(axis);
1789 outputShape[axis] = concatDimSize;
1795LogicalResult tosa::ConcatOp::verify() {
1797 auto outType = getOutput().getType();
1801 if (inputList.empty())
1802 return emitOpError(
"expect at least one input");
1804 if (!llvm::all_of(inputList, [&](
auto input) {
1806 *
this, input.getType(), outType));
1811 const int32_t axis = getAxis();
1813 for (
const auto &input : inputList) {
1814 const Type inputType = input.getType();
1816 if (currShape.hasRank()) {
1817 firstRankedInputShape = currShape;
1819 if (axis < 0 || axis >= firstRankedInputShape.
getRank())
1820 return emitOpError(
"expect axis to be within range 0 < axis < "
1821 "rank(input1[firstRankedTensorIdx]), got ")
1827 const auto allOperandsHasRank = [](
const Value input) {
1830 if (llvm::all_of(inputList, allOperandsHasRank)) {
1833 for (
const auto &[
index, input] : llvm::enumerate(inputList.drop_front())) {
1835 const int64_t inputRank = inputShape.getRank();
1836 const size_t operandNum =
index + 1;
1839 if (inputRank != firstInputRank)
1841 "expect all operands to have the same rank, but got ")
1842 << firstInputRank <<
" vs " << inputRank <<
" on operands 0 and "
1846 for (
int i = 0; i < inputRank; i++) {
1847 const int64_t inputDim = inputShape.getDimSize(i);
1849 if (i == axis || firstRankedInputShape.
isDynamicDim(i) ||
1850 inputShape.isDynamicDim(i))
1852 if (inputDim != firstInputDim)
1853 return emitOpError(
"expect all operand shapes to have the same sizes "
1854 "on non-axis dimensions, but got ")
1855 << inputDim <<
" vs " << firstInputDim <<
" at index " << i
1856 <<
" on operands 0 and " << operandNum;
1861 if (outputShape.hasRank() && outputShape.getRank() != firstInputRank)
1862 return emitOpError(
"expect output rank to match inputs rank, got ")
1863 << outputShape.getRank() <<
" vs " << firstInputRank;
1867 for (
const auto &input : inputList) {
1869 if (inputShape.isDynamicDim(axis)) {
1874 axisSum += inputShape.getDimSize(axis);
1877 if (axisSum >= 0 && outputShape.hasRank() &&
1878 !outputShape.isDynamicDim(axis) &&
1879 axisSum != outputShape.getDimSize(axis))
1880 return emitOpError(
"requires sum of axis dimensions of input1 "
1881 "equal to output axis dimension, got ")
1882 << axisSum <<
" and " << outputShape.getDimSize(axis);
1888LogicalResult tosa::EqualOp::inferReturnTypeComponents(
1889 MLIRContext *context, ::std::optional<Location> location,
1893 auto elementType = IntegerType::get(context, 1);
1906 if (l.size() != r.size() || l.size() != 1)
1916 if (!
shape.hasRank())
1917 return ShapedType::kDynamic;
1918 const int64_t inputAxis = axis - (outputRank -
shape.getRank());
1919 return inputAxis < 0 ? 1 :
shape.getDimSize(inputAxis);
1922static FailureOr<SmallVector<int64_t>>
1924 int64_t outputRank,
bool transposeB) {
1925 if (outputRank < 2 ||
1933 for (
int64_t axis = 0; axis < outputRank - 2; ++axis) {
1937 if (failed(resolvedDim))
1939 outputShape[axis] = *resolvedDim;
1945 outputShape[outputRank - 1] =
1960 inferredReturnShapes.emplace_back();
1967 if (ShapedType::isStatic(aChannels) && ShapedType::isStatic(bChannels) &&
1968 aChannels != bChannels)
1972 FailureOr<SmallVector<int64_t>> outputShape =
1974 if (failed(outputShape))
1977 inferredReturnShapes.emplace_back(*outputShape);
1981LogicalResult tosa::MatMulOp::inferReturnTypeComponents(
1982 MLIRContext *context, ::std::optional<Location> location,
1983 MatMulOp::Adaptor adaptor,
1988 inferredReturnShapes);
1991template <
typename T>
1993 Type bElementType) {
1994 const auto aQuantizedEType =
1995 llvm::dyn_cast<quant::UniformQuantizedType>(aElementType);
1996 const auto bQuantizedEType =
1997 llvm::dyn_cast<quant::UniformQuantizedType>(bElementType);
1999 if (aQuantizedEType || bQuantizedEType) {
2000 if (!aQuantizedEType || !bQuantizedEType) {
2001 return op.emitOpError(
"expect operands to be both quantized or both not "
2003 << aElementType <<
" and " << bElementType;
2006 auto aQuantWidth = aQuantizedEType.getStorageTypeIntegralWidth();
2007 auto bQuantWidth = bQuantizedEType.getStorageTypeIntegralWidth();
2008 if (aQuantWidth != bQuantWidth) {
2009 return op.emitOpError(
"expect quantized operands to have same widths, "
2011 << aQuantWidth <<
" and " << bQuantWidth;
2018template <
typename T>
2020 StringRef inputName,
2025 Type expectedElementType = inputStorageElementType;
2027 if (isa<BlockScaledType>(inputElementType))
2028 expectedElementType = Float32Type::get(op.getContext());
2030 if (expectedElementType == zpElementType)
2034 diag << inputName <<
" and " << zpName;
2035 if (isa<BlockScaledType>(inputElementType))
2036 diag <<
" have compatible element types, got " << inputElementType
2037 <<
" and " << zpElementType;
2039 diag <<
" have the same element type, got " << inputStorageElementType
2040 <<
" and " << zpElementType;
2048 batchShape.reserve(
shape.getRank() - 2);
2049 for (
int64_t i = 0, e =
shape.getRank() - 2; i < e; ++i)
2050 batchShape.push_back(
shape.getDimSize(i));
2054template <
typename T>
2058 const auto outputType = cast<ShapedType>(op.getResult().getType());
2061 : ShapedType::kDynamic;
2069 const int64_t minimumOutputRank =
2072 if (outputType.hasRank() && outputType.getRank() < minimumOutputRank)
2073 return op.emitOpError(
"expected output rank of at least ")
2074 << minimumOutputRank <<
", got " << outputType.getRank();
2076 const bool bothInputsRanked = aShape.
hasRank() && bShape.
hasRank();
2077 if (!bothInputsRanked && !outputType.hasRank())
2082 const int64_t expectedOutputRank =
2083 bothInputsRanked ? minimumOutputRank : outputType.getRank();
2084 FailureOr<SmallVector<int64_t>> expectedOutputShape =
2086 if (failed(expectedOutputShape)) {
2088 "expected batch dimensions of a and b to be broadcast compatible, "
2091 diag <<
"] and b=[";
2097 if (outputType.hasRank())
2099 op.getOperation(), outputType, *expectedOutputShape);
2103LogicalResult MatMulOp::verify() {
2115 FailureOr<int64_t> maybeAZp = getAZeroPoint();
2116 if (succeeded(maybeAZp) && verifyAZeroPoint(*maybeAZp).failed())
2119 FailureOr<int64_t> maybeBZp = getBZeroPoint();
2120 if (succeeded(maybeBZp) && verifyBZeroPoint(*maybeBZp).failed())
2126LogicalResult tosa::MatMulTOp::inferReturnTypeComponents(
2127 MLIRContext *context, ::std::optional<Location> location,
2128 MatMulTOp::Adaptor adaptor,
2133 inferredReturnShapes);
2136LogicalResult MatMulTOp::verify() {
2148 FailureOr<int64_t> maybeAZp = getAZeroPoint();
2149 if (succeeded(maybeAZp) && verifyAZeroPoint(*maybeAZp).failed())
2152 FailureOr<int64_t> maybeBZp = getBZeroPoint();
2153 if (succeeded(maybeBZp) && verifyBZeroPoint(*maybeBZp).failed())
2159LogicalResult tosa::MatmulTBlockScaledOp::inferReturnTypeComponents(
2160 MLIRContext *context, ::std::optional<Location> location,
2161 MatmulTBlockScaledOp::Adaptor adaptor,
2165 const auto aDataShape = cast<ShapedType>(adaptor.getAData().getType());
2166 if (aDataShape.hasRank()) {
2167 outShape[0] = aDataShape.getDimSize(0);
2168 outShape[1] = aDataShape.getDimSize(1);
2171 const auto aScaleShape = cast<ShapedType>(adaptor.getAScale().getType());
2172 if (aScaleShape.hasRank()) {
2173 outShape[0] = ShapedType::isDynamic(outShape[0]) ? aScaleShape.getDimSize(0)
2175 outShape[1] = ShapedType::isDynamic(outShape[1]) ? aScaleShape.getDimSize(1)
2180 const auto bDataShape = cast<ShapedType>(adaptor.getBData().getType());
2181 if (bDataShape.hasRank()) {
2182 const int64_t bDataBatchSize = bDataShape.getDimSize(0);
2183 if (bDataBatchSize != 1)
2185 ShapedType::isDynamic(outShape[0]) ? bDataBatchSize : outShape[0];
2186 outShape[2] = bDataShape.getDimSize(1);
2189 const auto bScaleShape = cast<ShapedType>(adaptor.getBScale().getType());
2190 if (bScaleShape.hasRank()) {
2191 const int64_t bScaleBatchSize = bScaleShape.getDimSize(0);
2192 if (bScaleBatchSize != 1)
2194 ShapedType::isDynamic(outShape[0]) ? bScaleBatchSize : outShape[0];
2195 outShape[2] = ShapedType::isDynamic(outShape[2]) ? bScaleShape.getDimSize(1)
2203LogicalResult MatmulTBlockScaledOp::verify() {
2205 const Type aDataType = getAData().getType();
2206 const Type bDataType = getBData().getType();
2212 int64_t N = ShapedType::kDynamic;
2213 int64_t D = ShapedType::kDynamic;
2214 int64_t H = ShapedType::kDynamic;
2217 int64_t multiplesOfC = ShapedType::kDynamic;
2229 "a_scale",
"batch")) ||
2231 "a_scale",
"height")))
2239 "b_data",
"batch")) ||
2241 "b_data",
"channels")))
2249 "b_scale",
"batch")) ||
2251 "b_scale",
"width")) ||
2259 if (ShapedType::isStatic(N) && ShapedType::isStatic(D) && N != D && D != 1)
2260 return emitOpError(
"expect B matrix batch size to be broadcast compatible "
2262 << D <<
" vs N=" << N;
2265 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
2266 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
2267 return emitOpError(
"expect block size to be 32, got ") << blockSize;
2268 if (ShapedType::isStatic(C) && C % blockSize != 0)
2269 return emitOpError(
"expect C to be a multiple of block size, got C=")
2270 <<
C <<
", block_size=" << blockSize;
2273 if (ShapedType::isStatic(C) && ShapedType::isStatic(multiplesOfC) &&
2274 multiplesOfC != C / blockSize)
2276 "expect scale operands dimension 2 to equal C/block_size (")
2277 <<
C <<
"/" << blockSize <<
")" <<
", got " << multiplesOfC;
2280 N = ShapedType::isDynamic(N) ? D : N;
2282 const auto outputType = cast<ShapedType>(getResult().
getType());
2283 if (outputType.hasRank() &&
2288 opError <<
" to be compatible with expected output shape ";
2296LogicalResult tosa::PadOp::inferReturnTypeComponents(
2297 MLIRContext *context, ::std::optional<Location> location,
2298 PadOp::Adaptor adaptor,
2300 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2302 cast<tosa::shapeType>(adaptor.getPadding().getType()).getRank();
2307 if (!inputShape.hasRank()) {
2308 outputShape.resize(paddingRank / 2, ShapedType::kDynamic);
2317 outputShape.resize(inputShape.getRank(), ShapedType::kDynamic);
2322 outputShape.reserve(inputShape.getRank());
2323 for (
int i = 0, s = inputShape.getRank(); i < s; i++) {
2324 if (inputShape.isDynamicDim(i)) {
2325 outputShape.push_back(ShapedType::kDynamic);
2328 auto padFront = paddingValues[i * 2];
2329 auto padBack = paddingValues[i * 2 + 1];
2330 outputShape.push_back(inputShape.getDimSize(i) + padFront + padBack);
2337LogicalResult tosa::PadOp::verify() {
2344 if (
auto padConst = getPadConst()) {
2352 RankedTensorType inputType =
2353 llvm::dyn_cast<RankedTensorType>(getInput1().
getType());
2354 RankedTensorType outputType =
2355 llvm::dyn_cast<RankedTensorType>(getOutput().
getType());
2356 if (!inputType || !outputType)
2363 auto inputRank = inputType.getRank();
2364 auto paddingRank = cast<tosa::shapeType>(getPadding().
getType()).getRank();
2365 if (paddingRank != inputRank * 2)
2366 return emitOpError() <<
"padding tensor must have " << inputRank
2367 <<
" * 2 = " << inputRank * 2 <<
" elements, but got "
2373LogicalResult tosa::SliceOp::inferReturnTypeComponents(
2374 MLIRContext *context, ::std::optional<Location> location,
2375 SliceOp::Adaptor adaptor,
2384 auto rank = cast<tosa::shapeType>(adaptor.getSize().getType()).getRank();
2392 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2395 if (inputShape.hasRank()) {
2396 for (
size_t i = 0; i < size.size(); i++) {
2397 if (size[i] != 0 && size[i] >= -1 && start[i] >= 0 &&
2398 (ShapedType::isDynamic(inputShape.getDimSize(i)) ||
2399 start[i] < inputShape.getDimSize(i))) {
2401 if (ShapedType::isDynamic(inputShape.getDimSize(i))) {
2404 outputShape[i] = size[i];
2408 if (size[i] == -1) {
2409 outputShape[i] = inputShape.getDimSize(i) - start[i];
2410 }
else if (start[i] + size[i] <= inputShape.getDimSize(i)) {
2412 outputShape[i] = size[i];
2424LogicalResult tosa::SliceOp::verify() {
2425 const Value input = getInput1();
2426 const Value output = getOutput();
2432 const Value start = getStart();
2433 const Value size = getSize();
2437 if (inputShape.hasRank()) {
2438 const auto inputRank = inputShape.getRank();
2439 if (outputShape.hasRank() && inputRank != outputShape.getRank())
2441 "expect input1 and output to have the same ranks, got ")
2442 << inputRank <<
" and " << outputShape.getRank();
2444 const auto startShapeRank =
2445 llvm::cast<tosa::shapeType>(start.
getType()).getRank();
2446 if (inputRank != startShapeRank)
2447 return emitOpError(
"length of start is not equal to rank of input shape");
2449 const auto sizeShapeRank =
2450 llvm::cast<tosa::shapeType>(size.
getType()).getRank();
2451 if (inputRank != sizeShapeRank)
2452 return emitOpError(
"length of size is not equal to rank of input shape");
2457 if (startValues.size()) {
2458 if (llvm::any_of(startValues, [](
const int64_t v) {
2461 return emitOpError(
"start values must be non-negative, got [")
2462 << startValues <<
"]";
2468 if (
const auto blockScaledType = llvm::dyn_cast<BlockScaledType>(elemType)) {
2469 const auto startBlock = startValues.back();
2470 const auto scaleBlock =
2471 BlockShapeAttr::getBlockShapeValue(blockScaledType.getBlockShape());
2472 if (startBlock % scaleBlock != 0) {
2474 "expected start innermost block size to match data type "
2475 "for block scaled input, got start block=")
2476 << startBlock <<
", scale block=" << scaleBlock;
2484 if (llvm::any_of(sizeValues, [](
const int64_t v) {
2487 return emitOpError(
"size values must be > 0, got [") << sizeValues <<
"]";
2488 if (outputShape.hasRank()) {
2490 outputShape.getDims(outputDims);
2491 const bool hasNoInferableDims = llvm::all_of(
2493 if (hasNoInferableDims &&
2495 return emitOpError(
"expected output shape to match size values, got ")
2496 << output.
getType() <<
" vs [" << sizeValues <<
"]";
2499 if (inputShape.hasRank() && startValues.size()) {
2501 inputShape.getDims(inputDims);
2502 for (
const auto &[
index, vals] :
2503 llvm::enumerate(llvm::zip_equal(startValues, sizeValues, inputDims))) {
2504 const auto &[start, size, inputDim] = vals;
2506 ShapedType::isDynamic(inputDim))
2508 if (start + size > inputDim)
2509 return emitOpError(
"start + size must be less than or equal to input "
2510 "dimension size, got start=")
2511 << start <<
", size=" << size
2512 <<
" vs input dim size=" << inputDim <<
" at dimension "
2520LogicalResult tosa::MulOp::inferReturnTypeComponents(
2521 MLIRContext *context, ::std::optional<Location> location,
2536LogicalResult tosa::MulOp::verify() {
2537 const Value output = getOutput();
2542 if (
auto resIntType = dyn_cast<IntegerType>(resElemType)) {
2543 IntegerType lhsIntType =
2545 IntegerType rhsIntType =
2547 if (!lhsIntType || !rhsIntType || lhsIntType != rhsIntType)
2548 return emitOpError(
"requires the same element type for all operands");
2553 if (lhsIntType.getWidth() > resIntType.getWidth())
2554 return emitOpError(
"invalid data type size for operands or result");
2559 for (
int i = 0; i < 2; ++i) {
2562 "requires the same element type for all operands and results");
2569 TypeRange operandTypes = getOperandTypes();
2570 ShapedType aType = cast<ShapedType>(operandTypes[0]);
2571 ShapedType bType = cast<ShapedType>(operandTypes[1]);
2573 const bool aHasRank = aType.hasRank();
2574 const bool bHasRank = bType.hasRank();
2576 bool hasExpectedOutputShape =
false;
2579 if (aHasRank && bHasRank) {
2580 const int64_t aRank = aType.getRank();
2581 const int64_t bRank = bType.getRank();
2583 return emitOpError(
"a and b operands don't have matching ranks, got ")
2584 << aRank <<
" and " << bRank;
2588 aType.getShape(), bType.getShape(), expectedOutputShape))
2589 return emitOpError(
"a and b operands don't have broadcast-compatible "
2591 << aType <<
" and " << bType;
2592 hasExpectedOutputShape =
true;
2595 ShapedType resultType = cast<ShapedType>(output.
getType());
2596 if (!resultType.hasRank())
2599 const int64_t resultRank = resultType.getRank();
2600 if (aHasRank && resultRank != aType.getRank())
2601 return emitOpError(
"result type has different rank than a, got ")
2602 << resultRank <<
" vs " << aType.getRank();
2603 if (bHasRank && resultRank != bType.getRank())
2604 return emitOpError(
"result type has different rank than b, got ")
2605 << resultRank <<
" vs " << bType.getRank();
2607 if (hasExpectedOutputShape &&
2609 expectedOutputShape)))
2615LogicalResult tosa::TableOp::inferReturnTypeComponents(
2616 MLIRContext *context, ::std::optional<Location> location,
2617 TableOp::Adaptor adaptor,
2619 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2621 if (!inputShape.hasRank()) {
2626 inferredReturnShapes.resize(1);
2627 inputShape.getDims(inferredReturnShapes[0]);
2631LogicalResult tosa::TableOp::verify() {
2632 const TensorType inputType = getInput1().getType();
2633 const TensorType outputType = getOutput().getType();
2642 auto inputDims = inputType.
getShape();
2643 auto outputDims = outputType.
getShape();
2644 for (
auto it : llvm::enumerate(llvm::zip(inputDims, outputDims))) {
2646 auto [inputDim, outputDim] = it.value();
2647 if (ShapedType::isStatic(outputDim) && outputDim != inputDim) {
2648 return emitOpError() <<
"dim(result, " << dim <<
") = " << outputDim
2649 <<
" doesn't match dim(input, " << dim
2650 <<
") = " << inputDim;
2663 llvm::map_to_vector(multiplesAttr.getValues<APInt>(),
2664 [](
const APInt &val) { return val.getSExtValue(); });
2668LogicalResult tosa::TileOp::inferReturnTypeComponents(
2669 MLIRContext *context, ::std::optional<Location> location,
2670 TileOp::Adaptor adaptor,
2677 cast<tosa::shapeType>(adaptor.getMultiples().getType()).getRank();
2684 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2686 if (!inputShape.hasRank()) {
2687 outputShape.resize(multiples.size(), ShapedType::kDynamic);
2688 inferredReturnShapes.push_back(
2692 if (
static_cast<size_t>(inputShape.getRank()) != multiples.size())
2696 outputShape.reserve(multiples.size());
2697 for (
int i = 0, s = inputShape.getRank(); i < s; i++) {
2698 if (multiples[i] == ShapedType::kDynamic) {
2699 outputShape.push_back(ShapedType::kDynamic);
2701 int64_t dim = inputShape.getDimSize(i);
2702 if (dim != ShapedType::kDynamic)
2703 dim *= multiples[i];
2704 outputShape.push_back(dim);
2712LogicalResult tosa::TileOp::verify() {
2718 ShapedType inputType = llvm::cast<ShapedType>(getInput1().
getType());
2719 ShapedType outputType = llvm::cast<ShapedType>(
getType());
2721 shapeType multiplesType =
2722 llvm::cast<tosa::shapeType>(getMultiples().
getType());
2724 auto multiplesRank = multiplesType.getRank();
2726 if (inputType.hasRank()) {
2727 if (inputType.getRank() != multiplesRank)
2728 return emitOpError(
"expect 'multiples' to have rank ")
2729 << inputType.getRank() <<
" but got " << multiplesRank <<
".";
2730 if (outputType.hasRank() &&
2734 }
else if (outputType.hasRank() && outputType.getRank() != multiplesRank)
2735 return emitOpError(
"expect 'multiples' array to have length ")
2736 << outputType.getRank() <<
" but got " << multiplesRank <<
".";
2739 if (getConstantMultiples(multiples).succeeded() &&
2740 llvm::any_of(multiples, [](
int64_t v) {
return v <= 0 && v != -1; }))
2742 "expect element of 'multiples' to be positive integer or -1.");
2748 if (l.size() != r.size() || l.size() != 1)
2753LogicalResult tosa::ReshapeOp::inferReturnTypeComponents(
2754 MLIRContext *context, ::std::optional<Location> location,
2755 ReshapeOp::Adaptor adaptor,
2757 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2762 auto rank = cast<tosa::shapeType>(adaptor.getShape().getType()).getRank();
2771 if (!inputShape.hasRank() || !inputShape.hasStaticShape()) {
2772 inferredReturnShapes.push_back(
2780 int64_t numElements = inputShape.getNumElements();
2782 for (
auto val : newShapeValue) {
2783 if (ShapedType::isStatic(val)) {
2789 for (
auto &val : newShapeValue) {
2790 if (ShapedType::isDynamic(val))
2791 val = numElements / staticMul;
2794 inferredReturnShapes.push_back(
2799llvm::LogicalResult tosa::ReshapeOp::verify() {
2805 TensorType inputType = getInput1().getType();
2810 return mlir::success();
2814 if (missingDims > 1)
2815 return emitOpError() <<
"expected at most one target dimension to be "
2818 const auto outputType = dyn_cast<RankedTensorType>(
getType());
2822 if ((
int64_t)shapeValues.size() != outputType.getRank())
2823 return emitOpError() <<
"new shape does not match result rank";
2825 for (
auto [newShapeDim, outputShapeDim] :
2826 zip(shapeValues, outputType.getShape())) {
2828 newShapeDim != ShapedType::kDynamic &&
2829 outputShapeDim != ShapedType::kDynamic && newShapeDim != outputShapeDim)
2830 return emitOpError() <<
"new shape is inconsistent with result shape";
2833 return emitOpError() <<
"new shape has invalid tensor dimension size "
2837 if (inputType.hasStaticShape()) {
2838 int64_t inputElementsNum = inputType.getNumElements();
2839 if (outputType.hasStaticShape()) {
2840 int64_t outputElementsNum = outputType.getNumElements();
2841 if (inputElementsNum != outputElementsNum) {
2842 return emitOpError() <<
"cannot reshape " << inputElementsNum
2843 <<
" elements into " << outputElementsNum;
2849 return (dim > 0) ?
acc * dim :
acc;
2851 bool isStaticNewShape =
2852 llvm::all_of(shapeValues, [](
int64_t s) {
return s > 0; });
2853 if ((isStaticNewShape && inputElementsNum != newShapeElementsNum) ||
2854 (!isStaticNewShape && newShapeElementsNum > inputElementsNum)) {
2855 return emitOpError() <<
"cannot reshape " << inputElementsNum
2856 <<
" elements into " << newShapeElementsNum;
2860 return mlir::success();
2863bool tosa::ReshapeBlockScaledOp::isCompatibleReturnTypes(
TypeRange l,
2865 if (l.size() != r.size() || l.size() < 1 || l.size() > 2)
2873LogicalResult tosa::ReshapeBlockScaledOp::inferReturnTypeComponents(
2874 MLIRContext *context, ::std::optional<Location> location,
2875 ReshapeBlockScaledOp::Adaptor adaptor,
2878 const auto numInputs = adaptor.getInput().size();
2879 ShapeAdaptor inputShape(adaptor.getInput()[0].getType());
2882 const auto newShape = adaptor.getNewValueShape();
2884 auto rank = cast<tosa::shapeType>(newShape.getType()).getRank();
2893 const uint32_t blockSize =
2894 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
2897 if (numInputs == 2) {
2898 newScaleShapeValue.assign(newShapeValue.begin(), newShapeValue.end());
2899 if (!newScaleShapeValue.empty() &&
2900 ShapedType::isStatic(newScaleShapeValue.back()))
2901 newScaleShapeValue.back() /= blockSize;
2904 inferredReturnShapes.push_back(
2906 if (numInputs == 2) {
2908 for (
size_t idx = 0; idx < newShapeValue.size(); idx++) {
2909 if (ShapedType::isDynamic(newScaleShapeValue[idx])) {
2910 newScaleShapeValue[idx] = newShapeValue[idx];
2911 if (idx + 1 == newShapeValue.size())
2912 newScaleShapeValue[idx] /= blockSize;
2923llvm::LogicalResult tosa::ReshapeBlockScaledOp::verify() {
2927 if (inputList.size() == 0)
2928 return emitOpError(
"requires at least one input");
2930 if (inputList.size() > 2)
2931 return emitOpError(
"requires at most two inputs");
2933 if (inputList.size() != outputList.size())
2934 return emitOpError(
"requires number of results to match inputs");
2942 if (inputList.size() == 2 &&
2943 cast<tosa::shapeType>(getNewValueShape().
getType()).getRank() == 0)
2944 return emitOpError(
"requires new shape to have a rank greater than 0");
2946 const auto inputType = llvm::cast<ShapedType>(inputList[0].
getType());
2947 if (!inputType.hasRank())
2949 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
2951 if (inputList.size() == 2) {
2952 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
2953 return emitOpError(
"expect block size to be 32, got ") << blockSize;
2954 if (llvm::any_of(inputList, [](
Value v) {
2955 const auto input = cast<ShapedType>(v.
getType());
2956 return input.hasRank() && input.getRank() == 0;
2959 "requires all input shapes have a rank greater than 0");
2960 if (llvm::any_of(outputList, [](
Value v) {
2961 const auto output = cast<ShapedType>(v.
getType());
2962 return output.hasRank() && output.getRank() == 0;
2965 "requires all result shapes have a rank greater than 0");
2973 const auto inputScaleType = llvm::cast<ShapedType>(inputList[1].
getType());
2974 if (inputScaleType.hasRank()) {
2975 if (inputType.getRank() != inputScaleType.getRank())
2976 return emitOpError(
"input shapes do not have same rank");
2979 for (
auto dimIdx = 0; dimIdx < inputType.getRank() - 1; dimIdx++) {
2980 const int64_t inputValueDim = inputType.getDimSize(dimIdx);
2981 const int64_t inputScaleDim = inputScaleType.getShape()[dimIdx];
2982 if (ShapedType::isStatic(inputValueDim) &&
2983 ShapedType::isStatic(inputScaleDim) &&
2984 inputValueDim != inputScaleDim)
2985 return emitOpError(
"input shapes for data and scale do not match on "
2992 inputType.getDimSize(inputType.getRank() - 1);
2993 if (ShapedType::isStatic(lastValueDim)) {
2994 if (lastValueDim % blockSize != 0)
2995 return emitOpError(
"expect last dimension of input_data (")
2996 << lastValueDim <<
") to be divisible by block_size ("
2997 << blockSize <<
")";
3000 inputScaleType.getDimSize(inputScaleType.getRank() - 1);
3002 if (ShapedType::isStatic(lastScaleDim) &&
3003 lastScaleDim != lastValueDim / blockSize)
3004 return emitOpError(
"expect last dimension of scale_data (")
3005 << lastScaleDim <<
") to be " << lastValueDim <<
"/"
3010 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_1))
3011 return emitOpError(
"expect block size to be 1, got ") << blockSize;
3019 return mlir::success();
3022 if (inputList.size() == 2) {
3023 const int64_t lastShapeDim = shapeValues.back();
3024 if (ShapedType::isStatic(lastShapeDim) && lastShapeDim % blockSize != 0)
3025 return emitOpError(
"expect last dimension of new shape (")
3026 << lastShapeDim <<
") to be divisible by block_size (" << blockSize
3030 const auto outputType = llvm::cast<ShapedType>(outputList[0].
getType());
3031 if (!outputType.hasRank())
3034 if (
static_cast<int64_t>(shapeValues.size()) != outputType.getRank())
3035 return emitOpError() <<
"result does not match new shape rank";
3037 for (
auto [newShapeDim, outputShapeDim] :
3038 zip(shapeValues, outputType.getShape())) {
3039 if (ShapedType::isStatic(newShapeDim) &&
3040 ShapedType::isStatic(outputShapeDim) && newShapeDim != outputShapeDim)
3041 return emitOpError() <<
"result shape is inconsistent with new shape";
3044 if (outputList.size() == 2) {
3048 scaleShapeValues.back() /= blockSize;
3050 const auto outputScaleType =
3051 llvm::cast<ShapedType>(outputList[1].
getType());
3052 if (outputScaleType.hasRank()) {
3053 if ((
int64_t)scaleShapeValues.size() != outputScaleType.getRank())
3054 return emitOpError() <<
"result scale does not match new shape rank";
3056 for (
auto [newScaleShapeDim, outputScaleShapeDim] :
3057 zip(scaleShapeValues, outputScaleType.getShape())) {
3058 if (ShapedType::isStatic(newScaleShapeDim) &&
3059 ShapedType::isStatic(outputScaleShapeDim) &&
3060 newScaleShapeDim != outputScaleShapeDim)
3061 return emitOpError()
3062 <<
"result scale shape is inconsistent with new shape";
3067 if (inputType.hasStaticShape()) {
3068 int64_t inputElementsNum = inputType.getNumElements();
3069 if (outputType.hasStaticShape()) {
3070 int64_t outputElementsNum = outputType.getNumElements();
3071 if (inputElementsNum != outputElementsNum) {
3072 return emitOpError() <<
"cannot reshape " << inputElementsNum
3073 <<
" elements into " << outputElementsNum;
3079 return (dim > 0) ?
acc * dim :
acc;
3081 bool isStaticNewShape =
3082 llvm::all_of(shapeValues, [](
int64_t s) {
return s > 0; });
3083 if ((isStaticNewShape && inputElementsNum != newShapeElementsNum) ||
3084 (!isStaticNewShape && newShapeElementsNum > inputElementsNum)) {
3085 return emitOpError() <<
"cannot reshape " << inputElementsNum
3086 <<
" elements into " << newShapeElementsNum;
3090 return mlir::success();
3097 ElementsAttr zpAttr;
3102 Type zpElemType = zpAttr.getElementType();
3104 if (llvm::isa<FloatType>(zpElemType)) {
3105 if (zpAttr.getValues<APFloat>()[0].isZero()) {
3112 if (llvm::isa<IntegerType>(zpElemType)) {
3114 return zpAttr.getValues<APInt>()[0].getSExtValue();
3115 return zpAttr.getValues<APInt>()[0].getZExtValue();
3122template <
typename T>
3124 const std::string &operand) {
3127 if (!zpElemType.
isInteger(8) && zp != 0) {
3129 std::string lower = operand;
3130 llvm::transform(lower, lower.begin(), ::tolower);
3131 return op.emitOpError()
3132 << lower <<
" zero point must be zero for non-int8 integer types";
3140 const std::string &operand) {
3141 bool isInputZp = (operand ==
"Input");
3143 bool tensorUnsigned =
3144 isInputZp ? op.getInputUnsigned() : op.getOutputUnsigned();
3145 StringRef tensorName = isInputZp ?
"input" :
"output";
3151 !(zpElemType.
isInteger(16) && tensorUnsigned)) {
3152 return op.emitOpError()
3153 <<
"expect " << tensorName <<
"_zp of 0, got " << zp;
3155 if (zpElemType.
isInteger(16) && tensorUnsigned && zp != 32768) {
3156 return op.emitOpError() <<
"expect " << tensorName
3157 <<
"_zp of 0 or 32768 for unsigned int16 "
3158 << tensorName <<
", got " << zp;
3165#define ZERO_POINT_HELPER(OP, OPERAND_NAME, SIGN_EXTEND) \
3166 FailureOr<int64_t> tosa::OP::get##OPERAND_NAME##ZeroPoint() { \
3167 return getZeroPoint(get##OPERAND_NAME##Zp(), SIGN_EXTEND); \
3169 LogicalResult tosa::OP::verify##OPERAND_NAME##ZeroPoint(int64_t zp) { \
3170 return verifyZeroPoint(*this, get##OPERAND_NAME##Zp(), zp, #OPERAND_NAME); \
3193#undef ZERO_POINT_HELPER
3195LogicalResult tosa::TransposeOp::inferReturnTypeComponents(
3196 MLIRContext *context, ::std::optional<Location> location,
3197 TransposeOp::Adaptor adaptor,
3199 ShapeAdaptor inputShape(adaptor.getInput1().getType());
3208 const auto inputRank = inputShape.
getRank();
3212 if (adaptor.getPerms().size() !=
static_cast<size_t>(inputRank)) {
3218 if (inputRank == 0) {
3224 bool allTheSame =
true;
3225 for (
int i = 1, s = inputRank; i < s; i++) {
3235 outputShape.resize(inputRank, inputShape.
getDimSize(0));
3240 outputShape.resize(inputRank, ShapedType::kDynamic);
3243 if (llvm::any_of(adaptor.getPerms(),
3244 [inputRank](
const auto i) { return i >= inputRank; }))
3247 outputShape.reserve(inputRank);
3248 for (
int i = 0, s = inputRank; i < s; i++) {
3249 outputShape[i] = inputShape.
getDimSize(adaptor.getPerms()[i]);
3256LogicalResult tosa::TransposeOp::verify() {
3268 if (inputShape.hasRank() &&
3269 constantPerms.size() !=
static_cast<size_t>(inputShape.getRank()))
3270 return emitOpError() <<
"expected perms attribute to have size "
3271 << inputShape.getRank()
3272 <<
" (input rank) but got size "
3273 << constantPerms.size();
3275 if (inputShape.hasRank() && outputShape.hasRank() &&
3276 inputShape.getRank() != outputShape.getRank())
3277 return emitOpError()
3278 <<
"expected input tensor rank to equal result tensor rank";
3280 if (outputShape.hasRank() &&
3281 constantPerms.size() !=
static_cast<size_t>(outputShape.getRank()))
3282 return emitOpError() <<
"expected perms attribute to have size "
3283 << outputShape.getRank()
3284 <<
" (output rank) but got size "
3285 << constantPerms.size();
3287 if (!llvm::all_of(constantPerms,
3288 [&constantPerms](int32_t s) {
3290 static_cast<size_t>(s) < constantPerms.size();
3293 constantPerms, [](int32_t v) ->
int64_t {
return v; })))
3294 return emitOpError() <<
"expected valid permutation indices";
3297 constantPerms.back() !=
static_cast<int32_t
>(constantPerms.size()) - 1) {
3298 return emitOpError() <<
"expected no-op permutation on innermost dimension "
3299 "for block scaled input";
3303 if (inputShape.hasStaticShape() && outputShape.hasStaticShape() &&
3304 inputShape.getNumElements() != outputShape.getNumElements())
3305 return emitOpError() <<
"expected input1 and output to have same numbers "
3307 << inputShape.getNumElements() <<
" and "
3308 << outputShape.getNumElements();
3312 if (inputShape.hasRank() && outputShape.hasRank()) {
3313 for (
auto i = 0; i < outputShape.getRank(); i++) {
3314 if (inputShape.isDynamicDim(constantPerms[i]) ||
3315 outputShape.isDynamicDim(i))
3318 if (inputShape.getDimSize(constantPerms[i]) != outputShape.getDimSize(i))
3319 return emitOpError()
3320 <<
"expected output tensor dim " << i <<
" to match "
3321 <<
"input dim " << constantPerms[i] <<
" with value of "
3322 << inputShape.getDimSize(constantPerms[i]);
3329LogicalResult TransposeOp::reifyResultShapes(
3332 const llvm::ArrayRef<int32_t> transposePerms = getPerms();
3334 Value input = getInput1();
3335 auto inputType = cast<TensorType>(input.
getType());
3337 SmallVector<OpFoldResult> returnedDims(inputType.getRank());
3338 for (
auto dim : transposePerms) {
3339 int32_t dimInInput = transposePerms[dim];
3340 if (inputType.isDynamicDim(dimInInput))
3342 tensor::DimOp::create(builder, getLoc(), input, dimInInput)
3346 builder.
getIndexAttr(inputType.getDimSize(dimInInput));
3349 reifiedReturnShapes.emplace_back(std::move(returnedDims));
3353LogicalResult tosa::GatherOp::inferReturnTypeComponents(
3354 MLIRContext *context, ::std::optional<Location> location,
3355 GatherOp::Adaptor adaptor,
3356 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3357 llvm::SmallVector<int64_t> outputShape;
3358 outputShape.resize(3, ShapedType::kDynamic);
3360 ShapeAdaptor valuesShape(adaptor.getValues().getType());
3361 if (valuesShape.hasRank()) {
3362 outputShape[0] = valuesShape.getDimSize(0);
3363 outputShape[2] = valuesShape.getDimSize(2);
3366 ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3367 if (indicesShape.hasRank()) {
3368 if (outputShape[0] == ShapedType::kDynamic)
3369 outputShape[0] = indicesShape.getDimSize(0);
3370 if (outputShape[1] == ShapedType::kDynamic)
3371 outputShape[1] = indicesShape.getDimSize(1);
3374 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3378LogicalResult tosa::RowGatherOp::inferReturnTypeComponents(
3379 MLIRContext *context, ::std::optional<Location> location,
3380 RowGatherOp::Adaptor adaptor,
3381 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3382 llvm::SmallVector<int64_t> outputShape;
3383 outputShape.resize(3, ShapedType::kDynamic);
3385 const ShapeAdaptor valuesShape(adaptor.getValues().getType());
3386 if (valuesShape.hasRank()) {
3387 outputShape[0] = valuesShape.getDimSize(0);
3388 outputShape[2] = valuesShape.getDimSize(2);
3391 const ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3392 if (indicesShape.hasRank()) {
3393 if (outputShape[0] == ShapedType::kDynamic)
3394 outputShape[0] = indicesShape.getDimSize(0);
3396 const FailureOr<int32_t> maybeRowCount =
3398 if (succeeded(maybeRowCount)) {
3399 const int64_t indicesW = indicesShape.getDimSize(1);
3400 if (ShapedType::isStatic(indicesW))
3401 outputShape[1] = indicesW * maybeRowCount.value();
3405 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3409LogicalResult tosa::RowGatherBlockScaledOp::inferReturnTypeComponents(
3410 MLIRContext *context, ::std::optional<Location> location,
3411 RowGatherBlockScaledOp::Adaptor adaptor,
3412 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3413 const auto values = adaptor.getValues();
3417 SmallVector<int64_t> dataShape(3, ShapedType::kDynamic);
3418 const ShapeAdaptor valuesShape(values.front().getType());
3419 if (valuesShape.hasRank()) {
3420 dataShape[0] = valuesShape.getDimSize(0);
3421 dataShape[2] = valuesShape.getDimSize(2);
3424 const ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3425 if (indicesShape.hasRank()) {
3426 if (dataShape[0] == ShapedType::kDynamic)
3427 dataShape[0] = indicesShape.getDimSize(0);
3431 succeeded(rowCount) && rowCount.value() > 0) {
3432 const int64_t indicesW = indicesShape.getDimSize(1);
3433 if (ShapedType::isStatic(indicesW))
3434 dataShape[1] = indicesW * rowCount.value();
3438 inferredReturnShapes.push_back(ShapedTypeComponents(dataShape));
3439 if (values.size() == 1)
3442 SmallVector<int64_t> scaleShape = dataShape;
3443 const uint32_t blockSize =
3444 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
3445 if (ShapedType::isStatic(dataShape[2]))
3446 scaleShape[2] = dataShape[2] / blockSize;
3448 inferredReturnShapes.push_back(ShapedTypeComponents(scaleShape));
3452LogicalResult tosa::GatherOp::verify() {
3459 const ShapeAdaptor valuesShape(getValues().
getType());
3461 const ShapeAdaptor outputShape(getOutput().
getType());
3463 int64_t n = ShapedType::kDynamic;
3464 int64_t w = ShapedType::kDynamic;
3465 int64_t c = ShapedType::kDynamic;
3467 if (valuesShape.hasRank()) {
3468 n = valuesShape.getDimSize(0);
3469 c = valuesShape.getDimSize(2);
3471 if (indicesShape.hasRank()) {
3472 const int64_t indicesN = indicesShape.getDimSize(0);
3473 w = indicesShape.getDimSize(1);
3474 if (n == ShapedType::kDynamic)
3476 else if (indicesN != ShapedType::kDynamic && n != indicesN)
3477 return emitOpError() <<
"requires indices dimension 0 to have size " << n
3478 <<
", got " << indicesN;
3480 if (outputShape.hasRank()) {
3481 const int64_t outputN = outputShape.getDimSize(0);
3482 const int64_t outputW = outputShape.getDimSize(1);
3483 const int64_t outputC = outputShape.getDimSize(2);
3484 if (n != ShapedType::kDynamic && outputN != ShapedType::kDynamic &&
3486 return emitOpError() <<
"requires output dimension 0 to have size " << n
3487 <<
", got " << outputN;
3489 if (w != ShapedType::kDynamic && outputW != ShapedType::kDynamic &&
3491 return emitOpError() <<
"requires output dimension 1 to have size " << w
3492 <<
", got " << outputW;
3493 if (c != ShapedType::kDynamic && outputC != ShapedType::kDynamic &&
3495 return emitOpError() <<
"requires output dimension 2 to have size " << c
3496 <<
", got " << outputC;
3501LogicalResult tosa::RowGatherOp::verify() {
3506 const FailureOr<int32_t> maybeRowCount =
3508 if (succeeded(maybeRowCount) && maybeRowCount.value() <= 0)
3509 return emitOpError() <<
"requires row_count to be > 0, got "
3510 << maybeRowCount.value();
3512 int64_t n = ShapedType::kDynamic;
3513 int64_t c = ShapedType::kDynamic;
3514 int64_t w = ShapedType::kDynamic;
3516 const ShapeAdaptor valuesShape(getValues().
getType());
3517 if (valuesShape.hasRank()) {
3518 n = valuesShape.getDimSize(0);
3519 c = valuesShape.getDimSize(2);
3523 if (indicesShape.hasRank()) {
3525 "indices",
"batch")))
3527 w = indicesShape.getDimSize(1);
3530 const ShapeAdaptor outputShape(getOutput().
getType());
3531 if (outputShape.hasRank()) {
3533 "output",
"batch")) ||
3535 "output",
"channels")))
3538 if (succeeded(maybeRowCount) && maybeRowCount.value() > 0 &&
3539 ShapedType::isStatic(w)) {
3540 const int64_t expectedOutputRows = w * maybeRowCount.value();
3541 if (ShapedType::isStatic(outputShape.getDimSize(1)) &&
3542 outputShape.getDimSize(1) != expectedOutputRows)
3543 return emitOpError()
3544 <<
"requires output dimension to be equal to "
3545 "indices[1]*row_count ("
3546 << expectedOutputRows <<
"), got " << outputShape.getDimSize(1);
3553LogicalResult tosa::RowGatherBlockScaledOp::verify() {
3554 const OperandRange values = getValues();
3555 const ResultRange output = getOutput();
3556 if (values.empty() || values.size() > 2)
3557 return emitOpError()
3558 <<
"expects values tensor list length to be 1 or 2, got "
3560 if (output.size() != values.size())
3561 return emitOpError()
3562 <<
"expects output tensor list length to match values tensor list "
3564 << output.size() <<
" results for " << values.size()
3565 <<
" input tensors";
3567 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
3568 if (values.size() == 1 && blockSize != 1)
3569 return emitOpError()
3570 <<
"requires block_size to be BLOCK_SIZE_1 when values tensor list "
3572 if (values.size() == 2 && blockSize == 1)
3573 return emitOpError()
3574 <<
"requires block_size to not be BLOCK_SIZE_1 when values tensor "
3578 output[0].
getType(),
"values[0]",
3583 "values[1]",
"output[1]")))
3587 succeeded(rowCount) && rowCount.value() <= 0)
3588 return emitOpError() <<
"requires row_count to be > 0, got "
3589 << rowCount.value();
3591 int64_t n = ShapedType::kDynamic;
3592 int64_t k = ShapedType::kDynamic;
3593 int64_t c = ShapedType::kDynamic;
3594 int64_t w = ShapedType::kDynamic;
3595 int64_t multiplesOfC = ShapedType::kDynamic;
3597 const ShapeAdaptor valuesDataShape(values[0].
getType());
3598 if (valuesDataShape.hasRank()) {
3599 n = valuesDataShape.getDimSize(0);
3600 k = valuesDataShape.getDimSize(1);
3601 c = valuesDataShape.getDimSize(2);
3604 if (ShapedType::isStatic(c) && c % blockSize != 0)
3605 return emitOpError() <<
"expects channels of values[0] (" << c
3606 <<
") to be divisible by block_size (" << blockSize
3610 if (indicesShape.hasRank()) {
3612 "indices",
"batch")))
3614 w = indicesShape.getDimSize(1);
3617 const ShapeAdaptor outputDataShape(output[0].
getType());
3618 if (outputDataShape.hasRank()) {
3620 "output[0]",
"batch")) ||
3622 "output[0]",
"channels")))
3626 succeeded(rowCount) && rowCount.value() > 0 &&
3627 ShapedType::isStatic(w)) {
3628 const int64_t expectedOutputRows = w * rowCount.value();
3629 if (ShapedType::isStatic(outputDataShape.getDimSize(1)) &&
3630 outputDataShape.getDimSize(1) != expectedOutputRows)
3631 return emitOpError() <<
"requires output[0] dimension 1 to have size "
3632 << expectedOutputRows <<
", got "
3633 << outputDataShape.getDimSize(1);
3637 if (values.size() == 2) {
3638 const ShapeAdaptor valuesScaleShape(values[1].
getType());
3639 if (valuesScaleShape.hasRank()) {
3641 "values[1]",
"batch")) ||
3643 "values[1]",
"rows")))
3645 multiplesOfC = valuesScaleShape.getDimSize(2);
3648 const ShapeAdaptor outputScaleShape(output[1].
getType());
3649 if (outputScaleShape.hasRank()) {
3651 "output[1]",
"batch")))
3655 succeeded(rowCount) && rowCount.value() > 0 &&
3656 ShapedType::isStatic(w)) {
3657 const int64_t expectedOutputRows = w * rowCount.value();
3658 if (ShapedType::isStatic(outputScaleShape.getDimSize(1)) &&
3659 outputScaleShape.getDimSize(1) != expectedOutputRows)
3660 return emitOpError() <<
"requires output[1] dimension 1 to have size "
3661 << expectedOutputRows <<
", got "
3662 << outputScaleShape.getDimSize(1);
3665 if (ShapedType::isDynamic(multiplesOfC))
3666 multiplesOfC = outputScaleShape.getDimSize(2);
3667 else if (ShapedType::isStatic(outputScaleShape.getDimSize(2)) &&
3668 multiplesOfC != outputScaleShape.getDimSize(2))
3669 return emitOpError()
3670 <<
"expected channels of output[1] to match size "
3671 << multiplesOfC <<
", got " << outputScaleShape.getDimSize(2);
3674 if (ShapedType::isStatic(c) && ShapedType::isStatic(multiplesOfC) &&
3675 multiplesOfC != c / blockSize)
3676 return emitOpError()
3677 <<
"expects channels of scale tensors to equal C/block_size (" << c
3678 <<
"/" << blockSize <<
"), got " << multiplesOfC;
3684LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
3685 MLIRContext *context, ::std::optional<Location> location,
3686 ResizeOp::Adaptor adaptor,
3687 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3688 llvm::SmallVector<int64_t, 4> outputShape;
3689 outputShape.resize(4, ShapedType::kDynamic);
3691 ShapeAdaptor inputShape(adaptor.getInput().getType());
3692 if (!inputShape.hasRank())
3695 outputShape[0] = inputShape.getDimSize(0);
3696 outputShape[3] = inputShape.getDimSize(3);
3697 int64_t inputHeight = inputShape.getDimSize(1);
3698 int64_t inputWidth = inputShape.getDimSize(2);
3700 if ((inputHeight == ShapedType::kDynamic) ||
3701 (inputWidth == ShapedType::kDynamic))
3704 SmallVector<int64_t> scaleInt, offsetInt, borderInt;
3715 const int64_t outputHeight =
3716 (((inputHeight - 1) * scaleInt[0] - offsetInt[0] + borderInt[0]) /
3720 const int64_t outputWidth =
3721 (((inputWidth - 1) * scaleInt[2] - offsetInt[1] + borderInt[1]) /
3725 if (outputHeight < 0 || outputWidth < 0) {
3728 "calculated output height and width must be non-negative, "
3730 outputHeight,
", width = ", outputWidth);
3733 outputShape[1] = outputHeight;
3734 outputShape[2] = outputWidth;
3735 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3739LogicalResult tosa::ResizeOp::verify() {
3740 const Value input = getInput();
3741 const Value output = getOutput();
3744 if (isa<BlockScaledType>(inputElementType) &&
3745 getMode() != ResizeMode::NEAREST_NEIGHBOR)
3746 return emitOpError(
"requires NEAREST_NEIGHBOR mode for block scaled input");
3748 const RankedTensorType inputType =
3749 llvm::dyn_cast<RankedTensorType>(input.
getType());
3750 const RankedTensorType outputType =
3751 llvm::dyn_cast<RankedTensorType>(output.
getType());
3753 SmallVector<int64_t> scaleValues;
3754 SmallVector<int64_t> offsetValues;
3755 SmallVector<int64_t> borderValues;
3763 if (llvm::any_of(scaleValues, [](int64_t s) {
return s <= 0; }))
3764 return emitOpError(
"expect all scale values to be > 0, got ")
3767 const int64_t scaleYN = scaleValues[0];
3768 const int64_t scaleYD = scaleValues[1];
3769 const int64_t scaleXN = scaleValues[2];
3770 const int64_t scaleXD = scaleValues[3];
3772 const int64_t offsetY = offsetValues[0];
3773 const int64_t offsetX = offsetValues[1];
3775 const int64_t borderY = borderValues[0];
3776 const int64_t borderX = borderValues[1];
3783 const int64_t oh = outputType.getDimSize(1);
3784 const int64_t ow = outputType.getDimSize(2);
3785 const int64_t ih = inputType.getDimSize(1);
3786 const int64_t iw = inputType.getDimSize(2);
3792 if (ih != ShapedType::kDynamic && ih != 1) {
3793 const std::optional<int64_t> calculatedOutHeightMinusOne =
3794 idivCheck((ih - 1) * scaleYN - offsetY + borderY, scaleYD);
3795 if (!calculatedOutHeightMinusOne.has_value())
3796 return emitOpError(
"expected (input_height - 1) * scale_y_n - offset_y + "
3798 <<
"to be wholly divisible by scale_y_d, got ((" << ih
3799 <<
" - 1) * " << scaleYN <<
" - " << offsetY <<
" + " << borderY
3800 <<
") / " << scaleYD;
3801 const int64_t calculatedOutHeight = calculatedOutHeightMinusOne.value() + 1;
3802 if (oh != ShapedType::kDynamic && calculatedOutHeight != oh)
3803 return emitOpError(
"calculated output height did not match expected: ")
3804 <<
"calculated=" << calculatedOutHeight <<
", expected=" << oh;
3811 if (iw != ShapedType::kDynamic && iw != 1) {
3812 const int64_t scaledInWidth = (iw - 1) * scaleXN - offsetX + borderX;
3813 const std::optional<int64_t> calculatedOutWidthMinusOne =
3815 if (!calculatedOutWidthMinusOne.has_value())
3816 return emitOpError(
"expected (input_width - 1) * scale_x_n - offset_x + "
3818 <<
"to be wholly divisible by scale_x_d, got ((" << iw
3819 <<
" - 1) * " << scaleXN <<
" - " << offsetX <<
" + " << borderX
3820 <<
") / " << scaleXD;
3821 const int64_t calculatedOutWidth = calculatedOutWidthMinusOne.value() + 1;
3822 if (ow != ShapedType::kDynamic && calculatedOutWidth != ow)
3823 return emitOpError(
"calculated output width did not match expected: ")
3824 <<
"calculated=" << calculatedOutWidth <<
", expected=" << ow;
3830LogicalResult tosa::ScatterOp::inferReturnTypeComponents(
3831 MLIRContext *context, ::std::optional<Location> location,
3832 ScatterOp::Adaptor adaptor,
3833 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3834 llvm::SmallVector<int64_t> outputShape;
3835 outputShape.resize(3, ShapedType::kDynamic);
3837 ShapeAdaptor valuesInShape(adaptor.getValuesIn().getType());
3838 if (valuesInShape.hasRank()) {
3839 outputShape[0] = valuesInShape.getDimSize(0);
3840 outputShape[1] = valuesInShape.getDimSize(1);
3841 outputShape[2] = valuesInShape.getDimSize(2);
3844 ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3845 if (indicesShape.hasRank()) {
3846 if (outputShape[0] == ShapedType::kDynamic)
3847 outputShape[0] = indicesShape.getDimSize(0);
3850 ShapeAdaptor inputShape(adaptor.getInput().getType());
3851 if (inputShape.hasRank()) {
3852 if (outputShape[0] == ShapedType::kDynamic)
3853 outputShape[0] = inputShape.getDimSize(0);
3854 if (outputShape[2] == ShapedType::kDynamic)
3855 outputShape[2] = inputShape.getDimSize(2);
3858 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3862LogicalResult tosa::ScatterOp::verify() {
3872 const ShapeAdaptor valuesInShape(getValuesIn().
getType());
3874 const ShapeAdaptor inputShape(getInput().
getType());
3875 const ShapeAdaptor outputShape(getValuesOut().
getType());
3877 int64_t n = ShapedType::kDynamic;
3878 int64_t k = ShapedType::kDynamic;
3879 int64_t w = ShapedType::kDynamic;
3880 int64_t c = ShapedType::kDynamic;
3881 if (valuesInShape.hasRank()) {
3882 n = valuesInShape.getDimSize(0);
3883 k = valuesInShape.getDimSize(1);
3884 c = valuesInShape.getDimSize(2);
3886 if (indicesShape.hasRank()) {
3887 const int64_t indicesN = indicesShape.getDimSize(0);
3888 w = indicesShape.getDimSize(1);
3889 if (n == ShapedType::kDynamic)
3891 else if (indicesN != ShapedType::kDynamic && n != indicesN)
3892 return emitOpError() <<
"requires indices dimension 0 to have size " << n
3893 <<
", got " << indicesN;
3895 if (inputShape.hasRank()) {
3896 const int64_t inputN = inputShape.getDimSize(0);
3897 const int64_t inputW = inputShape.getDimSize(1);
3898 const int64_t inputC = inputShape.getDimSize(2);
3899 if (n == ShapedType::kDynamic)
3901 else if (inputN != ShapedType::kDynamic && n != inputN)
3902 return emitOpError() <<
"requires input dimension 0 to have size " << n
3903 <<
", got " << inputN;
3904 if (w == ShapedType::kDynamic)
3906 else if (inputW != ShapedType::kDynamic && w != inputW)
3907 return emitOpError() <<
"requires input dimension 1 to have size " << w
3908 <<
", got " << inputW;
3910 if (c == ShapedType::kDynamic)
3912 else if (inputC != ShapedType::kDynamic && c != inputC)
3913 return emitOpError() <<
"requires input dimension 2 to have size " << c
3914 <<
", got " << inputC;
3916 if (outputShape.hasRank()) {
3917 const int64_t outputN = outputShape.getDimSize(0);
3918 const int64_t outputK = outputShape.getDimSize(1);
3919 const int64_t outputC = outputShape.getDimSize(2);
3920 if (n != ShapedType::kDynamic && outputN != ShapedType::kDynamic &&
3922 return emitOpError() <<
"requires values_out dimension 0 to have size "
3923 << n <<
", got " << outputN;
3924 if (k == ShapedType::kDynamic)
3926 else if (outputK != ShapedType::kDynamic && k != outputK)
3927 return emitOpError() <<
"requires values_out dimension 1 to have size "
3928 << k <<
", got " << outputK;
3929 if (c != ShapedType::kDynamic && outputC != ShapedType::kDynamic &&
3931 return emitOpError() <<
"requires values_out dimension 2 to have size "
3932 << c <<
", got " << outputC;
3934 if (k != ShapedType::kDynamic && w != ShapedType::kDynamic && !(k >= w))
3935 return emitOpError() <<
"requires dimensions K >= W, got K=" << k
3944 int64_t axisVal = axis.getValue().getSExtValue();
3945 if (!operandShape.
hasRank() || operandShape.
getRank() <= axisVal) {
3951 operandShape.
getDims(outputShape);
3952 outputShape[axisVal] = 1;
3957#define COMPATIBLE_RETURN_TYPES(OP) \
3958 bool OP::isCompatibleReturnTypes(TypeRange l, TypeRange r) { \
3959 if (l.size() != r.size() || l.size() != 1) \
3961 if (getElementTypeOrSelf(l[0]) != getElementTypeOrSelf(r[0])) \
3963 return succeeded(verifyCompatibleShape(l[0], r[0])); \
3966#define REDUCE_SHAPE_INFER(OP) \
3967 LogicalResult OP::inferReturnTypeComponents( \
3968 MLIRContext *context, ::std::optional<Location> location, \
3969 OP::Adaptor adaptor, \
3970 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) { \
3972 llvm::cast<TensorType>(adaptor.getInput().getType()).getElementType(); \
3973 ShapeAdaptor inputShape(adaptor.getInput().getType()); \
3974 const Properties &prop = adaptor.getProperties(); \
3975 return ReduceInferReturnTypes(inputShape, inputType, prop.axis, \
3976 inferredReturnShapes); \
3978 COMPATIBLE_RETURN_TYPES(OP)
3986#undef REDUCE_SHAPE_INFER
3988#undef COMPATIBLE_RETURN_TYPES
3990template <
typename T>
3993 TensorType inputType = op.getInput().getType();
3994 TensorType outputType = op.getOutput().getType();
3995 int32_t reduceAxis = op.getAxis();
3997 if (reduceAxis < 0) {
3998 op.emitOpError(
"reduce axis must not be negative");
4002 int64_t inputRank = inputType.getRank();
4005 if (reduceAxis >= inputRank && (reduceAxis != 0 || inputRank != 0)) {
4006 op.emitOpError(
"expect input tensor rank (")
4007 << inputRank <<
") to be larger than reduce axis (" << reduceAxis
4013 int64_t outputRank = outputType.getRank();
4014 if (inputType.
hasRank() && outputRank != inputType.getRank()) {
4016 "expect output tensor rank to be equal to input tensor rank");
4019 if (reduceAxis >= outputRank && (reduceAxis != 0 || outputRank != 0)) {
4020 op.emitOpError(
"expect output tensor rank (")
4021 << outputRank <<
") to be larger than reduce axis (" << reduceAxis
4027 if (outputRank != 0) {
4028 auto outputShape = outputType.
getShape();
4029 if (!outputType.isDynamicDim(reduceAxis) &&
4030 outputShape[reduceAxis] != 1) {
4031 op.emitOpError(
"expect reduced dimension size to be 1, got ")
4032 << outputShape[reduceAxis];
4040LogicalResult tosa::ReduceAllOp::verify() {
return verifyReduceOp(*
this); }
4041LogicalResult tosa::ReduceAnyOp::verify() {
return verifyReduceOp(*
this); }
4042LogicalResult tosa::ReduceMaxOp::verify() {
return verifyReduceOp(*
this); }
4043LogicalResult tosa::ReduceMinOp::verify() {
return verifyReduceOp(*
this); }
4044LogicalResult tosa::ReduceProductOp::verify() {
return verifyReduceOp(*
this); }
4045LogicalResult tosa::ReduceSumOp::verify() {
return verifyReduceOp(*
this); }
4059#define NARY_SHAPE_INFER(OP) \
4060 LogicalResult OP::inferReturnTypeComponents( \
4061 MLIRContext *context, ::std::optional<Location> location, \
4062 ValueShapeRange operands, DictionaryAttr attributes, \
4063 PropertyRef properties, RegionRange regions, \
4064 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) { \
4065 return NAryInferReturnTypes(operands, inferredReturnShapes); \
4105#undef PRED_SHAPE_INFER
4107LogicalResult tosa::NegateOp::inferReturnTypeComponents(
4108 MLIRContext *context, ::std::optional<Location> location,
4109 NegateOp::Adaptor adaptor,
4111 ShapeAdaptor inputShape(adaptor.getInput1().getType());
4116LogicalResult tosa::NegateOp::verify() {
4118 const Type input1Type = getInput1().getType();
4119 const Type outputType = getOutput().getType();
4124 const SmallVector<Type, 2> types = {input1Type, outputType};
4126 return emitOpError() <<
"requires the same shape for input1 and output";
4129 const Type input1ZpEType =
4131 if (input1EType != input1ZpEType) {
4132 return emitOpError(
"expect both input1 and its zero point are the same "
4133 "element type, got ")
4134 << input1EType <<
" and " << input1ZpEType;
4137 const Type outputZpEType =
4139 if (outputEType != outputZpEType) {
4140 return emitOpError(
"expect both output and its zero point are the same "
4141 "element type, got ")
4142 << outputEType <<
" and " << outputZpEType;
4145 FailureOr<int64_t> maybeIZp = getInput1ZeroPoint();
4146 if (succeeded(maybeIZp) && verifyInput1ZeroPoint(*maybeIZp).failed())
4149 FailureOr<int64_t> maybeOZp = getOutputZeroPoint();
4150 if (succeeded(maybeOZp) && verifyOutputZeroPoint(*maybeOZp).failed())
4161 outputShape.resize(4, ShapedType::kDynamic);
4176 if (ShapedType::isStatic(height)) {
4177 int64_t padded = height + pad[0] + pad[1] - kernel[0];
4178 outputShape[1] = padded / stride[0] + 1;
4181 if (ShapedType::isStatic(width)) {
4182 int64_t padded = width + pad[2] + pad[3] - kernel[1];
4183 outputShape[2] = padded / stride[1] + 1;
4190template <
typename AdaptorT>
4196 if (ShapedType::isDynamic(current))
4197 current = candidate;
4206 : adaptor(adaptor) {}
4210 const ShapeAdaptor inputShape(adaptor.getInput().getType());
4218 outputShape[0] = outputBatch;
4219 inputSpatial[0] = inputHeight;
4220 inputSpatial[1] = inputWidth;
4225 const ShapeAdaptor weightShape(adaptor.getWeight().getType());
4233 outputShape[3] = outputChannels;
4234 weightSpatial[0] = kernelHeight;
4235 weightSpatial[1] = kernelWidth;
4244 padValues.assign(adaptor.getPad().begin(), adaptor.getPad().end());
4245 strideValues.assign(adaptor.getStride().begin(), adaptor.getStride().end());
4246 dilationValues.assign(adaptor.getDilation().begin(),
4247 adaptor.getDilation().end());
4252 Conv2DOp::Adaptor adaptor;
4260 : adaptor(adaptor) {}
4264 const ShapeAdaptor inputDataShape(adaptor.getInputData().getType());
4265 if (inputDataShape.
hasRank()) {
4270 outputShape[0] = outputBatch;
4271 inputSpatial[0] = inputHeight;
4272 inputSpatial[1] = inputWidth;
4275 const ShapeAdaptor inputScaleShape(adaptor.getInputScale().getType());
4276 if (!inputScaleShape.
hasRank())
4290 const ShapeAdaptor weightDataShape(adaptor.getWeightData().getType());
4291 if (weightDataShape.
hasRank()) {
4296 outputShape[3] = outputChannels;
4297 weightSpatial[0] = kernelHeight;
4298 weightSpatial[1] = kernelWidth;
4301 const ShapeAdaptor weightScaleShape(adaptor.getWeightScale().getType());
4302 if (!weightScaleShape.
hasRank())
4331 Conv2DBlockScaledOp::Adaptor adaptor;
4339 : adaptor(adaptor) {}
4343 const ShapeAdaptor inputShape(adaptor.getInput().getType());
4352 outputShape[0] = outputBatch;
4353 inputSpatial[0] = inputDepth;
4354 inputSpatial[1] = inputHeight;
4355 inputSpatial[2] = inputWidth;
4360 const ShapeAdaptor weightShape(adaptor.getWeight().getType());
4369 outputShape[4] = outputChannels;
4370 weightSpatial[0] = kernelDepth;
4371 weightSpatial[1] = kernelHeight;
4372 weightSpatial[2] = kernelWidth;
4381 padValues.assign(adaptor.getPad().begin(), adaptor.getPad().end());
4382 strideValues.assign(adaptor.getStride().begin(), adaptor.getStride().end());
4383 dilationValues.assign(adaptor.getDilation().begin(),
4384 adaptor.getDilation().end());
4389 Conv3DOp::Adaptor adaptor;
4392template <
typename AdaptorT>
4398 ShapedType::kDynamic);
4400 ShapedType::kDynamic);
4402 ShapedType::kDynamic);
4404 convShapeAdaptor.inferInputShape(outputShape, inputSpatial);
4405 convShapeAdaptor.inferWeightShape(outputShape, weightSpatial);
4407 const ShapeAdaptor biasShape = adaptor.getBias().getType();
4410 if (biasSize != 1) {
4411 const size_t outputChannelDim = convShapeAdaptor.getOutputRank() - 1;
4412 outputShape[outputChannelDim] =
4413 ShapedType::isDynamic(outputShape[outputChannelDim])
4415 : outputShape[outputChannelDim];
4422 if (failed(convShapeAdaptor.getSpatialParameters(padValues, strideValues,
4428 for (
int64_t dim = 0; dim < convShapeAdaptor.getNumSpatialDims(); ++dim) {
4429 if (!ShapedType::isStatic(inputSpatial[dim]) ||
4430 !ShapedType::isStatic(weightSpatial[dim]))
4433 inputSpatial[dim] + padValues[2 * dim] + padValues[2 * dim + 1];
4435 (weightSpatial[dim] - 1) * dilationValues[dim] + 1;
4436 const int64_t unstridedResult = inputSize - filterSize + 1;
4437 outputShape[dim + 1] = (unstridedResult - 1) / strideValues[dim] + 1;
4444LogicalResult Conv2DOp::inferReturnTypeComponents(
4445 MLIRContext *context, ::std::optional<Location> location,
4446 Conv2DOp::Adaptor adaptor,
4447 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4451LogicalResult Conv2DOp::verify() {
4457LogicalResult Conv2DBlockScaledOp::inferReturnTypeComponents(
4458 MLIRContext *context, ::std::optional<Location> location,
4459 Conv2DBlockScaledOp::Adaptor adaptor,
4460 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4464LogicalResult Conv2DBlockScaledOp::verify() {
4466 getWeightData().
getType(),
"input_data",
4469 getWeightScale().
getType(),
"input_scale",
4472 getOutput().
getType(),
"bias",
"output")))
4476 int64_t N = ShapedType::kDynamic;
4477 int64_t IH = ShapedType::kDynamic;
4478 int64_t IW = ShapedType::kDynamic;
4479 int64_t IC = ShapedType::kDynamic;
4480 int64_t multiplesOfIC = ShapedType::kDynamic;
4481 int64_t OC = ShapedType::kDynamic;
4482 int64_t KH = ShapedType::kDynamic;
4483 int64_t KW = ShapedType::kDynamic;
4485 const ShapeAdaptor inputDataShape(getInputData().
getType());
4486 if (inputDataShape.hasRank()) {
4487 N = inputDataShape.getDimSize(0);
4488 IH = inputDataShape.getDimSize(1);
4489 IW = inputDataShape.getDimSize(2);
4490 IC = inputDataShape.getDimSize(3);
4493 const ShapeAdaptor inputScaleShape(getInputScale().
getType());
4494 if (inputScaleShape.hasRank()) {
4496 "input_scale",
"batch size")) ||
4498 "input_scale",
"input height")) ||
4500 "input_scale",
"input width")))
4502 multiplesOfIC = inputScaleShape.getDimSize(3);
4505 const ShapeAdaptor weightDataShape(getWeightData().
getType());
4506 if (weightDataShape.hasRank()) {
4507 OC = weightDataShape.getDimSize(0);
4508 KH = weightDataShape.getDimSize(1);
4509 KW = weightDataShape.getDimSize(2);
4511 "weight_data",
"input channels")))
4515 const ShapeAdaptor weightScaleShape(getWeightScale().
getType());
4516 if (weightScaleShape.hasRank()) {
4518 "weight_scale",
"output channels")) ||
4520 "weight_scale",
"kernel height")) ||
4522 "weight_scale",
"kernel width")) ||
4524 weightScaleShape.getDimSize(3),
4525 "weight_scale",
"input channel blocks")))
4529 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
4530 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
4531 return emitOpError(
"expect block size to be 32, got ") << blockSize;
4533 if (ShapedType::isStatic(IC) && IC % blockSize != 0)
4534 return emitOpError(
"expect IC to be a multiple of block size, got IC=")
4535 << IC <<
", block_size=" << blockSize;
4538 if (ShapedType::isStatic(IC) && ShapedType::isStatic(multiplesOfIC) &&
4539 multiplesOfIC != IC / blockSize)
4541 "expect scale operands dimension 2 to equal IC/block_size (")
4542 << IC <<
"/" << blockSize <<
")"
4543 <<
", got " << multiplesOfIC;
4546 SmallVector<int64_t> padValues;
4548 if (llvm::any_of(padValues, [](int64_t p) {
return p < 0; }))
4549 return emitOpError(
"expect all padding values to be >= 0, got ")
4553 SmallVector<int64_t> strideValues;
4555 if (llvm::any_of(strideValues, [](int64_t s) {
return s < 1; }))
4556 return emitOpError(
"expect all stride values to be >= 1, got ")
4560 SmallVector<int64_t> dilationValues;
4563 if (llvm::any_of(dilationValues, [](int64_t d) {
return d < 1; }))
4564 return emitOpError(
"expect all dilation values to be >= 1, got ")
4569 const ShapeAdaptor outputShape(getOutput().
getType());
4570 if (!padValues.empty() && !strideValues.empty() && !dilationValues.empty() &&
4571 outputShape.hasRank()) {
4573 padValues[0], padValues[1], strideValues[0],
4574 dilationValues[0],
"height",
"y",
"top",
4577 padValues[2], padValues[3], strideValues[1],
4578 dilationValues[1],
"width",
"x",
"left",
4584 const ShapeAdaptor biasShape(getBias().
getType());
4585 if (biasShape.hasRank() && outputShape.hasRank()) {
4586 const int64_t biasChannels = biasShape.getDimSize(0);
4587 const int64_t outputChannels =
4588 outputShape.getDimSize(outputShape.getRank() - 1);
4589 if (biasChannels == ShapedType::kDynamic ||
4590 outputChannels == ShapedType::kDynamic)
4594 if (biasChannels != outputChannels && biasChannels != 1)
4596 "bias channels expected to be equal to output channels (")
4597 << outputChannels <<
") or 1, got " << biasChannels;
4603LogicalResult Conv3DOp::inferReturnTypeComponents(
4604 MLIRContext *context, ::std::optional<Location> location,
4605 Conv3DOp::Adaptor adaptor,
4606 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4610LogicalResult Conv3DOp::verify() {
4616LogicalResult AvgPool2dOp::inferReturnTypeComponents(
4617 MLIRContext *context, ::std::optional<Location> location,
4618 AvgPool2dOp::Adaptor adaptor,
4619 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4620 ShapeAdaptor inputShape(adaptor.getInput().getType());
4621 const Properties &prop = adaptor.getProperties();
4623 inferredReturnShapes);
4626LogicalResult AvgPool2dAdaptiveOp::inferReturnTypeComponents(
4627 MLIRContext *context, ::std::optional<Location> location,
4628 AvgPool2dAdaptiveOp::Adaptor adaptor,
4629 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4630 ShapeAdaptor inputShape(adaptor.getInput().getType());
4632 llvm::SmallVector<int64_t> kernelValues;
4633 llvm::SmallVector<int64_t> strideValues;
4634 llvm::SmallVector<int64_t> padValues;
4641 padValues, inferredReturnShapes);
4644 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4645 if (inputShape.hasRank()) {
4647 outputShape[0] = inputShape.getDimSize(0);
4648 outputShape[3] = inputShape.getDimSize(3);
4651 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4655LogicalResult MaxPool2dOp::inferReturnTypeComponents(
4656 MLIRContext *context, ::std::optional<Location> location,
4657 MaxPool2dOp::Adaptor adaptor,
4658 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4659 ShapeAdaptor inputShape(adaptor.getInput().getType());
4660 const Properties &prop = adaptor.getProperties();
4662 inferredReturnShapes);
4665LogicalResult MaxPool2dAdaptiveOp::inferReturnTypeComponents(
4666 MLIRContext *context, ::std::optional<Location> location,
4667 MaxPool2dAdaptiveOp::Adaptor adaptor,
4668 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4669 ShapeAdaptor inputShape(adaptor.getInput().getType());
4671 llvm::SmallVector<int64_t> kernelValues;
4672 llvm::SmallVector<int64_t> strideValues;
4673 llvm::SmallVector<int64_t> padValues;
4680 padValues, inferredReturnShapes);
4683 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4684 if (inputShape.hasRank()) {
4685 outputShape[0] = inputShape.getDimSize(0);
4686 outputShape[3] = inputShape.getDimSize(3);
4688 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4692LogicalResult MaxPool2dOp::verify() {
4703LogicalResult MaxPool2dAdaptiveOp::verify() {
4708 AdaptivePoolingConstShapeValues values;
4712 values.pad, getInput(), getOutput())))
4718LogicalResult DepthwiseConv2DOp::inferReturnTypeComponents(
4719 MLIRContext *context, ::std::optional<Location> location,
4720 DepthwiseConv2DOp::Adaptor adaptor,
4721 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4722 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4724 int64_t inputWidth = ShapedType::kDynamic;
4725 int64_t inputHeight = ShapedType::kDynamic;
4726 int64_t inputChannels = ShapedType::kDynamic;
4728 int64_t weightWidth = ShapedType::kDynamic;
4729 int64_t weightHeight = ShapedType::kDynamic;
4730 int64_t depthChannels = ShapedType::kDynamic;
4733 ShapeAdaptor inputShape(adaptor.getInput().getType());
4734 if (inputShape.hasRank()) {
4735 outputShape[0] = inputShape.getDimSize(0);
4736 inputHeight = inputShape.getDimSize(1);
4737 inputWidth = inputShape.getDimSize(2);
4738 inputChannels = inputShape.getDimSize(3);
4742 ShapeAdaptor weightShape(adaptor.getWeight().getType());
4743 if (weightShape.hasRank()) {
4744 weightHeight = weightShape.getDimSize(0);
4745 weightWidth = weightShape.getDimSize(1);
4746 inputChannels = ShapedType::isDynamic(inputChannels)
4747 ? weightShape.getDimSize(2)
4749 depthChannels = weightShape.getDimSize(3);
4754 if (ShapedType::isStatic(inputChannels) &&
4755 ShapedType::isStatic(depthChannels)) {
4756 outputShape[3] = inputChannels * depthChannels;
4760 ShapeAdaptor biasShape(adaptor.getBias().getType());
4761 if (biasShape.hasRank() && ShapedType::isDynamic(outputShape[3])) {
4762 int64_t bc = biasShape.getDimSize(0);
4763 if (bc != ShapedType::kDynamic && bc != 1)
4764 outputShape[3] = bc;
4767 llvm::ArrayRef<int64_t> dilation = adaptor.getDilation();
4768 llvm::ArrayRef<int64_t> padding = adaptor.getPad();
4769 llvm::ArrayRef<int64_t> stride = adaptor.getStride();
4771 if (ShapedType::isStatic(inputHeight) && ShapedType::isStatic(weightHeight)) {
4772 int64_t inputSize = inputHeight + padding[0] + padding[1];
4773 int64_t filterSize = (weightHeight - 1) * dilation[0] + 1;
4774 int64_t unstridedResult = inputSize - filterSize + 1;
4775 outputShape[1] = (unstridedResult - 1) / stride[0] + 1;
4778 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(weightWidth)) {
4779 int64_t inputSize = inputWidth + padding[2] + padding[3];
4780 int64_t filterSize = (weightWidth - 1) * dilation[1] + 1;
4781 int64_t unstridedResult = inputSize - filterSize + 1;
4782 outputShape[2] = (unstridedResult - 1) / stride[1] + 1;
4785 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4789LogicalResult DepthwiseConv2DOp::verify() {
4795LogicalResult TransposeConv2DOp::inferReturnTypeComponents(
4796 MLIRContext *context, ::std::optional<Location> location,
4797 TransposeConv2DOp::Adaptor adaptor,
4798 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4799 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4801 int64_t inputWidth = ShapedType::kDynamic;
4802 int64_t inputHeight = ShapedType::kDynamic;
4803 int64_t weightWidth = ShapedType::kDynamic;
4804 int64_t weightHeight = ShapedType::kDynamic;
4807 ShapeAdaptor inputShape(adaptor.getInput().getType());
4808 if (inputShape.hasRank()) {
4809 outputShape[0] = ShapedType::isDynamic(outputShape[0])
4810 ? inputShape.getDimSize(0)
4812 inputHeight = inputShape.getDimSize(1);
4813 inputWidth = inputShape.getDimSize(2);
4817 ShapeAdaptor weightShape(adaptor.getWeight().getType());
4818 if (weightShape.hasRank()) {
4819 outputShape[3] = ShapedType::isDynamic(outputShape[3])
4820 ? weightShape.getDimSize(0)
4822 weightHeight = weightShape.getDimSize(1);
4823 weightWidth = weightShape.getDimSize(2);
4827 ShapeAdaptor biasShape(adaptor.getBias().getType());
4828 if (biasShape.hasRank() && ShapedType::isDynamic(outputShape[3])) {
4829 int64_t bc = biasShape.getDimSize(0);
4830 if (bc != ShapedType::kDynamic && bc != 1)
4831 outputShape[3] = bc;
4834 llvm::ArrayRef<int64_t> padding = adaptor.getOutPad();
4835 llvm::ArrayRef<int64_t> stride = adaptor.getStride();
4837 if (ShapedType::isStatic(inputHeight) && ShapedType::isStatic(weightHeight)) {
4838 int64_t calculateSize =
4839 (inputHeight - 1) * stride[0] + padding[0] + padding[1] + weightHeight;
4841 ShapedType::isDynamic(outputShape[1]) ? calculateSize : outputShape[1];
4844 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(weightWidth)) {
4845 int64_t calculateSize =
4846 (inputWidth - 1) * stride[1] + padding[2] + padding[3] + weightWidth;
4848 ShapedType::isDynamic(outputShape[2]) ? calculateSize : outputShape[2];
4851 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4855LogicalResult TransposeConv2DOp::verify() {
4859 const llvm::ArrayRef<int64_t> strides = getStride();
4860 const int64_t strideY = strides[0];
4861 const int64_t strideX = strides[1];
4863 if (strideY < 1 || strideX < 1)
4864 return emitOpError(
"expect all stride values to be >= 1, got [")
4867 const auto checkPadAgainstKernelDim =
4868 [
this](int64_t padValue, int64_t kernelDimSize, llvm::StringRef padName,
4869 llvm::StringRef kernelDimName) -> LogicalResult {
4870 if (padValue <= -kernelDimSize)
4871 return emitOpError(
"expected ")
4872 << padName <<
" > -" << kernelDimName <<
", but got: " << padName
4873 <<
"=" << padValue <<
" and " << kernelDimName <<
"="
4878 const llvm::ArrayRef<int64_t> padding = getOutPad();
4879 const int64_t outPadTop = padding[0];
4880 const int64_t outPadBottom = padding[1];
4881 const int64_t outPadLeft = padding[2];
4882 const int64_t outPadRight = padding[3];
4884 const auto weightType =
4885 llvm::dyn_cast<RankedTensorType>(getWeight().
getType());
4888 const int64_t kernelHeight = weightType.getDimSize(1);
4889 if (ShapedType::isStatic(kernelHeight)) {
4890 if (
failed(checkPadAgainstKernelDim(outPadTop, kernelHeight,
4891 "out_pad_top",
"KH")))
4894 if (
failed(checkPadAgainstKernelDim(outPadBottom, kernelHeight,
4895 "out_pad_bottom",
"KH")))
4899 const int64_t kernelWidth = weightType.getDimSize(2);
4900 if (ShapedType::isStatic(kernelWidth)) {
4901 if (
failed(checkPadAgainstKernelDim(outPadLeft, kernelWidth,
4902 "out_pad_left",
"KW")))
4905 if (
failed(checkPadAgainstKernelDim(outPadRight, kernelWidth,
4906 "out_pad_right",
"KW")))
4912 const auto outputType =
4913 llvm::dyn_cast<RankedTensorType>(getOutput().
getType());
4917 const auto inputType = llvm::dyn_cast<RankedTensorType>(getInput().
getType());
4918 if (inputType && weightType) {
4919 const int64_t inputHeight = inputType.getDimSize(1);
4920 const int64_t kernelHeight = weightType.getDimSize(1);
4921 const int64_t outputHeight = outputType.getDimSize(1);
4923 if (ShapedType::isStatic(inputHeight) &&
4924 ShapedType::isStatic(outputHeight)) {
4926 (inputHeight - 1) * strideY + outPadTop + outPadBottom + kernelHeight)
4928 "dimension mismatch: expected OH == (IH - 1) * stride_y "
4929 "+ out_pad_top + out_pad_bottom + KH, but got ")
4930 << outputHeight <<
" != (" << inputHeight <<
" - 1) * "
4931 << strideY <<
" + " << outPadTop <<
" + " << outPadBottom
4932 <<
" + " << kernelHeight;
4935 const int64_t inputWidth = inputType.getDimSize(2);
4936 const int64_t kernelWidth = weightType.getDimSize(2);
4937 const int64_t outputWidth = outputType.getDimSize(2);
4939 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(outputWidth)) {
4941 (inputWidth - 1) * strideX + outPadLeft + outPadRight + kernelWidth)
4943 "dimension mismatch: expected OW == (IW - 1) * stride_x "
4944 "+ out_pad_left + out_pad_right + KW, but got ")
4945 << outputWidth <<
" != (" << inputWidth <<
" - 1) * " << strideX
4946 <<
" + " << outPadLeft <<
" + " << outPadRight <<
" + "
4951 const auto biasType = llvm::dyn_cast<RankedTensorType>(getBias().
getType());
4956 const int64_t biasChannels = biasType.getDimSize(0);
4959 if (biasChannels == ShapedType::kDynamic)
4962 const int64_t outputChannels = outputType.getDimSize(3);
4963 if (!ShapedType::isDynamic(outputChannels) &&
4964 biasChannels != outputChannels && biasChannels != 1)
4966 "bias channels expected to be equal to output channels (")
4967 << outputChannels <<
") or 1, got " << biasChannels;
4972LogicalResult RescaleOp::verify() {
4973 const auto inputType = llvm::cast<ShapedType>(getInput().
getType());
4974 auto inputElementType =
4976 if (!mlir::isa<IntegerType>(inputElementType)) {
4977 emitOpError(
"expect input to have integer element type, got ")
4978 << inputElementType;
4982 const auto outputType = llvm::cast<ShapedType>(getOutput().
getType());
4983 auto outputElementType =
4985 if (!mlir::isa<IntegerType>(outputElementType)) {
4986 emitOpError(
"expect output to have integer element type, got ")
4987 << outputElementType;
4999 FailureOr<int64_t> maybeIZp = getInputZeroPoint();
5000 if (succeeded(maybeIZp) && verifyInputZeroPoint(*maybeIZp).failed())
5003 FailureOr<int64_t> maybeOZp = getOutputZeroPoint();
5004 if (succeeded(maybeOZp) && verifyOutputZeroPoint(*maybeOZp).failed())
5007 const auto multiplierType = llvm::cast<ShapedType>(getMultiplier().
getType());
5009 if (getScale32() && !multiplierType.getElementType().isInteger(32)) {
5010 emitOpError(
"expect i32 element type for multiplier for scale32=true, got ")
5011 << multiplierType.getElementType();
5016 if (!getScale32() && !multiplierType.getElementType().isInteger(16)) {
5018 "expect i16 element type for multiplier for scale32=false, got ")
5019 << multiplierType.getElementType();
5023 if (!inputType.hasRank())
5029 int64_t numChannels = 1;
5030 if (getPerChannel()) {
5031 if (inputType.getRank() < 1) {
5032 emitOpError(
"requires input to be at least rank 1 when per_channel is "
5033 "true, but got rank ")
5034 << inputType.getRank();
5037 numChannels = inputType.getDimSize(inputType.getRank() - 1);
5040 if (outputType.hasRank()) {
5042 getOperation(), outputType, inputType.getShape())))
5046 if (multiplierType.hasRank()) {
5047 ArrayRef<int64_t> multiplierShape = multiplierType.getShape();
5049 if (multiplierShape[0] != ShapedType::kDynamic &&
5050 multiplierShape[0] != numChannels) {
5051 emitOpError(
"expect shape of { ")
5052 << numChannels <<
" } for multiplier input, got { "
5053 << multiplierShape[0] <<
" }";
5058 const auto shiftType = llvm::cast<ShapedType>(getShift().
getType());
5059 if (shiftType.hasRank()) {
5060 ArrayRef<int64_t> shiftShape = shiftType.getShape();
5062 if (shiftShape[0] != ShapedType::kDynamic && shiftShape[0] != numChannels) {
5063 emitOpError(
"expect shape of { ")
5064 << numChannels <<
" } for shift input, got { " << shiftShape[0]
5073LogicalResult RescaleOp::inferReturnTypeComponents(
5074 MLIRContext *context, ::std::optional<Location> location,
5075 RescaleOp::Adaptor adaptor,
5076 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5077 ShapeAdaptor inputShape(adaptor.getInput().getType());
5078 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5082LogicalResult CastOp::verify() {
5083 const ShapedType inputType = llvm::cast<ShapedType>(getInput().
getType());
5084 const ShapedType outputType = llvm::cast<ShapedType>(
getType());
5085 const Type inputElementType = inputType.getElementType();
5086 const Type outputElementType = outputType.getElementType();
5088 const bool inputIsBlockScaled = llvm::isa<BlockScaledType>(inputElementType);
5089 const bool outputIsBlockScaled =
5090 llvm::isa<BlockScaledType>(outputElementType);
5092 const bool isUnsigned = this->getInputUnsigned();
5097 return emitOpError()
5098 <<
"attribute input_unsigned requires integer type inputs. Got: "
5101 if (!inputIsBlockScaled && !outputIsBlockScaled)
5104 if (inputIsBlockScaled && outputIsBlockScaled)
5105 return emitOpError()
5106 <<
"requires exactly one of input or output to have block scaled "
5109 const Type scalarElementType =
5110 inputIsBlockScaled ? outputElementType : inputElementType;
5111 if (!llvm::isa<FloatType>(scalarElementType))
5112 return emitOpError()
5113 <<
"requires non-block-scaled element type to be floating-point "
5114 "when casting to or from block scaled element type, got "
5115 << scalarElementType;
5120LogicalResult CastFromBlockScaledOp::inferReturnTypeComponents(
5121 MLIRContext *context, ::std::optional<Location> location,
5122 CastFromBlockScaledOp::Adaptor adaptor,
5123 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5124 const ShapeAdaptor inputShape(adaptor.getInputData().getType());
5125 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5129LogicalResult CastFromBlockScaledOp::verify() {
5130 const Type inputDataType = getInputData().getType();
5131 const Type outputDataType = getResult().getType();
5133 return emitOpError() <<
"require compatible shapes for input_data ("
5134 << inputDataType <<
") and " <<
"output_data ("
5135 << outputDataType <<
")";
5137 const ShapeAdaptor inputDataShape = ShapeAdaptor(inputDataType);
5139 if (inputDataShape.
hasRank()) {
5140 const unsigned int blockSize =
5142 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
5143 return emitOpError(
"expect block size to be 32, got ") << blockSize;
5144 const int64_t inputDataLastDim =
5146 if (inputDataLastDim % blockSize != 0)
5147 return emitOpError() <<
"expect last dimension of input_data ("
5149 <<
") to be divisible by block_size (" << blockSize
5152 const Type inputScaleType = getInputScale().getType();
5153 const ShapeAdaptor inputScaleShape = ShapeAdaptor(inputScaleType);
5155 if (inputScaleShape.
hasRank()) {
5156 SmallVector<int64_t> inputDataDims, inputScaleDims;
5157 inputDataShape.
getDims(inputDataDims);
5158 inputScaleShape.
getDims(inputScaleDims);
5160 if (inputDataDims.size() != inputScaleDims.size() ||
5162 ArrayRef<int64_t>(inputDataDims).drop_back(1),
5163 ArrayRef<int64_t>(inputScaleDims).drop_back(1))))
5164 return emitOpError()
5165 <<
"require compatible shapes for input_data (" << inputDataType
5166 <<
") and " <<
"input_scale (" << inputScaleType
5167 <<
") except for the last dimension";
5169 const SmallVector<int64_t, 2> dimsToCheck{inputDataLastDim / blockSize,
5170 inputScaleDims.back()};
5171 if (ShapedType::isStatic(inputDataLastDim) &&
5173 return emitOpError()
5174 <<
"expect last dimension of input_scale ("
5175 << inputScaleDims.back()
5176 <<
") to be equal to last dimension of input_data / block_size ("
5177 << inputDataDims.back() / blockSize <<
")";
5184LogicalResult CastToBlockScaledOp::inferReturnTypeComponents(
5185 MLIRContext *context, ::std::optional<Location> location,
5186 CastToBlockScaledOp::Adaptor adaptor,
5187 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5188 const ShapeAdaptor inputShape(adaptor.getInputData().getType());
5189 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5190 if (!inputShape.hasRank())
5194 SmallVector<int64_t> outputScaleShape;
5195 inputShape.getDims(outputScaleShape);
5196 const int64_t lastDimLoc = inputShape.getRank() - 1;
5197 const int64_t lastDimSize = inputShape.getDimSize(lastDimLoc);
5198 if (ShapedType::isStatic(lastDimSize)) {
5199 const unsigned int blockSize =
5200 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
5201 outputScaleShape[lastDimLoc] = lastDimSize / blockSize;
5203 inferredReturnShapes.push_back(ShapedTypeComponents(outputScaleShape));
5207LogicalResult CastToBlockScaledOp::verify() {
5208 const Type inputDataType = getInputData().getType();
5209 const Type outputDataType = getResult(0).getType();
5211 return emitOpError() <<
"require compatible shapes for input_data ("
5212 << inputDataType <<
") and " <<
"output_data ("
5213 << outputDataType <<
")";
5215 const unsigned int blockSize =
5217 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
5218 return emitOpError(
"expect block size to be 32, got ") << blockSize;
5219 const ShapeAdaptor inputDataShape = ShapeAdaptor(inputDataType);
5220 if (inputDataShape.
hasRank()) {
5221 const int64_t inputDataLastDim =
5223 if (ShapedType::isStatic(inputDataLastDim) &&
5224 inputDataLastDim % blockSize != 0)
5225 return emitOpError() <<
"expect last dimension of input_data ("
5227 <<
") to be divisible by block_size (" << blockSize
5231 const ShapeAdaptor outputDataShape = ShapeAdaptor(outputDataType);
5232 const Type outputScaleType = getResult(1).getType();
5233 const ShapeAdaptor outputScaleShape = ShapeAdaptor(outputScaleType);
5235 SmallVector<int64_t> outputDataDims, outputScaleDims;
5236 outputDataShape.
getDims(outputDataDims);
5237 outputScaleShape.
getDims(outputScaleDims);
5239 if (outputDataDims.size() != outputScaleDims.size() ||
5241 ArrayRef<int64_t>(outputDataDims).drop_back(1),
5242 ArrayRef<int64_t>(outputScaleDims).drop_back(1))))
5243 return emitOpError() <<
"require compatible shapes for output_data ("
5244 << outputDataType <<
") and " <<
"output_scale ("
5246 <<
") except for the last dimension";
5248 const int64_t outputDataLastDim = outputDataDims.back();
5249 const SmallVector<int64_t, 2> dimsToCheck{outputDataLastDim / blockSize,
5250 outputScaleDims.back()};
5251 if (ShapedType::isStatic(outputDataLastDim) &&
5253 return emitOpError()
5254 <<
"expect last dimension of output_scale ("
5255 << outputScaleDims.back()
5256 <<
") to be equal to last dimension of output_data / block_size ("
5257 << outputDataDims.back() / blockSize <<
")";
5263LogicalResult IfOp::inferReturnTypeComponents(
5264 MLIRContext *context, ::std::optional<Location> location,
5265 IfOp::Adaptor adaptor,
5266 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5267 llvm::SmallVector<tosa::YieldOp> yieldOps;
5268 for (Region *region : adaptor.getRegions()) {
5269 for (
auto &block : *region)
5270 if (
auto returnOp = dyn_cast<tosa::YieldOp>(block.getTerminator()))
5271 yieldOps.push_back(returnOp);
5274 if (yieldOps.empty())
5278 llvm::SmallVector<ValueKnowledge> resultKnowledge;
5279 resultKnowledge.reserve(yieldOps.front().getNumOperands());
5280 for (
auto operand : yieldOps.front().getOperands()) {
5281 resultKnowledge.push_back(
5285 for (
auto yieldOp : yieldOps) {
5286 if (resultKnowledge.size() != yieldOp.getNumOperands())
5289 for (
const auto &it : llvm::enumerate(yieldOp.getOperands())) {
5290 int32_t index = it.index();
5292 resultKnowledge[index],
5296 resultKnowledge[index] = meet;
5300 for (
const ValueKnowledge &
result : resultKnowledge) {
5301 inferredReturnShapes.push_back(
result.getShapedTypeComponents());
5307LogicalResult WhileOp::inferReturnTypeComponents(
5308 MLIRContext *context, ::std::optional<Location> location,
5309 WhileOp::Adaptor adaptor,
5310 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5311 llvm::SmallVector<tosa::YieldOp> yieldOps;
5312 for (
auto &block : adaptor.getBodyGraph())
5313 if (
auto returnOp = dyn_cast<tosa::YieldOp>(block.getTerminator()))
5314 yieldOps.push_back(returnOp);
5318 if (yieldOps.empty())
5322 llvm::SmallVector<ValueKnowledge> resultKnowledge;
5323 resultKnowledge.reserve(yieldOps.front().getNumOperands());
5324 for (
auto operand : yieldOps.front().getOperands()) {
5325 resultKnowledge.push_back(
5329 for (
auto yieldOp : yieldOps) {
5330 if (resultKnowledge.size() != yieldOp.getNumOperands())
5333 for (
const auto &it : llvm::enumerate(yieldOp.getOperands())) {
5334 int32_t index = it.index();
5336 resultKnowledge[index],
5338 resultKnowledge[index] = meet;
5343 for (
const ValueKnowledge &
result : resultKnowledge) {
5344 inferredReturnShapes.push_back(
result.getShapedTypeComponents());
5350std::optional<SmallVector<int64_t, 4>>
5351ApplyScaleOp::getIterationShapeToUnroll() {
5352 if (
auto vt = llvm::dyn_cast<VectorType>(
getType()))
5353 return llvm::to_vector<4>(vt.getShape());
5354 return std::nullopt;
5360 StringRef prefix =
"") {
5361 assert(blocksArgs.size() == initializers.size() &&
5362 "expected same length of arguments and initializers");
5363 if (initializers.empty())
5366 parser << prefix <<
'(';
5367 llvm::interleaveComma(
5368 llvm::zip(blocksArgs, initializers), parser,
5369 [&](
auto it) { parser << std::get<0>(it) <<
" = " << std::get<1>(it); });
5374ParseResult IfOp::parse(OpAsmParser &parser, OperationState &
result) {
5376 result.regions.reserve(2);
5377 Region *thenRegion =
result.addRegion();
5378 Region *elseRegion =
result.addRegion();
5380 OpAsmParser::UnresolvedOperand cond;
5385 SmallVector<OpAsmParser::Argument, 4> regionArgs;
5386 SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
5389 OptionalParseResult listResult =
5397 "expected type for condition operand");
5403 "expected type for condition operand");
5411 FunctionType functionType;
5415 <<
"expected list of types for block arguments "
5416 <<
"followed by arrow type and list of return types";
5418 result.addTypes(functionType.getResults());
5420 if (functionType.getNumInputs() != operands.size()) {
5422 <<
"expected as many input types as operands " <<
"(expected "
5423 << operands.size() <<
" got " << functionType.getNumInputs()
5454void IfOp::print(OpAsmPrinter &p) {
5455 p <<
" " << getCondition();
5458 getInputList(),
" ");
5460 p << getCondition().getType();
5462 if (!getInputList().empty()) {
5464 llvm::interleaveComma(getInputList().getTypes(), p);
5473 auto &elseRegion = getElseGraph();
5474 if (!elseRegion.
empty()) {
5482LogicalResult IfOp::verify() {
5484 "'then_graph' arguments", getInputList(),
5490 "'else_graph' arguments", getInputList(),
5496 if (getThenGraph().front().mightHaveTerminator()) {
5498 dyn_cast<tosa::YieldOp>(getThenGraph().front().getTerminator());
5500 *
this, thenYield.getInputs(),
"'then_graph' results",
5501 getOutputList(),
"'output_list'")
5507 if (getElseGraph().front().mightHaveTerminator()) {
5509 dyn_cast<tosa::YieldOp>(getElseGraph().front().getTerminator());
5511 *
this, elseYield.getInputs(),
"'else_graph' results",
5512 getOutputList(),
"'output_list'")
5517 auto condType = getCondition().getType();
5519 return emitOpError() <<
"'condition' must be a size 1 tensor, got "
5525LogicalResult WhileOp::verify() {
5527 getOutputList(),
"'output_list'")
5532 "'cond_graph' arguments", getInputList(),
5538 "'body_graph' arguments", getInputList(),
5543 if (getBodyGraph().front().mightHaveTerminator()) {
5545 dyn_cast<tosa::YieldOp>(getBodyGraph().front().getTerminator());
5547 "'body_graph' results",
5548 getInputList(),
"'input_list'")
5555 if (!getCondGraph().front().mightHaveTerminator())
5559 dyn_cast<tosa::YieldOp>(getCondGraph().front().getTerminator());
5563 if (condYield.getInputs().size() != 1)
5564 return emitOpError() <<
"require 'cond_graph' only have one result";
5566 auto condOutType = condYield.getInputs()[0].getType();
5568 return emitOpError() <<
"'cond_graph' result must be a size 1 tensor, got "
5572 return emitOpError() <<
"'cond_graph' result must be a boolean tensor, got "
5578LogicalResult ReverseOp::verify() {
5579 TensorType inputType = getInput1().getType();
5580 int32_t reverseAxis = getAxis();
5582 if (reverseAxis < 0)
5583 return emitOpError(
"expected non-negative reverse axis");
5585 int64_t inputRank = inputType.getRank();
5588 if (reverseAxis >= inputRank && (reverseAxis != 0 || inputRank != 0))
5589 return emitOpError(
"expect input tensor rank (")
5590 << inputRank <<
") to be larger than reverse axis (" << reverseAxis
5597LogicalResult tosa::SelectOp::verify() {
5608 auto predicateType = llvm::dyn_cast<ShapedType>(getPred().
getType());
5609 if (!predicateType) {
5610 return emitOpError(
"expect shaped tensor for input1, got ")
5611 << getInput1().getType();
5613 auto predicateElementType = predicateType.getElementType();
5614 if (!predicateElementType.isInteger(1)) {
5615 return emitOpError(
"expect element type of bool for input1, got ")
5616 << predicateElementType;
5622LogicalResult tosa::VariableReadOp::verify() {
5630LogicalResult tosa::VariableWriteOp::verify() {
5639ParseResult WhileOp::parse(OpAsmParser &parser, OperationState &
result) {
5640 SmallVector<OpAsmParser::Argument, 4> regionArgs;
5641 SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
5642 Region *cond =
result.addRegion();
5643 Region *body =
result.addRegion();
5645 OptionalParseResult listResult =
5650 FunctionType functionType;
5655 result.addTypes(functionType.getResults());
5657 if (functionType.getNumInputs() != operands.size()) {
5659 <<
"expected as many input types as operands " <<
"(expected "
5660 << operands.size() <<
" got " << functionType.getNumInputs() <<
")";
5670 for (
size_t i = 0, e = regionArgs.size(); i != e; ++i)
5671 regionArgs[i].type = functionType.getInput(i);
5673 return failure(parser.
parseRegion(*cond, regionArgs) ||
5678void WhileOp::print(OpAsmPrinter &parser) {
5680 getInputList(),
" ");
5683 getResults().getTypes());
5689 (*this)->getDiscardableAttrDictionary().getValue());
5698 auto zpType = mlir::RankedTensorType::get({1}, srcElemType);
5699 if (llvm::isa<FloatType>(srcElemType)) {
5701 zpType, builder.
getFloatAttr(srcElemType,
static_cast<double>(zp)));
5702 return tosa::ConstOp::create(builder, loc, zpType, zpAttr);
5704 if (llvm::isa<IntegerType>(srcElemType)) {
5707 return tosa::ConstOp::create(builder, loc, zpType, zpAttr);
5709 llvm::errs() <<
"zero point is not allowed for unsupported data types\n";
5710 return std::nullopt;
5718 return mlir::isa<tosa::shapeType>(t);
5725 return emitError() <<
"invalid rank (must be >= 0): " << rank;
5731 if (mlir::isa<::mlir::tosa::shapeType>(v.getType())) {
5732 Operation *definingOp = v.getDefiningOp();
5734 return op->
emitOpError(
"shape operand is not compile time resolvable");
5747 auto getRank = [](
const Type type) {
5748 return mlir::cast<mlir::tosa::shapeType>(type).getRank();
5754 for (
auto type : operandTypes) {
5755 if (getRank(type) != rank) {
5756 return op->
emitOpError(
"operands don't have matching ranks");
5759 for (
auto type : resultTypes) {
5760 if (getRank(type) != rank) {
5761 return op->
emitOpError(
"result shape has different rank than operands");
5771LogicalResult tosa::ConstShapeOp::verify() {
5773 auto valuesRank = getValues().getType().getRank();
5774 if (valuesRank != 1)
5775 return emitOpError(
"expect elements in attribute values with rank 1");
5777 auto count = getValues().getNumElements();
5778 auto rank = (cast<tosa::shapeType>(getResult().
getType())).getRank();
5779 if (count != rank && (count != 1 || rank != 0)) {
5780 return emitOpError(
"expect number of elements in attribute values (")
5781 << count <<
") to be equal to the rank (" << rank
5782 <<
") for the result shape type";
5787LogicalResult tosa::DimOp::verify() {
5788 const tosa::shapeType outShapeType =
5789 cast<tosa::shapeType>(getResult().
getType());
5790 if (outShapeType.getRank() != 1)
5791 return emitOpError(
"expect output shape type to contain one element, got ")
5796 const int64_t inputRank = inputType.getRank();
5797 const int64_t axis = getAxisAttr().getInt();
5798 if (axis < 0 || axis >= inputRank)
5799 return emitOpError(
"expect axis to be in the range [0, ")
5800 << inputRank <<
"), got " << axis;
5805LogicalResult tosa::ConcatShapeOp::verify() {
5806 const tosa::shapeType outShapeType =
5807 cast<tosa::shapeType>(getResult().
getType());
5808 const int64_t outputRank = outShapeType.getRank();
5811 if (inputList.size() == 0)
5812 return emitOpError(
"requires at least one input shape");
5814 if (llvm::any_of(inputList, [](Value v) {
5815 return cast<tosa::shapeType>(v.
getType()).getRank() == 0;
5817 return emitOpError(
"requires all inputs shapes have a rank greater than 0");
5819 const int64_t inputsRank =
5820 llvm::accumulate(inputList, 0, [](int64_t acc,
const Value &input) {
5821 const tosa::shapeType inShapeType =
5822 cast<tosa::shapeType>(input.
getType());
5823 return acc + inShapeType.getRank();
5825 if (outputRank != inputsRank)
5826 return emitOpError(
"requires output shape rank to be equal to the sum of "
5827 "the input shape ranks (")
5828 << inputsRank <<
"), got " << outputRank;
5833LogicalResult tosa::SliceShapeOp::verify() {
5834 std::optional<int32_t> start;
5835 DenseIntElementsAttr startAttr;
5837 start = startAttr.getValues<int32_t>()[0];
5838 if (start && start.value() < 0)
5839 return emitOpError(
"expected non-negative start index, got ")
5842 std::optional<int32_t> size;
5843 DenseIntElementsAttr sizeAttr;
5845 size = sizeAttr.getValues<int32_t>()[0];
5846 if (size && size.value() <= 0)
5847 return emitOpError(
"expected positive size, got ") << size.value();
5852 const tosa::shapeType outShapeType =
5853 cast<tosa::shapeType>(getResult().
getType());
5854 const int64_t outputRank = outShapeType.getRank();
5855 if (outputRank != size)
5857 "expected output type size to be equal to size attribute, got ")
5858 << outputRank <<
" vs " << size.value();
5863 const tosa::shapeType inShapeType =
5864 cast<tosa::shapeType>(getInput().
getType());
5865 const int64_t inputRank = inShapeType.getRank();
5866 const int64_t sliceSize = start.value() + size.value();
5867 if (sliceSize > inputRank)
5868 return emitOpError(
"expected start + size to be less than or equal to "
5869 "input shape rank (")
5870 << inputRank <<
"), got " << sliceSize;
5879#define GET_ATTRDEF_CLASSES
5880#include "mlir/Dialect/Tosa/IR/TosaAttributes.cpp.inc"
5885#define GET_TYPEDEF_CLASSES
5886#include "mlir/Dialect/Tosa/IR/TosaOpsTypesBase.cpp.inc"
5907 printer << keyword <<
'(';
5929#define GET_OP_CLASSES
5930#include "mlir/Dialect/Tosa/IR/TosaOps.cpp.inc"
static void printInitializationList(OpAsmPrinter &p, Block::BlockArgListType blocksArgs, ValueRange initializers, StringRef prefix="")
Prints the initialization list in the form of <prefix>(inner = outer, inner2 = outer2,...
true
Given two iterators into the same block, return "true" if a is before `b.
static bool isLegalToInline(InlinerInterface &interface, Region *src, Region *insertRegion, bool shouldCloneInlinedRegion, IRMapping &valueMapping)
Utility to check that all of the operations within 'src' can be inlined.
static Type getValueType(Attribute attr)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
static LogicalResult verifyMatMulShapes(T op, bool transposeB)
static ParseResult parseOptionalBoolClause(OpAsmParser &parser, StringRef keyword, BoolAttr &result)
static void printShapeToDiagnostic(InFlightDiagnostic &diag, ArrayRef< int64_t > shape)
static void buildMatMulOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value a, Value b)
static LogicalResult verifySameElementTypes(Operation *op, Type aType, Type bType, StringRef aName="input", StringRef bName="output")
static ParseResult parseLocalBound(OpAsmParser &parser, BoolAttr &result)
LogicalResult inferConvReturnTypeComponents(AdaptorT adaptor, SmallVectorImpl< ShapedTypeComponents > &inferredReturnShapes)
static int64_t getMatMulBatchDim(const ShapeAdaptor &shape, int64_t outputRank, int64_t axis)
static SmallVector< int64_t > convertToMlirShape(ArrayRef< int64_t > shape)
static LogicalResult ReduceInferReturnTypes(ShapeAdaptor operandShape, Type inputType, IntegerAttr axis, SmallVectorImpl< ShapedTypeComponents > &inferredReturnShapes)
static void printScaleValues(AsmPrinter &printer, ArrayRef< Attribute > scaleValues, Type)
static void buildAvgPool2dAdaptiveOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value input, DenseI64ArrayAttr kernel, DenseI64ArrayAttr stride, DenseI64ArrayAttr pad, TypeAttr accType)
This builder mirrors avg_pool2d quant-info handling and materializes kernel/stride/pad as const_shape...
static LogicalResult verifyRescaleValueAndZpTypes(Operation *op, Value val, Value valZp, StringRef name)
static void printOptionalBoolClause(OpAsmPrinter &printer, StringRef keyword, BoolAttr attr)
static LogicalResult errorIfShapeNotSizeOne(Operation *op, Type type)
static void printLocalBound(OpAsmPrinter &printer, Operation *, BoolAttr attr)
LogicalResult argMaxMinVerify(T op)
static LogicalResult verifyMatMulZeroPointType(T op, Value input, Value zp, StringRef inputName, StringRef zpName)
static ParseResult parseScaleValues(AsmParser &parser, SmallVector< Attribute > &scaleValues, Type scaleType)
static ParseResult parseInputUnsigned(OpAsmParser &parser, BoolAttr &result)
#define REDUCE_SHAPE_INFER(OP)
static LogicalResult verifyConvOp(T op)
static LogicalResult verifyAvgPoolCommonTypeAndZpChecks(T op)
static LogicalResult verifyVariableOpErrorIf(T op, Type type, StringRef name)
static LogicalResult poolingInferReturnTypes(ShapeAdaptor inputShape, ArrayRef< int64_t > kernel, ArrayRef< int64_t > stride, ArrayRef< int64_t > pad, SmallVectorImpl< ShapedTypeComponents > &inferredReturnShapes)
static void buildPadOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value input, Value paddings)
This builder is called on TOSA pad operator that needs to create its own OptionalAttr quantization_at...
static LogicalResult verifyPoolingOpImpl(Operation *op, ArrayRef< int64_t > kernel, ArrayRef< int64_t > strides, ArrayRef< int64_t > padding, Value input, Value output)
static std::optional< int64_t > idivCheck(const int64_t lhs, const int64_t rhs)
static void buildVariableOp(OpBuilder &builder, OperationState &result, StringRef name, Type variableType, Attribute initialValue)
static void buildMatMulLikeOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value a, Value b)
LogicalResult verifyConvOutputSize(Operation *op, const int64_t inputSize, const int64_t kernelSize, const int64_t outputSize, const int64_t padBefore, const int64_t padAfter, const int64_t stride, const int64_t dilation, const llvm::StringRef dimName, const llvm::StringRef dimAxis, const llvm::StringRef padBeforeName, const llvm::StringRef padAfterName)
static LogicalResult verifyReduceOp(T op)
#define NARY_SHAPE_INFER(OP)
#define ZERO_POINT_HELPER(OP, OPERAND_NAME, SIGN_EXTEND)
static void buildTransConvOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value input, Value weight, Value bias, DenseI64ArrayAttr outpad, DenseI64ArrayAttr stride, TypeAttr accType)
Handles tosa.transpose_conv2d which has outpad and output shape attributes.
LogicalResult inferArgMaxMinReturnTypeComponents(MLIRContext *context, ::std::optional< Location > location, A adaptor, SmallVectorImpl< ShapedTypeComponents > &inferredReturnShapes)
static void extractAdaptivePoolingConstShapeOperands(T op, AdaptivePoolingConstShapeValues &values)
static LogicalResult verifyConvOpErrorIf(T op)
static FailureOr< int64_t > getZeroPoint(Value val, bool signExtend)
static constexpr bool IsSupportedAdaptivePoolConstShapeVerifyOp
LogicalResult tryUpdateDimOrFailure(Operation *op, int64_t &currDim, const int64_t newDim, const StringRef operandName, const StringRef dimName)
static LogicalResult NAryInferReturnTypes(const ValueShapeRange &operands, SmallVectorImpl< ShapedTypeComponents > &inferredReturnShapes)
#define COMPATIBLE_RETURN_TYPES(OP)
static LogicalResult resolveBroadcastShape(const ValueShapeRange &operands, SmallVector< int64_t > &outShape)
static LogicalResult verifyMatMulQuantizedOperandsType(T op, Type aElementType, Type bElementType)
static LogicalResult verifyOutputShapeCompatibleWithExpected(Operation *op, ShapedType outputType, ArrayRef< int64_t > expectedShape, StringRef outputName="output")
static void printInputUnsigned(OpAsmPrinter &printer, Operation *, BoolAttr attr)
static void buildNegateOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value input)
This builder is called on single-parameter negate operator to construct input and output zero points ...
static void buildConvOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value input, Value weight, Value bias, DenseI64ArrayAttr pad, DenseI64ArrayAttr stride, DenseI64ArrayAttr dilation, TypeAttr accType)
This builder is called on all convolution operators except TransposeConv, which has specialized outpu...
static SmallVector< int64_t > getMatMulBatchShape(const ShapeAdaptor &shape)
static void buildAvgPool2dOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value input, DenseArrayAttr kernel, DenseArrayAttr stride, DenseArrayAttr pad, TypeAttr accType)
Both the tosa.avg_pool2d and unary ops use the same UnaryOpQuantizationAttr but avg_pool operator has...
static LogicalResult errorIfTypeOrShapeMismatch(Operation *op, Type type1, StringRef name1, Type type2, StringRef name2)
static LogicalResult inferMatMulReturnTypeComponents(const ShapeAdaptor &aShape, const ShapeAdaptor &bShape, bool transposeB, SmallVectorImpl< ShapedTypeComponents > &inferredReturnShapes)
static void buildMatMulTOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value a, Value b)
static FailureOr< SmallVector< int64_t > > resolveMatMulOutputShape(const ShapeAdaptor &aShape, const ShapeAdaptor &bShape, int64_t outputRank, bool transposeB)
static FailureOr< int64_t > resolveBroadcastDim(const int64_t dim1, const int64_t dim2)
static LogicalResult verifyZeroPoint(T op, Value val, const int64_t &zp, const std::string &operand)
static LogicalResult verifyPoolingOp(T op)
static LogicalResult verifyDimIsPowerOfTwo(Operation *op, const int64_t dimSize, const llvm::StringRef dimName)
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
static void updateIfDynamic(int64_t ¤t, int64_t candidate)
void inferWeightShape(SmallVectorImpl< int64_t > &outputShape, SmallVectorImpl< int64_t > &weightSpatial)
LogicalResult getSpatialParameters(SmallVector< int64_t > &padValues, SmallVector< int64_t > &strideValues, SmallVector< int64_t > &dilationValues)
void inferInputShape(SmallVectorImpl< int64_t > &outputShape, SmallVectorImpl< int64_t > &inputSpatial)
ConvInferShapeAdaptor(Conv2DBlockScaledOp::Adaptor adaptor)
int64_t getOutputRank() const
int64_t getNumSpatialDims() const
void inferInputShape(SmallVectorImpl< int64_t > &outputShape, SmallVectorImpl< int64_t > &inputSpatial)
void inferWeightShape(SmallVectorImpl< int64_t > &outputShape, SmallVectorImpl< int64_t > &weightSpatial)
ConvInferShapeAdaptor(Conv2DOp::Adaptor adaptor)
int64_t getNumSpatialDims() const
int64_t getOutputRank() const
LogicalResult getSpatialParameters(SmallVector< int64_t > &padValues, SmallVector< int64_t > &strideValues, SmallVector< int64_t > &dilationValues)
int64_t getNumSpatialDims() const
void inferWeightShape(SmallVectorImpl< int64_t > &outputShape, SmallVectorImpl< int64_t > &weightSpatial)
int64_t getOutputRank() const
ConvInferShapeAdaptor(Conv3DOp::Adaptor adaptor)
void inferInputShape(SmallVectorImpl< int64_t > &outputShape, SmallVectorImpl< int64_t > &inputSpatial)
LogicalResult getSpatialParameters(SmallVector< int64_t > &padValues, SmallVector< int64_t > &strideValues, SmallVector< int64_t > &dilationValues)
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalEqual()=0
Parse a = token if present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseOptionalColon()=0
Parse a : token if present.
virtual ParseResult parseOptionalAttrDictWithKeyword(NamedAttrList &result)=0
Parse a named dictionary into 'result' if the attributes keyword is present.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseColon()=0
Parse a : token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseOptionalArrowTypeList(SmallVectorImpl< Type > &result)=0
Parse an optional arrow followed by a type list.
virtual ParseResult parseFloat(double &result)=0
Parse a floating point value from the stream.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual void printAttribute(Attribute attr)
void printArrowTypeList(TypeRange &&types)
Attributes are known-constant values of operations.
MutableArrayRef< BlockArgument > BlockArgListType
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
This class is a general helper class for creating context-global objects like types,...
IntegerAttr getIndexAttr(int64_t value)
IntegerAttr getIntegerAttr(Type type, int64_t value)
FloatAttr getFloatAttr(Type type, double value)
IntegerType getIntegerType(unsigned width)
StringAttr getStringAttr(const Twine &bytes)
DenseIntElementsAttr getIndexTensorAttr(ArrayRef< int64_t > values)
An attribute that represents a reference to a dense vector or tensor object.
auto getValues() const
Return the held element values as a range of the given type.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
An attribute that represents a reference to a dense integer vector or tensor object.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
virtual InFlightDiagnostic emitError(const Twine &msg={}) const =0
Emit an error to the reader.
ImplicitLocOpBuilder maintains a 'current location', allowing use of the create<> method without spec...
This class represents a diagnostic that is inflight and set to be reported.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual OptionalParseResult parseOptionalAssignmentList(SmallVectorImpl< Argument > &lhs, SmallVectorImpl< UnresolvedOperand > &rhs)=0
virtual ParseResult parseRegion(Region ®ion, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
virtual ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printOptionalAttrDictWithKeyword(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary prefixed with 'attribute...
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
void printFunctionalType(Operation *op)
Print the complete type of an operation in functional form.
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
This class helps build Operations.
This class indicates that op operates on tosa shape types.
Operation is the basic unit of execution within MLIR.
ResultRange result_range
Support result iteration.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
OperandRange operand_range
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
ParseResult value() const
Access the internal ParseResult value.
bool has_value() const
Returns true if we contain a valid ParseResult value.
Type-safe wrapper around a void* for passing properties, including the properties structs of operatio...
This class provides an abstraction over the different types of ranges over Regions.
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Adaptor class to abstract the differences between whether value is from a ShapedType or ShapedTypeCom...
bool isDynamicDim(int index) const
Returns whether the index'th dimension is dynamic.
int64_t getDimSize(int index) const
Returns the size of the index'th dimension.
int64_t getRank() const
Returns the rank of the shape.
bool hasStaticShape() const
Returns whether the shape is fully static.
int64_t getNumElements() const
Returns the number of elements in the shape.
void getDims(SmallVectorImpl< int64_t > &res) const
Populates the dimensions from shape referenced.
bool hasRank() const
Returns whether the shape has a rank.
ShapedTypeComponents that represents the components of a ShapedType.
This class allows for representing and managing the symbol table used by operations with the 'SymbolT...
Operation * lookup(StringRef name) const
Look up a symbol with the specified name, returning null if no such name exists.
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
ArrayRef< int64_t > getShape() const
Returns the shape of this tensor type.
bool hasRank() const
Returns if this type is ranked, i.e. it has a known number of dimensions.
This class provides an abstraction over the various different ranges of value types.
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 isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
bool isUnsignedInteger() const
Return true if this is an unsigned integer type (with the specified width).
bool isInteger() const
Return true if this is an integer type (with the specified width).
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
type_range getTypes() const
Range of values and shapes (corresponding effectively to Shapes dialect's ValueShape type concept).
ShapeAdaptor getShape(int index) const
Returns the shape of index'th operand.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
ArrayRef< T > asArrayRef() const
LogicalResult verifyAtLeastNOperands(Operation *op, unsigned numOperands)
LogicalResult verifyTosaShapeOperatorWithSameRanks(Operation *op)
LogicalResult verifyTosaResolvableShapeOperands(Operation *op)
bool getBroadcastedShape(ArrayRef< int64_t > shape1, ArrayRef< int64_t > shape2, SmallVectorImpl< int64_t > &resultShape)
Returns true and sets resultShape to the broadcasted shape from the two given shapes if they are broa...
LogicalResult convertFloatTypeFromAttribute(Type type, Attribute attr, llvm::SmallVectorImpl< char > &result)
Float type implementation of DenseElementTypeInterface::convertFromAttribute.
Attribute convertFloatTypeToAttribute(Type type, llvm::ArrayRef< char > rawData)
Float type implementation of DenseElementTypeInterface::convertToAttribute.
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
SmallVector< unsigned > getBlockSize(AffineMap dimToLvl)
Given the dimToLvl map, returns the block sizes in a vector.
ConvOpQuantizationAttr buildConvOpQuantizationAttr(OpBuilder &builder, Value input, Value weight)
Method to build ConvOpQuantizationAttr, called from ConvOpQuantInfoBuilder/TransConvOpQuantInfoBuilde...
Type getStorageElementTypeOrSelf(Type type)
RankedTensorType getVariableType(VariableOp variableOp)
Type buildConvOpResultTypeInfo(OpBuilder &builder, Type outputType, Value input, Value weight)
construct ConvOp output type with correct bitwidth based on input/weight width.
ParseResult parseVariableOpTypeOrInitialValue(OpAsmParser &parser, DenseElementsAttr &varShapeAttr, TypeAttr &typeAttr, Attribute &initialValueAttr)
PadOpQuantizationAttr buildPadOpQuantizationAttr(OpBuilder &builder, Value input)
Builds PadOpQuantizationAttr, called from PadOpQuantInfoBuilder: inputZp: input zeropoint.
constexpr int64_t kInferableDimSize
Represents a dimension in the shape of a tensor that can be inferred based on the other provided dime...
std::pair< Value, Value > createZPsAsConst(OpBuilder &builder, Value input, Value weight)
void printVariableOpTypeOrInitialValue(OpAsmPrinter &p, Operation *op, DenseElementsAttr varShapeAttr, TypeAttr typeAttr, Attribute initialValueAttr)
FailureOr< T > getConstantScalarIntValue(Value val)
Value getTosaConstShape(ImplicitLocOpBuilder &builder, llvm::ArrayRef< int64_t > shape)
MatMulOpQuantizationAttr buildMatMulOpQuantizationAttr(OpBuilder &builder, Value a, Value b)
Builds MatMulOpQuantizationAttr, called from MatMulOpQuantInfoBuilder: aZp: input a zeropoint bZp: in...
unsigned getBitWidth(Type type)
std::optional< Value > createZeroPointTensor(OpBuilder &builder, Location loc, Type srcElemType, int64_t zp=0)
bool isa_tosa_shape_type(mlir::Type t)
SmallVector< int64_t > convertFromMlirShape(ArrayRef< int64_t > shape)
UnaryOpQuantizationAttr buildUnaryOpQuantizationAttr(OpBuilder &builder, Value input, Type outputRawType)
Builds UnaryOpQuantizationAttr UnaryOpQuantInfoBuilder: inputZp: input zeropoint outputZp: output zer...
Type getStorageElementTypeFromQuantized(quant::QuantizedType quantizedType)
Value createPadConstTensor(OpBuilder &builder, Location loc, Value src, int32_t val=0)
LogicalResult verifyBlockScaledTensorType(mlir::Type type, llvm::function_ref< mlir::InFlightDiagnostic()> emitError=nullptr, bool allowScaleValues=false)
std::string getTosaTensorTypeErrorMessage(mlir::Type type)
bool getConstShapeValues(Operation *op, llvm::SmallVector< int64_t > &result_shape)
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
LogicalResult verifyCompatibleShapes(TypeRange types1, TypeRange types2)
Returns success if the given two arrays have the same number of elements and each pair wise entries h...
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
LogicalResult emitOptionalError(std::optional< Location > loc, Args &&...args)
Overloads of the above emission functions that take an optionally null location.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
SmallVector< SmallVector< OpFoldResult > > ReifiedRankedShapedTypeDims
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
LogicalResult verifyCompatibleDims(ArrayRef< int64_t > dims)
Dimensions are compatible if all non-dynamic dims are equal.
LogicalResult verifyRanksMatch(Operation *op, ShapedType lhs, ShapedType rhs, StringRef lhsName, StringRef rhsName)
Verify that two shaped types have matching ranks.
LogicalResult verifyCompatibleShape(ArrayRef< int64_t > shape1, ArrayRef< int64_t > shape2)
Returns success if the given two shapes are compatible.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
llvm::function_ref< Fn > function_ref
bool isPermutationVector(ArrayRef< int64_t > interchange)
Method to check if an interchange vector is a permutation.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
static ValueKnowledge meet(const ValueKnowledge &lhs, const ValueKnowledge &rhs)
static ValueKnowledge getKnowledgeFromType(Type type)