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) {
278template <
typename EnumType>
279ParseResult parseAttrEntryWithEnumHandling(
OpAsmParser &parser,
281 llvm::StringRef name;
288 if constexpr (std::is_same_v<EnumType, tosa::RoundingMode>) {
289 if (name ==
"rounding_mode" &&
291 auto sym = symbolizeRoundingMode(kw);
294 <<
"invalid rounding_mode value: " << kw;
295 auto attr = RoundingModeAttr::get(parser.
getContext(), sym.value());
301 if constexpr (std::is_same_v<EnumType, tosa::ResizeMode>) {
303 auto sym = symbolizeResizeMode(kw);
306 <<
"invalid resize mode value: " << kw;
307 auto attr = ResizeModeAttr::get(parser.
getContext(), sym.value());
314 if constexpr (std::is_same_v<EnumType, tosa::NanPropagationMode>) {
316 auto sym = symbolizeNanPropagationMode(kw);
319 <<
"invalid nan_mode value: " << kw;
320 auto attr = NanPropagationModeAttr::get(parser.
getContext(), sym.value());
327 if constexpr (std::is_same_v<EnumType, tosa::BlockSize>) {
329 auto sym = symbolizeBlockSize(kw);
332 <<
"invalid block_size value: " << kw;
333 auto attr = BlockSizeAttr::get(parser.
getContext(), sym.value());
345template <
typename EnumType>
350 [&]() { return parser.parseOperand(operands.emplace_back()); }))
358 if (parseAttrEntryWithEnumHandling<EnumType>(parser, attrs))
375 result.addTypes(fnTy.getResults());
376 result.addAttributes(attrs);
382 parser << namedAttr.
getName().strref() <<
" = ";
384 if (
auto roundingModeAttr = dyn_cast<tosa::RoundingModeAttr>(attr)) {
385 parser << roundingModeAttr.getValue();
386 }
else if (
auto resizeModeAttr = dyn_cast<tosa::ResizeModeAttr>(attr)) {
387 parser << resizeModeAttr.getValue();
388 }
else if (
auto nanPropagationModeAttr =
389 dyn_cast<tosa::NanPropagationModeAttr>(attr)) {
390 parser << nanPropagationModeAttr.getValue();
391 }
else if (
auto blockSizeAttr = dyn_cast<tosa::BlockSizeAttr>(attr)) {
392 parser << blockSizeAttr.getValue();
405 const auto kDefaultNanValue = NanPropagationMode::PROPAGATE;
407 if (
auto nanAttr = dyn_cast<NanPropagationModeAttr>(attr.getValue())) {
408 if (nanAttr.getValue() == kDefaultNanValue) {
410 toPrint.erase(attr.getName());
416 if (!toPrint.empty()) {
418 llvm::interleaveComma(toPrint, parser, [&](
const NamedAttribute namedAttr) {
419 printNamedAttr(parser, namedAttr);
435 llvm::interleaveComma(op->
getAttrs(), parser,
437 printNamedAttr(parser, namedAttr);
449 return parseWithEnumHandling<tosa::RoundingMode>(parser,
result);
453 printWithEnumHandling(parser, *
this);
457 return parseWithEnumHandling<tosa::RoundingMode>(parser,
result);
461 printWithEnumHandling(parser, *
this);
465 return parseWithEnumHandling<tosa::ResizeMode>(parser,
result);
469 printWithEnumHandling(parser, *
this);
473 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
477 printWithNanPropagationHandling(parser, *
this);
481 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
485 printWithNanPropagationHandling(parser, *
this);
488ParseResult MaxPool2dAdaptiveOp::parse(
OpAsmParser &parser,
490 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
494 printWithNanPropagationHandling(parser, *
this);
498 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
502 printWithNanPropagationHandling(parser, *
this);
506 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
510 printWithNanPropagationHandling(parser, *
this);
514 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
518 printWithNanPropagationHandling(parser, *
this);
522 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
526 printWithNanPropagationHandling(parser, *
this);
530 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
534 printWithNanPropagationHandling(parser, *
this);
537ParseResult MatmulTBlockScaledOp::parse(
OpAsmParser &parser,
539 return parseWithEnumHandling<tosa::BlockSize>(parser,
result);
543 printWithEnumHandling(parser, *
this);
546ParseResult CastFromBlockScaledOp::parse(
OpAsmParser &parser,
548 return parseWithEnumHandling<tosa::BlockSize>(parser,
result);
551void CastFromBlockScaledOp::print(
OpAsmPrinter &parser) {
552 printWithEnumHandling(parser, *
this);
555ParseResult CastToBlockScaledOp::parse(
OpAsmParser &parser,
557 return parseWithEnumHandling<tosa::BlockSize>(parser,
result);
561 printWithEnumHandling(parser, *
this);
564ParseResult Conv2DBlockScaledOp::parse(
OpAsmParser &parser,
566 return parseWithEnumHandling<tosa::BlockSize>(parser,
result);
570 printWithEnumHandling(parser, *
this);
585 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(srcType))
595 Value valZp, StringRef name) {
600 mlir::isa<IntegerType>(eType) && mlir::isa<IntegerType>(eZpType);
604 if (!bothInts || !sameBitWidth) {
606 <<
"expected " << name <<
" and " << name
607 <<
"_zp to both be integer of the same bitwidth, but got " << eType
608 <<
" vs. " << eZpType;
615 Value src, int32_t val) {
618 const auto padConstType = mlir::RankedTensorType::get({1}, srcType);
619 const auto padConstEType = mlir::RankedTensorType::get({1}, srcElemType);
620 const auto padConstAttr{
621 llvm::isa<FloatType>(srcElemType)
626 return tosa::ConstOp::create(builder, loc, padConstType, padConstAttr);
630 if (
auto blockScaledTy = dyn_cast<tosa::BlockScaledType>(type))
632 if (dyn_cast<tosa::mxint8Type>(type))
641 const StringRef operandName,
642 const StringRef dimName) {
643 if (ShapedType::isDynamic(currDim)) {
646 }
else if (ShapedType::isStatic(newDim) && currDim != newDim) {
648 << dimName <<
" of " << operandName <<
" to match size " << currDim
649 <<
", got " << newDim;
656 auto printDim = [&](
int64_t dim) {
657 if (ShapedType::isDynamic(dim))
663 llvm::interleaveComma(
shape,
diag, printDim);
669 StringRef outputName =
"output") {
670 assert(outputType.hasRank() &&
"expected output type to be ranked");
676 diag << outputName <<
" shape ";
678 diag <<
" to be compatible with inferred shape ";
686 const int64_t stride,
const int64_t dilation,
const llvm::StringRef dimName,
687 const llvm::StringRef dimAxis,
const llvm::StringRef padBeforeName,
688 const llvm::StringRef padAfterName) {
689 if (inputSize == ShapedType::kDynamic || kernelSize == ShapedType::kDynamic)
694 const std::optional<int64_t> calculatedOutSizeMinusOne =
idivCheck(
695 inputSize - 1 + padBefore + padAfter - (kernelSize - 1) * dilation,
697 if (!calculatedOutSizeMinusOne.has_value())
699 << dimName <<
" - 1 + pad_" << padBeforeName <<
" + pad_"
700 << padAfterName <<
" - (kernel_" << dimName <<
" - 1) * dilation_"
701 << dimAxis <<
" to be wholly divisible by stride_" << dimAxis
702 <<
", got (" << inputSize <<
" - 1 + " << padBefore <<
" + "
703 << padAfter <<
" - (" << kernelSize <<
" - 1) * " << dilation
706 const int64_t calculatedOutSize = calculatedOutSizeMinusOne.value() + 1;
707 if (outputSize != ShapedType::kDynamic && calculatedOutSize != outputSize)
709 << dimName <<
" did not match expected: "
710 <<
"calculated=" << calculatedOutSize <<
", expected=" << outputSize;
718size_t mlir::tosa::mxint8Type::getDenseElementBitSize()
const {
return 8; }
721mlir::tosa::mxint8Type::convertToAttribute(
ArrayRef<char> rawData)
const {
722 assert(rawData.size() == 1 &&
"expected 1 byte for tosa.mxint8 element");
723 const auto intType = IntegerType::get(
getContext(), 8);
724 return intType.convertToAttribute(rawData);
727LogicalResult mlir::tosa::mxint8Type::convertFromAttribute(
729 const auto intAttr = dyn_cast<IntegerAttr>(attr);
732 const Type attrType = intAttr.getType();
735 return cast<IntegerType>(attrType).convertFromAttribute(attr,
result);
743 bool allowScaleValues) {
744 const auto tensorType = llvm::cast<ShapedType>(type);
745 const BlockScaledType elemType =
746 llvm::dyn_cast<BlockScaledType>(tensorType.getElementType());
750 if (!allowScaleValues && elemType.hasScaleValues())
753 if (!tensorType.hasRank())
756 if (tensorType.getRank() == 0)
760 const uint32_t blockSize =
761 BlockShapeAttr::getBlockShapeValue(elemType.getBlockShape());
763 if (allowScaleValues && elemType.hasScaleValues() &&
764 tensorType.hasStaticShape()) {
765 const size_t numBlocks = tensorType.getNumElements() / blockSize;
766 if (elemType.getScaleValues().size() != numBlocks)
770 const int64_t blockedDimension = tensorShape.back();
771 if (ShapedType::isDynamic(blockedDimension))
773 if (blockedDimension % blockSize != 0)
782 const auto parseScaleValue = [&]() -> ParseResult {
789 if (floatValue < 0.0)
790 return parser.
emitError(loc,
"scale value must be non-negative, got ")
793 Type attrType = scaleType;
797 if (attrType != scaleType)
798 return parser.
emitError(loc,
"parsed attribute type ")
799 << attrType <<
" does not match expected scale type " << scaleType;
801 scaleValues.push_back(FloatAttr::get(attrType, floatValue));
810 llvm::interleaveComma(scaleValues, printer, [&](
Attribute scaleValue) {
815size_t mlir::tosa::BlockScaledType::getDenseElementBitSize()
const {
817 if (isa<tosa::mxint8Type>(valueType))
823mlir::tosa::BlockScaledType::convertToAttribute(
ArrayRef<char> rawData)
const {
827 assert(rawData.size() == 1 &&
"expected 1 byte for block_scaled element");
829 if (
const auto mxint8Value = dyn_cast<tosa::mxint8Type>(valueType))
830 return mxint8Value.convertToAttribute(rawData);
831 if (!isa<FloatType>(valueType))
836LogicalResult mlir::tosa::BlockScaledType::convertFromAttribute(
839 if (
const auto mxint8Value = dyn_cast<tosa::mxint8Type>(valueType))
840 return mxint8Value.convertFromAttribute(attr,
result);
842 const auto floatAttr = dyn_cast<FloatAttr>(attr);
843 if (!floatAttr || floatAttr.getType() != valueType)
856 const auto inputType = llvm::dyn_cast<TensorType>(op.getInput().getType());
857 const auto weightType = llvm::dyn_cast<TensorType>(op.getWeight().getType());
859 auto inputEType = inputType.getElementType();
860 auto weightEType = weightType.getElementType();
862 llvm::cast<ShapedType>(op.getBias().getType()).getElementType();
864 llvm::cast<ShapedType>(op.getResult().getType()).getElementType();
865 bool biasIsFloat = llvm::isa<FloatType>(biasEType);
866 bool resultIsFloat = llvm::isa<FloatType>(resultEType);
868 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(inputEType))
871 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(weightEType))
874 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(biasEType))
877 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(resultEType))
880 if (biasIsFloat && resultIsFloat && (biasEType != resultEType)) {
884 "expect both bias and result to have same element type, got ")
885 << biasEType <<
" and " << resultEType;
889 const bool isInputBlockScaled = llvm::isa<BlockScaledType>(inputEType);
890 const bool isWeightBlockScaled = llvm::isa<BlockScaledType>(weightEType);
891 const bool isInputFloat = llvm::isa<FloatType>(inputEType);
892 const bool isWeightFloat = llvm::isa<FloatType>(weightEType);
894 const bool isInputBSorFloat = isInputBlockScaled || isInputFloat;
895 const bool isWeightBSorFloat = isWeightBlockScaled || isWeightFloat;
898 if (isInputBSorFloat != isWeightBSorFloat) {
900 "expect both input and weight to be float or not together, got ")
901 << inputEType <<
" and " << weightEType;
906 if (!isInputBlockScaled && inputEType != inputZpEType) {
907 return op.emitOpError(
"expect both input and its zero point are the same "
908 "element type, got ")
909 << inputEType <<
" and " << inputZpEType;
911 if (isInputBlockScaled && !llvm::isa<Float32Type>(inputZpEType)) {
912 return op.emitOpError(
913 "expect block scaled input to have fp32 zero point, got ")
914 << inputEType <<
" and " << inputZpEType;
918 if (!isWeightBlockScaled && weightEType != weightZpEType) {
919 return op.emitOpError(
"expect both weight and its zero point are the same "
920 "element type, got ")
921 << weightEType <<
" and " << weightZpEType;
923 if (isWeightBlockScaled && !llvm::isa<Float32Type>(weightZpEType)) {
924 return op.emitOpError(
925 "expect block scaled weight to have fp32 zero point, got ")
926 << weightEType <<
" and " << weightZpEType;
929 FailureOr<int64_t> maybeIZp = op.getInputZeroPoint();
930 if (succeeded(maybeIZp) && op.verifyInputZeroPoint(*maybeIZp).failed())
933 FailureOr<int64_t> maybeWZp = op.getWeightZeroPoint();
934 if (succeeded(maybeWZp) && op.verifyWeightZeroPoint(*maybeWZp).failed())
940LogicalResult tosa::ConstOp::verify() {
942 auto attrType = llvm::dyn_cast<TensorType>(getValuesAttr().
getType());
943 auto outputType = llvm::dyn_cast<TensorType>(getOutput().
getType());
945 if (!attrType || !outputType) {
946 emitOpError(
"expected tensors for attr/result type");
950 const Type attrElemType = attrType.getElementType();
951 const Type resultElemType = outputType.getElementType();
954 llvm::dyn_cast<mlir::quant::QuantizedType>(resultElemType)) {
959 if (
auto attrBlockScaledType =
960 llvm::dyn_cast<mlir::tosa::BlockScaledType>(attrElemType)) {
961 if (!attrBlockScaledType.hasScaleValues())
963 "attribute block scaled type must have scale values");
966 return op.
emitOpError(
"block scaled attribute type is not valid, got ")
969 const BlockScaledType resultBlockScaledType =
970 llvm::dyn_cast<mlir::tosa::BlockScaledType>(resultElemType);
971 if (!resultBlockScaledType)
973 "result type must be block scaled type if attribute is block "
976 if (attrBlockScaledType.getValueType() !=
977 resultBlockScaledType.getValueType() ||
978 attrBlockScaledType.getScaleType() !=
979 resultBlockScaledType.getScaleType() ||
980 attrBlockScaledType.getBlockShape() !=
981 resultBlockScaledType.getBlockShape())
983 "expected block scaled element type to be compatible "
984 "between attr and result, got ")
985 << attrBlockScaledType <<
" vs. " << resultBlockScaledType;
990 if (attrElemType != resultElemType)
991 return emitOpError(
"expected same attr/result element types");
999 llvm::cast<ShapedType>(op.getInput().getType()).getElementType();
1001 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(inputEType))
1005 llvm::cast<ShapedType>(op.getResult().getType()).getElementType();
1007 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(resultEType))
1018template <
typename T>
1021 if (llvm::any_of(padding, [](
int64_t p) {
return p < 0; }))
1022 return op.emitOpError(
"expect all padding values to be >= 0, got ")
1026 if (llvm::any_of(strides, [](
int64_t s) {
return s < 1; }))
1027 return op.emitOpError(
"expect all stride values to be >= 1, got ")
1031 if (llvm::any_of(dilations, [](
int64_t d) {
return d < 1; }))
1032 return op.emitOpError(
"expect all dilation values to be >= 1, got ")
1035 const RankedTensorType outputType =
1036 llvm::dyn_cast<RankedTensorType>(op.getOutput().getType());
1041 const RankedTensorType inputType =
1042 llvm::dyn_cast<RankedTensorType>(op.getInput().getType());
1043 const RankedTensorType weightType =
1044 llvm::dyn_cast<RankedTensorType>(op.getWeight().getType());
1046 if (inputType && weightType) {
1048 if constexpr (std::is_same<T, tosa::Conv2DOp>::value) {
1050 op, inputType.getDimSize(1), weightType.getDimSize(1),
1051 outputType.getDimSize(1), padding[0], padding[1], strides[0],
1052 dilations[0],
"height",
"y",
"top",
"bottom")))
1056 op, inputType.getDimSize(2), weightType.getDimSize(2),
1057 outputType.getDimSize(2), padding[2], padding[3], strides[1],
1058 dilations[1],
"width",
"x",
"left",
"right")))
1063 if constexpr (std::is_same<T, tosa::DepthwiseConv2DOp>::value) {
1065 op, inputType.getDimSize(1), weightType.getDimSize(0),
1066 outputType.getDimSize(1), padding[0], padding[1], strides[0],
1067 dilations[0],
"height",
"y",
"top",
"bottom")))
1071 op, inputType.getDimSize(2), weightType.getDimSize(1),
1072 outputType.getDimSize(2), padding[2], padding[3], strides[1],
1073 dilations[1],
"width",
"x",
"left",
"right")))
1078 if constexpr (std::is_same<T, tosa::Conv3DOp>::value) {
1080 op, inputType.getDimSize(1), weightType.getDimSize(1),
1081 outputType.getDimSize(1), padding[0], padding[1], strides[0],
1082 dilations[0],
"depth",
"d",
"front",
"back")))
1086 op, inputType.getDimSize(2), weightType.getDimSize(2),
1087 outputType.getDimSize(2), padding[2], padding[3], strides[1],
1088 dilations[1],
"height",
"y",
"top",
"bottom")))
1092 op, inputType.getDimSize(3), weightType.getDimSize(3),
1093 outputType.getDimSize(3), padding[4], padding[5], strides[2],
1094 dilations[2],
"width",
"x",
"left",
"right")))
1099 const RankedTensorType biasType =
1100 llvm::dyn_cast<RankedTensorType>(op.getBias().getType());
1105 const int64_t biasChannels = biasType.getDimSize(0);
1106 const int64_t outputChannels =
1107 outputType.getDimSize(outputType.getRank() - 1);
1108 if (biasChannels == ShapedType::kDynamic ||
1109 outputChannels == ShapedType::kDynamic)
1113 if (biasChannels != outputChannels && biasChannels != 1)
1114 return op.emitOpError(
1115 "bias channels expected to be equal to output channels (")
1116 << outputChannels <<
") or 1, got " << biasChannels;
1123 StringRef name1,
Type type2,
1125 auto shapeType1 = dyn_cast<ShapedType>(type1);
1126 auto shapeType2 = dyn_cast<ShapedType>(type2);
1127 if (!shapeType1 || !shapeType2)
1130 auto elemType1 = shapeType1.getElementType();
1131 auto elemType2 = shapeType2.getElementType();
1132 if (elemType1 != elemType2)
1134 <<
"require same element type for " << name1 <<
" (" << elemType1
1135 <<
") and " << name2 <<
" (" << elemType2 <<
")";
1139 <<
"require same shapes for " << name1 <<
" (" << type1 <<
") and "
1140 << name2 <<
" (" << type2 <<
")";
1150 if (list1.size() != list2.size())
1152 <<
"require same number of values in " << name1 <<
" ("
1153 << list1.size() <<
") and " << name2 <<
" (" << list2.size() <<
")";
1155 for (
auto [type1, type2] :
1172template <
typename T>
1175 op->template getParentWithTrait<OpTrait::SymbolTable>();
1182 const auto varOp = symTable.
lookup<tosa::VariableOp>(op.getName());
1186 return op->emitOpError(
"'")
1187 << op.getName() <<
"' has not been declared by 'tosa.variable'";
1201 StringRef aName =
"input",
1202 StringRef bName =
"output") {
1203 auto aTType = llvm::dyn_cast<TensorType>(aType);
1204 auto bTType = llvm::dyn_cast<TensorType>(bType);
1206 op->
emitOpError(
"expect shaped tensor for") << aName <<
", got " << aType;
1210 op->
emitOpError(
"expect shaped tensor for") << bName <<
", got" << bType;
1213 auto aElementType = aTType.getElementType();
1214 auto bElementType = bTType.getElementType();
1216 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(aElementType);
1218 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(bElementType);
1219 if ((aElementType.isIntOrIndexOrFloat() || aQuantType) &&
1220 (bElementType.isIntOrIndexOrFloat() || bQuantType) &&
1221 aElementType != bElementType) {
1227 << aName <<
" and " << bName <<
" to have same element type, got "
1228 << aElementType <<
" and " << bElementType;
1234LogicalResult tosa::ArgMaxOp::verify() {
1235 const ShapedType resultType = llvm::cast<ShapedType>(
getType());
1238 if (
const auto resultETy = resultType.getElementType();
1239 !resultETy.isIntOrIndex())
1240 return emitOpError(
"result tensor is not of integer type");
1242 const auto inputType = llvm::cast<ShapedType>(getInput().
getType());
1243 if (!inputType.hasRank())
1247 const int64_t axis = getAxisAttr().getInt();
1248 if (((axis < 0) || axis >= inputType.getRank()))
1249 return emitOpError(
"specified axis is outside the rank of the tensor");
1251 if (!resultType.hasRank())
1257 expectedOutputShape.erase(expectedOutputShape.begin() + axis);
1260 << expectedOutputShape <<
"', got '" << outputShape <<
"'";
1273 const bool hasKernel = kernel.size() > 0;
1274 const bool hasStrides = strides.size() > 0;
1275 const bool hasPad = padding.size() > 0;
1277 if (hasKernel && llvm::any_of(kernel, [](
int64_t s) {
return s < 1; }))
1278 return op->
emitOpError(
"expect all kernel values to be >= 1, got ")
1281 if (hasStrides && llvm::any_of(strides, [](
int64_t s) {
return s < 1; }))
1282 return op->
emitOpError(
"expect all stride values to be >= 1, got ")
1285 if (hasPad && llvm::any_of(padding, [](
int64_t p) {
return p < 0; }))
1286 return op->
emitOpError(
"expect all padding values to be >= 0, got ")
1289 if (hasKernel && hasPad) {
1291 const int64_t kernelX = kernel[1];
1292 const int64_t padLeft = padding[2];
1293 const int64_t padRight = padding[3];
1294 if (padRight >= kernelX || padLeft >= kernelX)
1295 return op->
emitOpError(
"expected left/right padding to be less than the "
1296 "width of the kernel, got pad_left=")
1297 << padLeft <<
", pad_right=" << padRight
1298 <<
", kernel_x=" << kernelX;
1300 const int64_t kernelY = kernel[0];
1301 const int64_t padTop = padding[0];
1302 const int64_t padBottom = padding[1];
1303 if (padTop >= kernelY || padBottom >= kernelY)
1304 return op->
emitOpError(
"expected top/bottom padding to be less than the "
1305 "height of the kernel, got pad_top=")
1306 << padTop <<
", pad_bottom=" << padBottom
1307 <<
", kernel_y=" << kernelY;
1310 const auto inputType = llvm::dyn_cast<RankedTensorType>(input.
getType());
1311 const auto outputType = llvm::dyn_cast<RankedTensorType>(output.
getType());
1312 if (!inputType || !outputType)
1315 if (hasKernel && hasStrides && hasPad) {
1316 const auto verifyOutputSize =
1320 const llvm::StringRef dimName,
const llvm::StringRef dimAxis,
1321 const llvm::StringRef padBeforeName,
1322 const llvm::StringRef padAfterName) -> LogicalResult {
1323 if (ShapedType::isDynamic(inputSize))
1326 const std::optional<int64_t> calculatedOutSizeMinusOne =
1327 idivCheck(inputSize + padBefore + padAfter - kernelSize, strideSize);
1328 if (!calculatedOutSizeMinusOne.has_value())
1330 << dimName <<
" + pad_" << padBeforeName <<
" + pad_"
1331 << padAfterName <<
" - kernel_" << dimAxis
1332 <<
" to be wholly divisible by stride_" << dimAxis <<
", got ("
1333 << inputSize <<
" + " << padBefore <<
" + " << padAfter <<
" - "
1334 << kernelSize <<
") / " << strideSize;
1336 const int64_t calculatedOutSize = calculatedOutSizeMinusOne.value() + 1;
1337 if (ShapedType::isStatic(outputSize) && calculatedOutSize != outputSize)
1339 << dimName <<
" did not match expected: " <<
"calculated="
1340 << calculatedOutSize <<
", expected=" << outputSize;
1345 if (failed(verifyOutputSize(inputType.getDimSize(1),
1346 outputType.getDimSize(1), kernel[0], strides[0],
1347 padding[0], padding[1],
"height",
"y",
"top",
1351 if (failed(verifyOutputSize(
1352 inputType.getDimSize(2), outputType.getDimSize(2), kernel[1],
1353 strides[1], padding[2], padding[3],
"width",
"x",
"left",
"right")))
1359template <
typename T>
1362 op.getPad(), op.getInput(), op.getOutput());
1365template <
typename T>
1369 const Type inputZpETy =
1371 const Type outputZpETy =
1374 auto accType = op.getAccType();
1375 if (llvm::isa<IntegerType>(inputETy) && !accType.isInteger(32))
1376 return op.emitOpError(
"accumulator type for integer tensor is not i32");
1378 if (inputETy.
isF16() && !(accType.isF16() || accType.isF32()))
1379 return op.emitOpError(
"accumulator type for f16 tensor is not f16/f32");
1381 if (inputETy.
isBF16() && !accType.isF32())
1382 return op.emitOpError(
"accumulator type for bf16 tensor is not f32");
1384 if (inputETy.
isF32() && !accType.isF32())
1385 return op.emitOpError(
"accumulator type for f32 tensor is not f32");
1387 if (inputETy != inputZpETy)
1388 return op.emitOpError(
"expect both input and its zero point are the same "
1389 "element type, got ")
1390 << inputETy <<
" and " << inputZpETy;
1392 if (resultETy != outputZpETy)
1393 return op.emitOpError(
"expect both output and its zero point are the same "
1394 "element type, got ")
1395 << resultETy <<
" and " << outputZpETy;
1397 FailureOr<int64_t> maybeIZp = op.getInputZeroPoint();
1398 if (succeeded(maybeIZp) && op.verifyInputZeroPoint(*maybeIZp).failed())
1401 FailureOr<int64_t> maybeOZp = op.getOutputZeroPoint();
1402 if (succeeded(maybeOZp) && op.verifyOutputZeroPoint(*maybeOZp).failed())
1409struct AdaptivePoolingConstShapeValues {
1410 llvm::SmallVector<int64_t> kernel;
1411 llvm::SmallVector<int64_t> stride;
1412 llvm::SmallVector<int64_t> pad;
1416template <
typename T>
1418 std::is_same_v<T, tosa::AvgPool2dAdaptiveOp> ||
1419 std::is_same_v<T, tosa::MaxPool2dAdaptiveOp>;
1421template <
typename T,
1422 typename std::enable_if<IsSupportedAdaptivePoolConstShapeVerifyOp<T>,
1425 T op, AdaptivePoolingConstShapeValues &values) {
1431LogicalResult tosa::AvgPool2dOp::verify() {
1439LogicalResult tosa::AvgPool2dAdaptiveOp::verify() {
1440 AdaptivePoolingConstShapeValues values;
1449 values.pad, getInput(), getOutput())))
1458LogicalResult tosa::ClampOp::verify() {
1460 llvm::cast<ShapedType>(getInput().
getType()).getElementType();
1461 if (
auto quantType =
1462 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(inputETy)) {
1466 llvm::cast<ShapedType>(getOutput().
getType()).getElementType();
1467 if (
auto quantType =
1468 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(outputETy)) {
1471 if (inputETy != outputETy)
1472 return emitOpError(
"input/output element types are incompatible.");
1474 auto maxValAttr = getMaxValAttr();
1475 auto minValAttr = getMinValAttr();
1479 if (inputETy.
isInteger(dataTypeBitWidth)) {
1483 auto intMaxValAttr = mlir::dyn_cast<mlir::IntegerAttr>(maxValAttr);
1484 auto intMinValAttr = mlir::dyn_cast<mlir::IntegerAttr>(minValAttr);
1485 if (!intMaxValAttr || !intMinValAttr ||
1486 (intMaxValAttr.getType() != intMinValAttr.getType()) ||
1487 (intMaxValAttr.getType() != inputETy))
1488 return emitOpError(
"min/max attributes types are incompatible with "
1489 "input/output element types.");
1492 const bool isBoolean = inputETy.
isInteger(1);
1493 const APInt minVal = intMinValAttr.getValue();
1494 const APInt maxVal = intMaxValAttr.getValue();
1495 if ((isUnsigned || isBoolean) ? maxVal.ult(minVal) : maxVal.slt(minVal))
1496 return emitOpError(
"expected min_val <= max_val, got min_val=")
1497 << minValAttr <<
", max_val=" << maxValAttr;
1502 auto floatMaxValAttr = mlir::dyn_cast<mlir::FloatAttr>(maxValAttr);
1503 auto floatMinValAttr = mlir::dyn_cast<mlir::FloatAttr>(minValAttr);
1504 if (!floatMaxValAttr || !floatMinValAttr ||
1505 (floatMaxValAttr.getType() != floatMinValAttr.getType()) ||
1506 (floatMaxValAttr.getType() != inputETy))
1507 return emitOpError(
"min/max attributes types are incompatible with "
1508 "input/output element types.");
1510 const APFloat minVal = floatMinValAttr.getValue();
1511 const APFloat maxVal = floatMaxValAttr.getValue();
1512 if (minVal.isNaN() || maxVal.isNaN())
1513 return emitOpError(
"min/max attributes should not be 'NaN', got min_val=")
1514 << minValAttr <<
", max_val=" << maxValAttr;
1516 if (maxVal < minVal)
1517 return emitOpError(
"expected min_val <= max_val, got min_val=")
1518 << minValAttr <<
", max_val=" << maxValAttr;
1538 result.addOperands({input, weight, bias, zps.first, zps.second});
1539 result.addAttribute(
"pad", pad);
1540 result.addAttribute(
"stride", stride);
1541 result.addAttribute(
"dilation", dilation);
1542 result.addAttribute(
"acc_type", accType);
1543 Type finalOutputType = outputType;
1549 result.addTypes(finalOutputType);
1560 result.addOperands({input, weight, bias, zps.first, zps.second});
1561 result.addAttribute(
"out_pad", outpad);
1562 result.addAttribute(
"stride", stride);
1563 result.addAttribute(
"acc_type", accType);
1564 Type finalOutputType = outputType;
1570 result.addTypes(finalOutputType);
1577 result.addOperands({a,
b, zps.first, zps.second});
1579 Type finalOutputType{outputType};
1582 auto inputBits = eType.getIntOrFloatBitWidth();
1584 auto outputShapedType = llvm::dyn_cast<ShapedType>(outputType);
1585 assert(outputShapedType &&
"Output must be a shaped type");
1587 IntegerType accElementType;
1588 if (inputBits == 16)
1593 finalOutputType = outputShapedType.clone(accElementType);
1595 result.addTypes(finalOutputType);
1616 DenseArrayAttr kernel, DenseArrayAttr stride,
1617 DenseArrayAttr pad, TypeAttr accType) {
1622 if (
auto quantAttr =
1624 inputZp = quantAttr.getInputZp();
1625 outputZp = quantAttr.getOutputZp();
1627 const std::optional<Value> inputZpOp =
1632 "Failed to create input zero point tensor for quantized AVG_POOL2D op");
1634 const std::optional<Value> outputZpOp =
1637 (
void)
emitError(loc,
"Failed to create output zero point tensor for "
1638 "quantized AVG_POOL2D op");
1641 if (inputZpOp && outputZpOp) {
1642 result.addOperands({input, inputZpOp.value(), outputZpOp.value()});
1647 result.addOperands({input});
1649 result.addAttribute(
"kernel", kernel);
1650 result.addAttribute(
"stride", stride);
1651 result.addAttribute(
"pad", pad);
1652 result.addAttribute(
"acc_type", accType);
1653 result.types.push_back(outputType);
1666 if (
auto quantAttr =
1668 inputZp = quantAttr.getInputZp();
1669 outputZp = quantAttr.getOutputZp();
1671 const std::optional<Value> inputZpOp =
1675 "Failed to create input zero point tensor for quantized "
1676 "AVG_POOL2D_ADAPTIVE op");
1678 const std::optional<Value> outputZpOp =
1681 (
void)
emitError(loc,
"Failed to create output zero point tensor for "
1682 "quantized AVG_POOL2D_ADAPTIVE op");
1685 if (inputZpOp && outputZpOp) {
1690 result.addOperands({input, inputZpOp.value(), outputZpOp.value(),
1691 kernelShape, strideShape, padShape});
1696 result.addOperands({input});
1698 result.addAttribute(
"acc_type", accType);
1699 result.types.push_back(outputType);
1713 input1Zp = quantAttr.getInputZp();
1714 outputZp = quantAttr.getOutputZp();
1716 const std::optional<Value> input1ZpOp =
1720 loc,
"Failed to create input1 zero point for quantized NEGATE op");
1723 const std::optional<Value> outputZpOp =
1727 loc,
"Failed to create output zero point for quantized NEGATE op");
1730 if (input1ZpOp && outputZpOp) {
1731 result.addOperands({input, input1ZpOp.value(), outputZpOp.value()});
1736 result.addOperands({input});
1739 result.types.push_back(outputType);
1752 zp =
static_cast<int32_t
>(quantAttr.getInputZp());
1755 result.addOperands({input, paddings, padConstOp});
1756 result.types.push_back(outputType);
1760 StringRef name,
Type variableType,
1765 auto shapedType = dyn_cast<ShapedType>(variableType);
1767 (
void)
emitError(loc,
"variable type must be a shaped type");
1770 if (!shapedType.hasRank()) {
1771 (
void)
emitError(loc,
"variable type must be a ranked type");
1775 auto elementType = shapedType.getElementType();
1776 auto elementTypeAttr = TypeAttr::get(elementType);
1780 result.addAttribute(
"sym_name", nameAttr);
1781 result.addAttribute(
"var_shape", varShapeAttr);
1782 result.addAttribute(
"type", elementTypeAttr);
1783 result.addAttribute(
"initial_value", initialValue);
1796 if (ShapedType::isStatic(dim1) && ShapedType::isStatic(dim2) && dim1 != dim2)
1800 return ShapedType::isDynamic(dim1) ? dim2 : dim1;
1806 for (
int i = 0, e = operands.size(); i != e; ++i) {
1808 if (!
shape.hasRank()) {
1813 outRank = std::max<int64_t>(outRank,
shape.getRank());
1816 outShape.resize(outRank, 1);
1818 for (
int i = 0, e = operands.size(); i != e; ++i) {
1820 auto rankDiff = outShape.size() -
shape.getRank();
1822 for (
size_t i = 0, e =
shape.getRank(); i < e; ++i) {
1823 auto dim1 = outShape[i + rankDiff];
1824 auto dim2 =
shape.getDimSize(i);
1826 const FailureOr<int64_t> maybeResolvedDim =
1828 if (failed(maybeResolvedDim))
1830 const int64_t resolvedDim = *maybeResolvedDim;
1831 outShape[i + rankDiff] = resolvedDim;
1838LogicalResult tosa::ArgMaxOp::inferReturnTypeComponents(
1839 MLIRContext *context, ::std::optional<Location> location,
1840 ArgMaxOp::Adaptor adaptor,
1843 IntegerAttr axis = adaptor.getProperties().axis;
1844 int32_t axisVal = axis.getValue().getSExtValue();
1846 if (!inputShape.hasRank()) {
1852 outShape.reserve(inputShape.getRank() - 1);
1853 for (
int i = 0, s = inputShape.getRank(); i < s; i++) {
1856 outShape.push_back(inputShape.getDimSize(i));
1863LogicalResult tosa::RFFT2dOp::inferReturnTypeComponents(
1864 MLIRContext *context, ::std::optional<Location> location,
1865 RFFT2dOp::Adaptor adaptor,
1867 ShapeAdaptor inputShape(adaptor.getInputReal().getType());
1869 if (!inputShape.hasRank())
1873 outputShape.resize(3, ShapedType::kDynamic);
1874 outputShape[0] = inputShape.getDimSize(0);
1875 outputShape[1] = inputShape.getDimSize(1);
1876 int64_t inWidth = inputShape.getDimSize(2);
1880 if (inWidth != ShapedType::kDynamic)
1881 outputShape[2] = inWidth / 2 + 1;
1890 const llvm::StringRef dimName) {
1891 const bool isPowerOfTwo = (dimSize & (dimSize - 1)) == 0 && dimSize > 0;
1894 << dimName <<
" to be a power of two, got " << dimSize;
1899LogicalResult tosa::RFFT2dOp::verify() {
1900 const auto outputTypes = getResultTypes();
1902 return emitOpError(
"expected output shapes to match, got ") << outputTypes;
1904 const auto inputType =
1905 llvm::dyn_cast<RankedTensorType>(getInputReal().
getType());
1909 const int64_t height = inputType.getDimSize(1);
1910 if (ShapedType::isStatic(height) &&
1914 const int64_t width = inputType.getDimSize(2);
1915 if (ShapedType::isStatic(width) &&
1919 const auto outputType = llvm::dyn_cast<RankedTensorType>(outputTypes[0]);
1925 outputType.getShape().drop_back())))
1926 return emitOpError(
"expected batch and height dimensions of input/output "
1927 "to match, got input=")
1928 << inputType <<
" output=" << outputType;
1931 const int64_t outputWidth = outputType.getDimSize(2);
1932 if (ShapedType::isStatic(width) && ShapedType::isStatic(outputWidth) &&
1933 (outputWidth != (width / 2) + 1))
1935 "expected output width to be equal to input_width / 2 + 1, got ")
1941LogicalResult tosa::FFT2dOp::inferReturnTypeComponents(
1942 MLIRContext *context, ::std::optional<Location> location,
1943 FFT2dOp::Adaptor adaptor,
1945 inferredReturnShapes.push_back(
1947 inferredReturnShapes.push_back(
1952LogicalResult tosa::FFT2dOp::verify() {
1953 const auto inputRealType =
1954 llvm::dyn_cast<RankedTensorType>(getInputReal().
getType());
1955 const auto inputImagType =
1956 llvm::dyn_cast<RankedTensorType>(getInputImag().
getType());
1957 if (!inputRealType || !inputImagType)
1960 const auto trySelectStaticDim = [](
const int64_t a,
const int64_t b) {
1961 return ShapedType::isDynamic(a) ? a :
b;
1964 const int64_t height = trySelectStaticDim(inputRealType.getDimSize(1),
1965 inputImagType.getDimSize(1));
1966 if (ShapedType::isStatic(height) &&
1970 const int64_t width = trySelectStaticDim(inputRealType.getDimSize(2),
1971 inputImagType.getDimSize(2));
1972 if (ShapedType::isStatic(width) &&
1979LogicalResult tosa::ConcatOp::inferReturnTypeComponents(
1980 MLIRContext *context, ::std::optional<Location> location,
1981 ConcatOp::Adaptor adaptor,
1984 const Properties &prop = adaptor.getProperties();
1985 int32_t axis = prop.axis.getValue().getSExtValue();
1987 bool hasRankedInput =
false;
1988 for (
auto operand : adaptor.getOperands()) {
1990 if (!operandShape.hasRank())
1994 if (!hasRankedInput)
1995 outputShape.resize(operandShape.getRank(), ShapedType::kDynamic);
1998 for (
int i = 0, s = operandShape.getRank(); i < s; i++) {
1999 if (i == axis || operandShape.isDynamicDim(i))
2001 if (outputShape[i] == ShapedType::kDynamic)
2002 outputShape[i] = operandShape.getDimSize(i);
2003 if (outputShape[i] != operandShape.getDimSize(i))
2005 "Cannot concat tensors with different sizes"
2006 " on the non-axis dimension ",
2010 hasRankedInput =
true;
2013 if (adaptor.getInput1().empty())
2017 llvm::cast<TensorType>(adaptor.getInput1().getType()[0]).getElementType();
2018 if (!hasRankedInput) {
2025 for (
auto operand : adaptor.getOperands()) {
2030 if (!operandShape.hasRank() || operandShape.isDynamicDim(axis)) {
2031 concatDimSize = ShapedType::kDynamic;
2035 concatDimSize += operandShape.getDimSize(axis);
2038 outputShape[axis] = concatDimSize;
2044LogicalResult tosa::ConcatOp::verify() {
2046 auto outType = getOutput().getType();
2050 if (inputList.empty())
2053 if (!llvm::all_of(inputList, [&](
auto input) {
2055 *
this, input.getType(), outType));
2060 const int32_t axis = getAxis();
2062 for (
const auto &input : inputList) {
2063 const Type inputType = input.getType();
2065 if (currShape.hasRank()) {
2066 firstRankedInputShape = currShape;
2068 if (axis < 0 || axis >= firstRankedInputShape.
getRank())
2069 return emitOpError(
"expect axis to be within range 0 < axis < "
2070 "rank(input1[firstRankedTensorIdx]), got ")
2076 const auto allOperandsHasRank = [](
const Value input) {
2079 if (llvm::all_of(inputList, allOperandsHasRank)) {
2082 for (
const auto &[
index, input] : llvm::enumerate(inputList.drop_front())) {
2084 const int64_t inputRank = inputShape.getRank();
2085 const size_t operandNum =
index + 1;
2088 if (inputRank != firstInputRank)
2090 "expect all operands to have the same rank, but got ")
2091 << firstInputRank <<
" vs " << inputRank <<
" on operands 0 and "
2095 for (
int i = 0; i < inputRank; i++) {
2096 const int64_t inputDim = inputShape.getDimSize(i);
2098 if (i == axis || firstRankedInputShape.
isDynamicDim(i) ||
2099 inputShape.isDynamicDim(i))
2101 if (inputDim != firstInputDim)
2102 return emitOpError(
"expect all operand shapes to have the same sizes "
2103 "on non-axis dimensions, but got ")
2104 << inputDim <<
" vs " << firstInputDim <<
" at index " << i
2105 <<
" on operands 0 and " << operandNum;
2110 if (outputShape.hasRank() && outputShape.getRank() != firstInputRank)
2111 return emitOpError(
"expect output rank to match inputs rank, got ")
2112 << outputShape.getRank() <<
" vs " << firstInputRank;
2116 for (
const auto &input : inputList) {
2118 if (inputShape.isDynamicDim(axis)) {
2123 axisSum += inputShape.getDimSize(axis);
2126 if (axisSum >= 0 && outputShape.hasRank() &&
2127 !outputShape.isDynamicDim(axis) &&
2128 axisSum != outputShape.getDimSize(axis))
2129 return emitOpError(
"requires sum of axis dimensions of input1 "
2130 "equal to output axis dimension, got ")
2131 << axisSum <<
" and " << outputShape.getDimSize(axis);
2137LogicalResult tosa::EqualOp::inferReturnTypeComponents(
2138 MLIRContext *context, ::std::optional<Location> location,
2142 auto elementType = IntegerType::get(context, 1);
2155 if (l.size() != r.size() || l.size() != 1)
2160LogicalResult tosa::MatMulOp::inferReturnTypeComponents(
2161 MLIRContext *context, ::std::optional<Location> location,
2162 MatMulOp::Adaptor adaptor,
2169 outShape.resize(3, ShapedType::kDynamic);
2171 if (lhsShape.hasRank()) {
2172 outShape[0] = lhsShape.getDimSize(0);
2173 outShape[1] = lhsShape.getDimSize(1);
2176 if (rhsShape.hasRank()) {
2177 outShape[0] = outShape[0] == ShapedType::kDynamic ? rhsShape.getDimSize(0)
2179 outShape[2] = rhsShape.getDimSize(2);
2186template <
typename T>
2188 Type bElementType) {
2189 const auto aQuantizedEType =
2190 llvm::dyn_cast<quant::UniformQuantizedType>(aElementType);
2191 const auto bQuantizedEType =
2192 llvm::dyn_cast<quant::UniformQuantizedType>(bElementType);
2194 if (aQuantizedEType || bQuantizedEType) {
2195 if (!aQuantizedEType || !bQuantizedEType) {
2196 return op.emitOpError(
"expect operands to be both quantized or both not "
2198 << aElementType <<
" and " << bElementType;
2201 auto aQuantWidth = aQuantizedEType.getStorageTypeIntegralWidth();
2202 auto bQuantWidth = bQuantizedEType.getStorageTypeIntegralWidth();
2203 if (aQuantWidth != bQuantWidth) {
2204 return op.emitOpError(
"expect quantized operands to have same widths, "
2206 << aQuantWidth <<
" and " << bQuantWidth;
2213template <
typename T>
2215 StringRef inputName,
2220 Type expectedElementType = inputStorageElementType;
2222 if (isa<BlockScaledType>(inputElementType))
2223 expectedElementType = Float32Type::get(op.getContext());
2225 if (expectedElementType == zpElementType)
2229 diag << inputName <<
" and " << zpName;
2230 if (isa<BlockScaledType>(inputElementType))
2231 diag <<
" have compatible element types, got " << inputElementType
2232 <<
" and " << zpElementType;
2234 diag <<
" have the same element type, got " << inputStorageElementType
2235 <<
" and " << zpElementType;
2239LogicalResult MatMulOp::verify() {
2242 const Type aElementType = aShape.getElementType();
2243 const Type bElementType = bShape.getElementType();
2253 FailureOr<int64_t> maybeAZp = getAZeroPoint();
2254 if (succeeded(maybeAZp) && verifyAZeroPoint(*maybeAZp).failed())
2257 FailureOr<int64_t> maybeBZp = getBZeroPoint();
2258 if (succeeded(maybeBZp) && verifyBZeroPoint(*maybeBZp).failed())
2262 int64_t N = ShapedType::kDynamic;
2263 int64_t H = ShapedType::kDynamic;
2267 if (aShape.hasRank()) {
2268 N = aShape.getDimSize(0);
2269 H = aShape.getDimSize(1);
2270 C = aShape.getDimSize(2);
2273 if (bShape.hasRank()) {
2279 W = bShape.getDimSize(2);
2283 const auto outputType = cast<ShapedType>(getResult().
getType());
2284 if (outputType.hasRank() &&
2286 expectedOutputShape)))
2292LogicalResult tosa::MatMulTOp::inferReturnTypeComponents(
2293 MLIRContext *context, ::std::optional<Location> location,
2294 MatMulTOp::Adaptor adaptor,
2301 if (lhsShape.hasRank()) {
2302 outShape[0] = lhsShape.getDimSize(0);
2303 outShape[1] = lhsShape.getDimSize(1);
2306 if (rhsShape.hasRank()) {
2307 const int64_t bBatchSize = rhsShape.getDimSize(0);
2308 if (bBatchSize != 1 && ShapedType::isDynamic(outShape[0]))
2309 outShape[0] = bBatchSize;
2310 outShape[2] = rhsShape.getDimSize(1);
2317LogicalResult MatMulTOp::verify() {
2320 const Type aElementType = aShape.getElementType();
2321 const Type bElementType = bShape.getElementType();
2331 FailureOr<int64_t> maybeAZp = getAZeroPoint();
2332 if (succeeded(maybeAZp) && verifyAZeroPoint(*maybeAZp).failed())
2335 FailureOr<int64_t> maybeBZp = getBZeroPoint();
2336 if (succeeded(maybeBZp) && verifyBZeroPoint(*maybeBZp).failed())
2340 int64_t N = ShapedType::kDynamic;
2341 int64_t D = ShapedType::kDynamic;
2342 int64_t H = ShapedType::kDynamic;
2346 if (aShape.hasRank()) {
2347 N = aShape.getDimSize(0);
2348 H = aShape.getDimSize(1);
2349 C = aShape.getDimSize(2);
2352 if (bShape.hasRank()) {
2353 D = bShape.getDimSize(0);
2354 W = bShape.getDimSize(1);
2361 if (ShapedType::isStatic(N) && ShapedType::isStatic(D) && N != D && D != 1)
2362 return emitOpError(
"expect B matrix batch size to be broadcast compatible "
2364 << D <<
" vs N=" << N;
2366 if (ShapedType::isDynamic(N) && ShapedType::isStatic(D) && D != 1)
2370 const auto outputType = cast<ShapedType>(getResult().
getType());
2371 if (outputType.hasRank() &&
2373 expectedOutputShape)))
2379LogicalResult tosa::MatmulTBlockScaledOp::inferReturnTypeComponents(
2380 MLIRContext *context, ::std::optional<Location> location,
2381 MatmulTBlockScaledOp::Adaptor adaptor,
2385 const auto aDataShape = cast<ShapedType>(adaptor.getAData().getType());
2386 if (aDataShape.hasRank()) {
2387 outShape[0] = aDataShape.getDimSize(0);
2388 outShape[1] = aDataShape.getDimSize(1);
2391 const auto aScaleShape = cast<ShapedType>(adaptor.getAScale().getType());
2392 if (aScaleShape.hasRank()) {
2393 outShape[0] = ShapedType::isDynamic(outShape[0]) ? aScaleShape.getDimSize(0)
2395 outShape[1] = ShapedType::isDynamic(outShape[1]) ? aScaleShape.getDimSize(1)
2400 const auto bDataShape = cast<ShapedType>(adaptor.getBData().getType());
2401 if (bDataShape.hasRank()) {
2402 const int64_t bDataBatchSize = bDataShape.getDimSize(0);
2403 if (bDataBatchSize != 1)
2405 ShapedType::isDynamic(outShape[0]) ? bDataBatchSize : outShape[0];
2406 outShape[2] = bDataShape.getDimSize(1);
2409 const auto bScaleShape = cast<ShapedType>(adaptor.getBScale().getType());
2410 if (bScaleShape.hasRank()) {
2411 const int64_t bScaleBatchSize = bScaleShape.getDimSize(0);
2412 if (bScaleBatchSize != 1)
2414 ShapedType::isDynamic(outShape[0]) ? bScaleBatchSize : outShape[0];
2415 outShape[2] = ShapedType::isDynamic(outShape[2]) ? bScaleShape.getDimSize(1)
2423LogicalResult MatmulTBlockScaledOp::verify() {
2425 const Type aDataType = getAData().getType();
2426 const Type bDataType = getBData().getType();
2432 int64_t N = ShapedType::kDynamic;
2433 int64_t D = ShapedType::kDynamic;
2434 int64_t H = ShapedType::kDynamic;
2437 int64_t multiplesOfC = ShapedType::kDynamic;
2449 "a_scale",
"batch")) ||
2451 "a_scale",
"height")))
2459 "b_data",
"batch")) ||
2461 "b_data",
"channels")))
2469 "b_scale",
"batch")) ||
2471 "b_scale",
"width")) ||
2479 if (ShapedType::isStatic(N) && ShapedType::isStatic(D) && N != D && D != 1)
2480 return emitOpError(
"expect B matrix batch size to be broadcast compatible "
2482 << D <<
" vs N=" << N;
2485 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
2486 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
2487 return emitOpError(
"expect block size to be 32, got ") << blockSize;
2488 if (ShapedType::isStatic(C) && C % blockSize != 0)
2489 return emitOpError(
"expect C to be a multiple of block size, got C=")
2490 <<
C <<
", block_size=" << blockSize;
2493 if (ShapedType::isStatic(C) && ShapedType::isStatic(multiplesOfC) &&
2494 multiplesOfC != C / blockSize)
2496 "expect scale operands dimension 2 to equal C/block_size (")
2497 <<
C <<
"/" << blockSize <<
")" <<
", got " << multiplesOfC;
2500 N = ShapedType::isDynamic(N) ? D : N;
2502 const auto outputType = cast<ShapedType>(getResult().
getType());
2503 if (outputType.hasRank() &&
2508 opError <<
" to be compatible with expected output shape ";
2516LogicalResult tosa::PadOp::inferReturnTypeComponents(
2517 MLIRContext *context, ::std::optional<Location> location,
2518 PadOp::Adaptor adaptor,
2520 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2522 cast<tosa::shapeType>(adaptor.getPadding().getType()).getRank();
2527 if (!inputShape.hasRank()) {
2528 outputShape.resize(paddingRank / 2, ShapedType::kDynamic);
2537 outputShape.resize(inputShape.getRank(), ShapedType::kDynamic);
2542 outputShape.reserve(inputShape.getRank());
2543 for (
int i = 0, s = inputShape.getRank(); i < s; i++) {
2544 if (inputShape.isDynamicDim(i)) {
2545 outputShape.push_back(ShapedType::kDynamic);
2548 auto padFront = paddingValues[i * 2];
2549 auto padBack = paddingValues[i * 2 + 1];
2550 if (padFront < 0 || padBack < 0) {
2552 outputShape.push_back(ShapedType::kDynamic);
2556 outputShape.push_back(inputShape.getDimSize(i) + padFront + padBack);
2563LogicalResult tosa::PadOp::verify() {
2570 if (
auto padConst = getPadConst()) {
2578 RankedTensorType inputType =
2579 llvm::dyn_cast<RankedTensorType>(getInput1().
getType());
2580 RankedTensorType outputType =
2581 llvm::dyn_cast<RankedTensorType>(getOutput().
getType());
2582 if (!inputType || !outputType)
2589 auto inputRank = inputType.getRank();
2594 auto paddingValues = paddingAttr.getValues<APInt>();
2595 if (paddingValues.size() !=
static_cast<size_t>(inputRank * 2))
2596 return emitOpError() <<
"padding tensor must have " << inputRank
2597 <<
" * 2 = " << inputRank * 2 <<
" elements, but got "
2598 << paddingValues.size();
2600 auto inputShape = inputType.getShape();
2601 auto outputShape = outputType.getShape();
2603 for (
int64_t i = 0; i < inputRank; ++i) {
2604 int64_t padStart = paddingValues[i * 2].getSExtValue();
2605 int64_t padEnd = paddingValues[i * 2 + 1].getSExtValue();
2607 if ((padStart < 0 && padStart != -1) || (padEnd < 0 && padEnd != -1)) {
2609 <<
"invalid padding values at dimension " << i
2610 <<
": values must be non-negative or -1 for dynamic padding, got ["
2611 << padStart <<
", " << padEnd <<
"]";
2615 if (inputShape[i] == ShapedType::kDynamic ||
2616 outputShape[i] == ShapedType::kDynamic)
2619 if (outputShape[i] != inputShape[i] + padStart + padEnd) {
2620 return emitOpError() <<
"mismatch in output shape at dimension " << i
2621 <<
": expected " << inputShape[i] <<
" + "
2622 << padStart <<
" + " << padEnd <<
" = "
2623 << (inputShape[i] + padStart + padEnd)
2624 <<
", but got " << outputShape[i];
2631LogicalResult tosa::SliceOp::inferReturnTypeComponents(
2632 MLIRContext *context, ::std::optional<Location> location,
2633 SliceOp::Adaptor adaptor,
2642 auto rank = cast<tosa::shapeType>(adaptor.getSize().getType()).getRank();
2650 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2653 if (inputShape.hasRank()) {
2654 for (
size_t i = 0; i < size.size(); i++) {
2655 if (size[i] != 0 && size[i] >= -1 && start[i] >= 0 &&
2656 (ShapedType::isDynamic(inputShape.getDimSize(i)) ||
2657 start[i] < inputShape.getDimSize(i))) {
2659 if (ShapedType::isDynamic(inputShape.getDimSize(i))) {
2662 outputShape[i] = size[i];
2666 if (size[i] == -1) {
2667 outputShape[i] = inputShape.getDimSize(i) - start[i];
2668 }
else if (start[i] + size[i] <= inputShape.getDimSize(i)) {
2670 outputShape[i] = size[i];
2682LogicalResult tosa::SliceOp::verify() {
2683 const Value input = getInput1();
2684 const Value output = getOutput();
2690 const Value start = getStart();
2691 const Value size = getSize();
2695 if (inputShape.hasRank()) {
2696 const auto inputRank = inputShape.getRank();
2697 if (outputShape.hasRank() && inputRank != outputShape.getRank())
2699 "expect input1 and output to have the same ranks, got ")
2700 << inputRank <<
" and " << outputShape.getRank();
2702 const auto startShapeRank =
2703 llvm::cast<tosa::shapeType>(start.
getType()).getRank();
2704 if (inputRank != startShapeRank)
2705 return emitOpError(
"length of start is not equal to rank of input shape");
2707 const auto sizeShapeRank =
2708 llvm::cast<tosa::shapeType>(size.
getType()).getRank();
2709 if (inputRank != sizeShapeRank)
2710 return emitOpError(
"length of size is not equal to rank of input shape");
2715 if (startValues.size()) {
2716 if (llvm::any_of(startValues, [](
const int64_t v) {
2719 return emitOpError(
"start values must be non-negative, got [")
2720 << startValues <<
"]";
2727 if (llvm::any_of(sizeValues, [](
const int64_t v) {
2730 return emitOpError(
"size values must be > 0, got [") << sizeValues <<
"]";
2731 if (outputShape.hasRank()) {
2733 outputShape.getDims(outputDims);
2734 const bool hasNoInferableDims = llvm::all_of(
2736 if (hasNoInferableDims &&
2738 return emitOpError(
"expected output shape to match size values, got ")
2739 << output.
getType() <<
" vs [" << sizeValues <<
"]";
2742 if (inputShape.hasRank() && startValues.size()) {
2744 inputShape.getDims(inputDims);
2745 for (
const auto &[
index, vals] :
2746 llvm::enumerate(llvm::zip_equal(startValues, sizeValues, inputDims))) {
2747 const auto &[start, size, inputDim] = vals;
2749 ShapedType::isDynamic(inputDim))
2751 if (start + size > inputDim)
2752 return emitOpError(
"start + size must be less than or equal to input "
2753 "dimension size, got start=")
2754 << start <<
", size=" << size
2755 <<
" vs input dim size=" << inputDim <<
" at dimension "
2763LogicalResult tosa::MulOp::inferReturnTypeComponents(
2764 MLIRContext *context, ::std::optional<Location> location,
2779LogicalResult tosa::MulOp::verify() {
2780 const Value output = getOutput();
2785 if (
auto resIntType = dyn_cast<IntegerType>(resElemType)) {
2786 IntegerType lhsIntType =
2788 IntegerType rhsIntType =
2790 if (!lhsIntType || !rhsIntType || lhsIntType != rhsIntType)
2791 return emitOpError(
"requires the same element type for all operands");
2796 if (lhsIntType.getWidth() > resIntType.getWidth())
2797 return emitOpError(
"invalid data type size for operands or result");
2802 for (
int i = 0; i < 2; ++i) {
2805 "requires the same element type for all operands and results");
2809 ElementsAttr shiftElem;
2811 int32_t shift = shiftElem.getValues<IntegerAttr>()[0].getInt();
2813 return emitOpError() <<
"require shift to be 0 for float type";
2821 TypeRange operandTypes = getOperandTypes();
2822 ShapedType aType = cast<ShapedType>(operandTypes[0]);
2823 ShapedType bType = cast<ShapedType>(operandTypes[1]);
2825 const bool aHasRank = aType.hasRank();
2826 const bool bHasRank = bType.hasRank();
2828 bool hasExpectedOutputShape =
false;
2831 if (aHasRank && bHasRank) {
2832 const int64_t aRank = aType.getRank();
2833 const int64_t bRank = bType.getRank();
2835 return emitOpError(
"a and b operands don't have matching ranks, got ")
2836 << aRank <<
" and " << bRank;
2840 aType.getShape(), bType.getShape(), expectedOutputShape))
2841 return emitOpError(
"a and b operands don't have broadcast-compatible "
2843 << aType <<
" and " << bType;
2844 hasExpectedOutputShape =
true;
2847 ShapedType resultType = cast<ShapedType>(output.
getType());
2848 if (!resultType.hasRank())
2851 const int64_t resultRank = resultType.getRank();
2852 if (aHasRank && resultRank != aType.getRank())
2853 return emitOpError(
"result type has different rank than a, got ")
2854 << resultRank <<
" vs " << aType.getRank();
2855 if (bHasRank && resultRank != bType.getRank())
2856 return emitOpError(
"result type has different rank than b, got ")
2857 << resultRank <<
" vs " << bType.getRank();
2859 if (hasExpectedOutputShape &&
2861 expectedOutputShape)))
2867LogicalResult tosa::TableOp::inferReturnTypeComponents(
2868 MLIRContext *context, ::std::optional<Location> location,
2869 TableOp::Adaptor adaptor,
2871 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2873 if (!inputShape.hasRank()) {
2878 inferredReturnShapes.resize(1);
2879 inputShape.getDims(inferredReturnShapes[0]);
2883LogicalResult tosa::TableOp::verify() {
2884 const TensorType inputType = getInput1().getType();
2885 const TensorType outputType = getOutput().getType();
2894 auto inputDims = inputType.
getShape();
2895 auto outputDims = outputType.
getShape();
2896 for (
auto it : llvm::enumerate(llvm::zip(inputDims, outputDims))) {
2898 auto [inputDim, outputDim] = it.value();
2899 if (ShapedType::isStatic(outputDim) && outputDim != inputDim) {
2900 return emitOpError() <<
"dim(result, " << dim <<
") = " << outputDim
2901 <<
" doesn't match dim(input, " << dim
2902 <<
") = " << inputDim;
2915 llvm::map_to_vector(multiplesAttr.getValues<APInt>(),
2916 [](
const APInt &val) { return val.getSExtValue(); });
2920LogicalResult tosa::TileOp::inferReturnTypeComponents(
2921 MLIRContext *context, ::std::optional<Location> location,
2922 TileOp::Adaptor adaptor,
2929 cast<tosa::shapeType>(adaptor.getMultiples().getType()).getRank();
2936 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2938 if (!inputShape.hasRank()) {
2939 outputShape.resize(multiples.size(), ShapedType::kDynamic);
2940 inferredReturnShapes.push_back(
2944 if (
static_cast<size_t>(inputShape.getRank()) != multiples.size())
2948 outputShape.reserve(multiples.size());
2949 for (
int i = 0, s = inputShape.getRank(); i < s; i++) {
2950 if (multiples[i] == ShapedType::kDynamic) {
2951 outputShape.push_back(ShapedType::kDynamic);
2953 int64_t dim = inputShape.getDimSize(i);
2954 if (dim != ShapedType::kDynamic)
2955 dim *= multiples[i];
2956 outputShape.push_back(dim);
2964LogicalResult tosa::TileOp::verify() {
2970 ShapedType inputType = llvm::cast<ShapedType>(getInput1().
getType());
2971 ShapedType outputType = llvm::cast<ShapedType>(
getType());
2973 shapeType multiplesType =
2974 llvm::cast<tosa::shapeType>(getMultiples().
getType());
2976 auto multiplesRank = multiplesType.getRank();
2978 if (inputType.hasRank()) {
2979 if (inputType.getRank() != multiplesRank)
2980 return emitOpError(
"expect 'multiples' to have rank ")
2981 << inputType.getRank() <<
" but got " << multiplesRank <<
".";
2982 if (outputType.hasRank() &&
2986 }
else if (outputType.hasRank() && outputType.getRank() != multiplesRank)
2987 return emitOpError(
"expect 'multiples' array to have length ")
2988 << outputType.getRank() <<
" but got " << multiplesRank <<
".";
2991 if (getConstantMultiples(multiples).succeeded() &&
2992 llvm::any_of(multiples, [](
int64_t v) {
return v <= 0 && v != -1; }))
2994 "expect element of 'multiples' to be positive integer or -1.");
3000 if (l.size() != r.size() || l.size() != 1)
3005LogicalResult tosa::ReshapeOp::inferReturnTypeComponents(
3006 MLIRContext *context, ::std::optional<Location> location,
3007 ReshapeOp::Adaptor adaptor,
3009 ShapeAdaptor inputShape(adaptor.getInput1().getType());
3014 auto rank = cast<tosa::shapeType>(adaptor.getShape().getType()).getRank();
3023 if (!inputShape.hasRank() || !inputShape.hasStaticShape()) {
3024 inferredReturnShapes.push_back(
3032 int64_t numElements = inputShape.getNumElements();
3034 for (
auto val : newShapeValue) {
3035 if (ShapedType::isStatic(val)) {
3041 for (
auto &val : newShapeValue) {
3042 if (ShapedType::isDynamic(val))
3043 val = numElements / staticMul;
3046 inferredReturnShapes.push_back(
3051llvm::LogicalResult tosa::ReshapeOp::verify() {
3057 TensorType inputType = getInput1().getType();
3062 return mlir::success();
3066 if (missingDims > 1)
3067 return emitOpError() <<
"expected at most one target dimension to be "
3070 const auto outputType = dyn_cast<RankedTensorType>(
getType());
3074 if ((
int64_t)shapeValues.size() != outputType.getRank())
3075 return emitOpError() <<
"new shape does not match result rank";
3077 for (
auto [newShapeDim, outputShapeDim] :
3078 zip(shapeValues, outputType.getShape())) {
3080 newShapeDim != ShapedType::kDynamic &&
3081 outputShapeDim != ShapedType::kDynamic && newShapeDim != outputShapeDim)
3082 return emitOpError() <<
"new shape is inconsistent with result shape";
3085 return emitOpError() <<
"new shape has invalid tensor dimension size "
3089 if (inputType.hasStaticShape()) {
3090 int64_t inputElementsNum = inputType.getNumElements();
3091 if (outputType.hasStaticShape()) {
3092 int64_t outputElementsNum = outputType.getNumElements();
3093 if (inputElementsNum != outputElementsNum) {
3094 return emitOpError() <<
"cannot reshape " << inputElementsNum
3095 <<
" elements into " << outputElementsNum;
3101 return (dim > 0) ?
acc * dim :
acc;
3103 bool isStaticNewShape =
3104 llvm::all_of(shapeValues, [](
int64_t s) {
return s > 0; });
3105 if ((isStaticNewShape && inputElementsNum != newShapeElementsNum) ||
3106 (!isStaticNewShape && newShapeElementsNum > inputElementsNum)) {
3107 return emitOpError() <<
"cannot reshape " << inputElementsNum
3108 <<
" elements into " << newShapeElementsNum;
3112 return mlir::success();
3115bool tosa::ReshapeBlockScaledOp::isCompatibleReturnTypes(
TypeRange l,
3117 if (l.size() != r.size() || l.size() < 1 || l.size() > 2)
3125LogicalResult tosa::ReshapeBlockScaledOp::inferReturnTypeComponents(
3126 MLIRContext *context, ::std::optional<Location> location,
3127 ReshapeBlockScaledOp::Adaptor adaptor,
3130 const auto numInputs = adaptor.getInput().size();
3131 ShapeAdaptor inputShape(adaptor.getInput()[0].getType());
3134 const auto newShape = adaptor.getNewValueShape();
3136 auto rank = cast<tosa::shapeType>(newShape.getType()).getRank();
3145 const uint32_t blockSize =
3146 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
3149 if (numInputs == 2) {
3150 newScaleShapeValue.assign(newShapeValue.begin(), newShapeValue.end());
3151 if (ShapedType::isStatic(newScaleShapeValue.back()))
3152 newScaleShapeValue.back() /= blockSize;
3155 inferredReturnShapes.push_back(
3157 if (numInputs == 2) {
3159 for (
size_t idx = 0; idx < newShapeValue.size(); idx++) {
3160 if (ShapedType::isDynamic(newScaleShapeValue[idx])) {
3161 newScaleShapeValue[idx] = newShapeValue[idx];
3162 if (idx == (newShapeValue.size() - 1))
3163 newScaleShapeValue[idx] /= blockSize;
3174llvm::LogicalResult tosa::ReshapeBlockScaledOp::verify() {
3178 if (inputList.size() == 0)
3179 return emitOpError(
"requires at least one input");
3181 if (inputList.size() > 2)
3182 return emitOpError(
"requires at most two inputs");
3184 if (inputList.size() != outputList.size())
3185 return emitOpError(
"requires number of results to match inputs");
3193 const auto inputType = llvm::cast<ShapedType>(inputList[0].
getType());
3194 if (!inputType.hasRank())
3196 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
3198 if (inputList.size() == 2) {
3199 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
3200 return emitOpError(
"expect block size to be 32, got ") << blockSize;
3201 if (llvm::any_of(inputList, [](
Value v) {
3202 const auto input = cast<ShapedType>(v.
getType());
3203 return input.hasRank() && input.getRank() == 0;
3206 "requires all input shapes have a rank greater than 0");
3207 if (llvm::any_of(outputList, [](
Value v) {
3208 const auto output = cast<ShapedType>(v.
getType());
3209 return output.hasRank() && output.getRank() == 0;
3212 "requires all result shapes have a rank greater than 0");
3220 const auto inputScaleType = llvm::cast<ShapedType>(inputList[1].
getType());
3221 if (inputScaleType.hasRank()) {
3222 if (inputType.getRank() != inputScaleType.getRank())
3223 return emitOpError(
"input shapes do not have same rank");
3226 for (
auto dimIdx = 0; dimIdx < inputType.getRank() - 1; dimIdx++) {
3227 const int64_t inputValueDim = inputType.getDimSize(dimIdx);
3228 const int64_t inputScaleDim = inputScaleType.getShape()[dimIdx];
3229 if (ShapedType::isStatic(inputValueDim) &&
3230 ShapedType::isStatic(inputScaleDim) &&
3231 inputValueDim != inputScaleDim)
3232 return emitOpError(
"input shapes for data and scale do not match on "
3239 inputType.getDimSize(inputType.getRank() - 1);
3240 if (ShapedType::isStatic(lastValueDim)) {
3241 if (lastValueDim % blockSize != 0)
3242 return emitOpError(
"expect last dimension of input_data (")
3243 << lastValueDim <<
") to be divisible by block_size ("
3244 << blockSize <<
")";
3247 inputScaleType.getDimSize(inputScaleType.getRank() - 1);
3249 if (ShapedType::isStatic(lastScaleDim) &&
3250 lastScaleDim != lastValueDim / blockSize)
3251 return emitOpError(
"expect last dimension of scale_data (")
3252 << lastScaleDim <<
") to be " << lastValueDim <<
"/"
3257 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_1))
3258 return emitOpError(
"expect block size to be 1, got ") << blockSize;
3266 return mlir::success();
3269 if (inputList.size() == 2) {
3270 if (
static_cast<int64_t>(shapeValues.size()) == 0)
3271 return emitOpError(
"requires new shape to have a rank greater than 0");
3273 const int64_t lastShapeDim = shapeValues.back();
3274 if (ShapedType::isStatic(lastShapeDim) && lastShapeDim % blockSize != 0)
3275 return emitOpError(
"expect last dimension of new shape (")
3276 << lastShapeDim <<
") to be divisible by block_size (" << blockSize
3280 const auto outputType = llvm::cast<ShapedType>(outputList[0].
getType());
3281 if (!outputType.hasRank())
3284 if (
static_cast<int64_t>(shapeValues.size()) != outputType.getRank())
3285 return emitOpError() <<
"result does not match new shape rank";
3287 for (
auto [newShapeDim, outputShapeDim] :
3288 zip(shapeValues, outputType.getShape())) {
3289 if (ShapedType::isStatic(newShapeDim) &&
3290 ShapedType::isStatic(outputShapeDim) && newShapeDim != outputShapeDim)
3291 return emitOpError() <<
"result shape is inconsistent with new shape";
3294 if (outputList.size() == 2) {
3298 scaleShapeValues.back() /= blockSize;
3300 const auto outputScaleType =
3301 llvm::cast<ShapedType>(outputList[1].
getType());
3302 if (outputScaleType.hasRank()) {
3303 if ((
int64_t)scaleShapeValues.size() != outputScaleType.getRank())
3304 return emitOpError() <<
"result scale does not match new shape rank";
3306 for (
auto [newScaleShapeDim, outputScaleShapeDim] :
3307 zip(scaleShapeValues, outputScaleType.getShape())) {
3308 if (ShapedType::isStatic(newScaleShapeDim) &&
3309 ShapedType::isStatic(outputScaleShapeDim) &&
3310 newScaleShapeDim != outputScaleShapeDim)
3312 <<
"result scale shape is inconsistent with new shape";
3317 if (inputType.hasStaticShape()) {
3318 int64_t inputElementsNum = inputType.getNumElements();
3319 if (outputType.hasStaticShape()) {
3320 int64_t outputElementsNum = outputType.getNumElements();
3321 if (inputElementsNum != outputElementsNum) {
3322 return emitOpError() <<
"cannot reshape " << inputElementsNum
3323 <<
" elements into " << outputElementsNum;
3329 return (dim > 0) ?
acc * dim :
acc;
3331 bool isStaticNewShape =
3332 llvm::all_of(shapeValues, [](
int64_t s) {
return s > 0; });
3333 if ((isStaticNewShape && inputElementsNum != newShapeElementsNum) ||
3334 (!isStaticNewShape && newShapeElementsNum > inputElementsNum)) {
3335 return emitOpError() <<
"cannot reshape " << inputElementsNum
3336 <<
" elements into " << newShapeElementsNum;
3340 return mlir::success();
3347 ElementsAttr zpAttr;
3352 Type zpElemType = zpAttr.getElementType();
3354 if (llvm::isa<FloatType>(zpElemType)) {
3355 if (zpAttr.getValues<APFloat>()[0].isZero()) {
3362 if (llvm::isa<IntegerType>(zpElemType)) {
3364 return zpAttr.getValues<APInt>()[0].getSExtValue();
3365 return zpAttr.getValues<APInt>()[0].getZExtValue();
3372template <
typename T>
3374 const std::string &operand) {
3377 if (!zpElemType.
isInteger(8) && zp != 0) {
3379 std::string lower = operand;
3380 llvm::transform(lower, lower.begin(), ::tolower);
3381 return op.emitOpError()
3382 << lower <<
" zero point must be zero for non-int8 integer types";
3390 const std::string &operand) {
3391 bool isInputZp = (operand ==
"Input");
3393 bool tensorUnsigned =
3394 isInputZp ? op.getInputUnsigned() : op.getOutputUnsigned();
3395 StringRef tensorName = isInputZp ?
"input" :
"output";
3401 !(zpElemType.
isInteger(16) && tensorUnsigned)) {
3402 return op.emitOpError()
3403 <<
"expect " << tensorName <<
"_zp of 0, got " << zp;
3405 if (zpElemType.
isInteger(16) && tensorUnsigned && zp != 32768) {
3406 return op.emitOpError() <<
"expect " << tensorName
3407 <<
"_zp of 0 or 32768 for unsigned int16 "
3408 << tensorName <<
", got " << zp;
3415#define ZERO_POINT_HELPER(OP, OPERAND_NAME, SIGN_EXTEND) \
3416 FailureOr<int64_t> tosa::OP::get##OPERAND_NAME##ZeroPoint() { \
3417 return getZeroPoint(get##OPERAND_NAME##Zp(), SIGN_EXTEND); \
3419 LogicalResult tosa::OP::verify##OPERAND_NAME##ZeroPoint(int64_t zp) { \
3420 return verifyZeroPoint(*this, get##OPERAND_NAME##Zp(), zp, #OPERAND_NAME); \
3443#undef ZERO_POINT_HELPER
3445LogicalResult tosa::TransposeOp::inferReturnTypeComponents(
3446 MLIRContext *context, ::std::optional<Location> location,
3447 TransposeOp::Adaptor adaptor,
3449 ShapeAdaptor inputShape(adaptor.getInput1().getType());
3458 const auto inputRank = inputShape.
getRank();
3462 if (adaptor.getPerms().size() !=
static_cast<size_t>(inputRank)) {
3468 if (inputRank == 0) {
3474 bool allTheSame =
true;
3475 for (
int i = 1, s = inputRank; i < s; i++) {
3485 outputShape.resize(inputRank, inputShape.
getDimSize(0));
3490 outputShape.resize(inputRank, ShapedType::kDynamic);
3493 if (llvm::any_of(adaptor.getPerms(),
3494 [inputRank](
const auto i) { return i >= inputRank; }))
3497 outputShape.reserve(inputRank);
3498 for (
int i = 0, s = inputRank; i < s; i++) {
3499 outputShape[i] = inputShape.
getDimSize(adaptor.getPerms()[i]);
3506LogicalResult tosa::TransposeOp::verify() {
3518 if (inputShape.hasRank() &&
3519 constantPerms.size() !=
static_cast<size_t>(inputShape.getRank()))
3520 return emitOpError() <<
"expected perms attribute to have size "
3521 << inputShape.getRank()
3522 <<
" (input rank) but got size "
3523 << constantPerms.size();
3525 if (inputShape.hasRank() && outputShape.hasRank() &&
3526 inputShape.getRank() != outputShape.getRank())
3528 <<
"expected input tensor rank to equal result tensor rank";
3530 if (outputShape.hasRank() &&
3531 constantPerms.size() !=
static_cast<size_t>(outputShape.getRank()))
3532 return emitOpError() <<
"expected perms attribute to have size "
3533 << outputShape.getRank()
3534 <<
" (output rank) but got size "
3535 << constantPerms.size();
3537 if (!llvm::all_of(constantPerms,
3538 [&constantPerms](int32_t s) {
3540 static_cast<size_t>(s) < constantPerms.size();
3543 constantPerms, [](int32_t v) ->
int64_t {
return v; })))
3544 return emitOpError() <<
"expected valid permutation indices";
3547 if (inputShape.hasStaticShape() && outputShape.hasStaticShape() &&
3548 inputShape.getNumElements() != outputShape.getNumElements())
3549 return emitOpError() <<
"expected input1 and output to have same numbers "
3551 << inputShape.getNumElements() <<
" and "
3552 << outputShape.getNumElements();
3556 if (inputShape.hasRank() && outputShape.hasRank()) {
3557 for (
auto i = 0; i < outputShape.getRank(); i++) {
3558 if (inputShape.isDynamicDim(constantPerms[i]) ||
3559 outputShape.isDynamicDim(i))
3562 if (inputShape.getDimSize(constantPerms[i]) != outputShape.getDimSize(i))
3564 <<
"expected output tensor dim " << i <<
" to match "
3565 <<
"input dim " << constantPerms[i] <<
" with value of "
3566 << inputShape.getDimSize(constantPerms[i]);
3573LogicalResult TransposeOp::reifyResultShapes(
3576 const llvm::ArrayRef<int32_t> transposePerms = getPerms();
3578 Value input = getInput1();
3579 auto inputType = cast<TensorType>(input.
getType());
3581 SmallVector<OpFoldResult> returnedDims(inputType.getRank());
3582 for (
auto dim : transposePerms) {
3583 int32_t dimInInput = transposePerms[dim];
3584 if (inputType.isDynamicDim(dimInInput))
3586 tensor::DimOp::create(builder, getLoc(), input, dimInInput)
3590 builder.
getIndexAttr(inputType.getDimSize(dimInInput));
3593 reifiedReturnShapes.emplace_back(std::move(returnedDims));
3597LogicalResult tosa::GatherOp::inferReturnTypeComponents(
3598 MLIRContext *context, ::std::optional<Location> location,
3599 GatherOp::Adaptor adaptor,
3600 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3601 llvm::SmallVector<int64_t> outputShape;
3602 outputShape.resize(3, ShapedType::kDynamic);
3604 ShapeAdaptor valuesShape(adaptor.getValues().getType());
3605 if (valuesShape.hasRank()) {
3606 outputShape[0] = valuesShape.getDimSize(0);
3607 outputShape[2] = valuesShape.getDimSize(2);
3610 ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3611 if (indicesShape.hasRank()) {
3612 if (outputShape[0] == ShapedType::kDynamic)
3613 outputShape[0] = indicesShape.getDimSize(0);
3614 if (outputShape[1] == ShapedType::kDynamic)
3615 outputShape[1] = indicesShape.getDimSize(1);
3618 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3622LogicalResult tosa::RowGatherOp::inferReturnTypeComponents(
3623 MLIRContext *context, ::std::optional<Location> location,
3624 RowGatherOp::Adaptor adaptor,
3625 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3626 llvm::SmallVector<int64_t> outputShape;
3627 outputShape.resize(3, ShapedType::kDynamic);
3629 const ShapeAdaptor valuesShape(adaptor.getValues().getType());
3630 if (valuesShape.hasRank()) {
3631 outputShape[0] = valuesShape.getDimSize(0);
3632 outputShape[2] = valuesShape.getDimSize(2);
3635 const ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3636 if (indicesShape.hasRank()) {
3637 if (outputShape[0] == ShapedType::kDynamic)
3638 outputShape[0] = indicesShape.getDimSize(0);
3640 const FailureOr<int32_t> maybeRowCount =
3642 if (succeeded(maybeRowCount)) {
3643 const int64_t indicesW = indicesShape.getDimSize(1);
3644 if (ShapedType::isStatic(indicesW))
3645 outputShape[1] = indicesW * maybeRowCount.value();
3649 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3653LogicalResult tosa::RowGatherBlockScaledOp::inferReturnTypeComponents(
3654 MLIRContext *context, ::std::optional<Location> location,
3655 RowGatherBlockScaledOp::Adaptor adaptor,
3656 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3657 const auto values = adaptor.getValues();
3661 SmallVector<int64_t> dataShape(3, ShapedType::kDynamic);
3662 const ShapeAdaptor valuesShape(values.front().getType());
3663 if (valuesShape.hasRank()) {
3664 dataShape[0] = valuesShape.getDimSize(0);
3665 dataShape[2] = valuesShape.getDimSize(2);
3668 const ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3669 if (indicesShape.hasRank()) {
3670 if (dataShape[0] == ShapedType::kDynamic)
3671 dataShape[0] = indicesShape.getDimSize(0);
3675 succeeded(rowCount) && rowCount.value() > 0) {
3676 const int64_t indicesW = indicesShape.getDimSize(1);
3677 if (ShapedType::isStatic(indicesW))
3678 dataShape[1] = indicesW * rowCount.value();
3682 inferredReturnShapes.push_back(ShapedTypeComponents(dataShape));
3683 if (values.size() == 1)
3686 SmallVector<int64_t> scaleShape = dataShape;
3687 const uint32_t blockSize =
3688 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
3689 if (ShapedType::isStatic(dataShape[2]))
3690 scaleShape[2] = dataShape[2] / blockSize;
3692 inferredReturnShapes.push_back(ShapedTypeComponents(scaleShape));
3696LogicalResult tosa::GatherOp::verify() {
3703 const ShapeAdaptor valuesShape(getValues().
getType());
3705 const ShapeAdaptor outputShape(getOutput().
getType());
3707 int64_t n = ShapedType::kDynamic;
3708 int64_t w = ShapedType::kDynamic;
3709 int64_t c = ShapedType::kDynamic;
3711 if (valuesShape.hasRank()) {
3712 n = valuesShape.getDimSize(0);
3713 c = valuesShape.getDimSize(2);
3715 if (indicesShape.hasRank()) {
3716 const int64_t indicesN = indicesShape.getDimSize(0);
3717 w = indicesShape.getDimSize(1);
3718 if (n == ShapedType::kDynamic)
3720 else if (indicesN != ShapedType::kDynamic && n != indicesN)
3721 return emitOpError() <<
"requires indices dimension 0 to have size " << n
3722 <<
", got " << indicesN;
3724 if (outputShape.hasRank()) {
3725 const int64_t outputN = outputShape.getDimSize(0);
3726 const int64_t outputW = outputShape.getDimSize(1);
3727 const int64_t outputC = outputShape.getDimSize(2);
3728 if (n != ShapedType::kDynamic && outputN != ShapedType::kDynamic &&
3730 return emitOpError() <<
"requires output dimension 0 to have size " << n
3731 <<
", got " << outputN;
3733 if (w != ShapedType::kDynamic && outputW != ShapedType::kDynamic &&
3735 return emitOpError() <<
"requires output dimension 1 to have size " << w
3736 <<
", got " << outputW;
3737 if (c != ShapedType::kDynamic && outputC != ShapedType::kDynamic &&
3739 return emitOpError() <<
"requires output dimension 2 to have size " << c
3740 <<
", got " << outputC;
3745LogicalResult tosa::RowGatherOp::verify() {
3750 const FailureOr<int32_t> maybeRowCount =
3752 if (succeeded(maybeRowCount) && maybeRowCount.value() <= 0)
3753 return emitOpError() <<
"requires row_count to be > 0, got "
3754 << maybeRowCount.value();
3756 int64_t n = ShapedType::kDynamic;
3757 int64_t c = ShapedType::kDynamic;
3758 int64_t w = ShapedType::kDynamic;
3760 const ShapeAdaptor valuesShape(getValues().
getType());
3761 if (valuesShape.hasRank()) {
3762 n = valuesShape.getDimSize(0);
3763 c = valuesShape.getDimSize(2);
3767 if (indicesShape.hasRank()) {
3769 "indices",
"batch")))
3771 w = indicesShape.getDimSize(1);
3774 const ShapeAdaptor outputShape(getOutput().
getType());
3775 if (outputShape.hasRank()) {
3777 "output",
"batch")) ||
3779 "output",
"channels")))
3782 if (succeeded(maybeRowCount) && maybeRowCount.value() > 0 &&
3783 ShapedType::isStatic(w)) {
3784 const int64_t expectedOutputRows = w * maybeRowCount.value();
3785 if (ShapedType::isStatic(outputShape.getDimSize(1)) &&
3786 outputShape.getDimSize(1) != expectedOutputRows)
3788 <<
"requires output dimension to be equal to "
3789 "indices[1]*row_count ("
3790 << expectedOutputRows <<
"), got " << outputShape.getDimSize(1);
3797LogicalResult tosa::RowGatherBlockScaledOp::verify() {
3798 const OperandRange values = getValues();
3799 const ResultRange output = getOutput();
3800 if (values.empty() || values.size() > 2)
3802 <<
"expects values tensor list length to be 1 or 2, got "
3804 if (output.size() != values.size())
3806 <<
"expects output tensor list length to match values tensor list "
3808 << output.size() <<
" results for " << values.size()
3809 <<
" input tensors";
3811 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
3812 if (values.size() == 1 && blockSize != 1)
3814 <<
"requires block_size to be BLOCK_SIZE_1 when values tensor list "
3816 if (values.size() == 2 && blockSize == 1)
3818 <<
"requires block_size to not be BLOCK_SIZE_1 when values tensor "
3822 output[0].
getType(),
"values[0]",
3827 "values[1]",
"output[1]")))
3831 succeeded(rowCount) && rowCount.value() <= 0)
3832 return emitOpError() <<
"requires row_count to be > 0, got "
3833 << rowCount.value();
3835 int64_t n = ShapedType::kDynamic;
3836 int64_t k = ShapedType::kDynamic;
3837 int64_t c = ShapedType::kDynamic;
3838 int64_t w = ShapedType::kDynamic;
3839 int64_t multiplesOfC = ShapedType::kDynamic;
3841 const ShapeAdaptor valuesDataShape(values[0].
getType());
3842 if (valuesDataShape.hasRank()) {
3843 n = valuesDataShape.getDimSize(0);
3844 k = valuesDataShape.getDimSize(1);
3845 c = valuesDataShape.getDimSize(2);
3848 if (ShapedType::isStatic(c) && c % blockSize != 0)
3849 return emitOpError() <<
"expects channels of values[0] (" << c
3850 <<
") to be divisible by block_size (" << blockSize
3854 if (indicesShape.hasRank()) {
3856 "indices",
"batch")))
3858 w = indicesShape.getDimSize(1);
3861 const ShapeAdaptor outputDataShape(output[0].
getType());
3862 if (outputDataShape.hasRank()) {
3864 "output[0]",
"batch")) ||
3866 "output[0]",
"channels")))
3870 succeeded(rowCount) && rowCount.value() > 0 &&
3871 ShapedType::isStatic(w)) {
3872 const int64_t expectedOutputRows = w * rowCount.value();
3873 if (ShapedType::isStatic(outputDataShape.getDimSize(1)) &&
3874 outputDataShape.getDimSize(1) != expectedOutputRows)
3875 return emitOpError() <<
"requires output[0] dimension 1 to have size "
3876 << expectedOutputRows <<
", got "
3877 << outputDataShape.getDimSize(1);
3881 if (values.size() == 2) {
3882 const ShapeAdaptor valuesScaleShape(values[1].
getType());
3883 if (valuesScaleShape.hasRank()) {
3885 "values[1]",
"batch")) ||
3887 "values[1]",
"rows")))
3889 multiplesOfC = valuesScaleShape.getDimSize(2);
3892 const ShapeAdaptor outputScaleShape(output[1].
getType());
3893 if (outputScaleShape.hasRank()) {
3895 "output[1]",
"batch")))
3899 succeeded(rowCount) && rowCount.value() > 0 &&
3900 ShapedType::isStatic(w)) {
3901 const int64_t expectedOutputRows = w * rowCount.value();
3902 if (ShapedType::isStatic(outputScaleShape.getDimSize(1)) &&
3903 outputScaleShape.getDimSize(1) != expectedOutputRows)
3904 return emitOpError() <<
"requires output[1] dimension 1 to have size "
3905 << expectedOutputRows <<
", got "
3906 << outputScaleShape.getDimSize(1);
3909 if (ShapedType::isDynamic(multiplesOfC))
3910 multiplesOfC = outputScaleShape.getDimSize(2);
3911 else if (ShapedType::isStatic(outputScaleShape.getDimSize(2)) &&
3912 multiplesOfC != outputScaleShape.getDimSize(2))
3914 <<
"expected channels of output[1] to match size "
3915 << multiplesOfC <<
", got " << outputScaleShape.getDimSize(2);
3918 if (ShapedType::isStatic(c) && ShapedType::isStatic(multiplesOfC) &&
3919 multiplesOfC != c / blockSize)
3921 <<
"expects channels of scale tensors to equal C/block_size (" << c
3922 <<
"/" << blockSize <<
"), got " << multiplesOfC;
3928LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
3929 MLIRContext *context, ::std::optional<Location> location,
3930 ResizeOp::Adaptor adaptor,
3931 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3932 llvm::SmallVector<int64_t, 4> outputShape;
3933 outputShape.resize(4, ShapedType::kDynamic);
3935 ShapeAdaptor inputShape(adaptor.getInput().getType());
3936 if (!inputShape.hasRank())
3939 outputShape[0] = inputShape.getDimSize(0);
3940 outputShape[3] = inputShape.getDimSize(3);
3941 int64_t inputHeight = inputShape.getDimSize(1);
3942 int64_t inputWidth = inputShape.getDimSize(2);
3944 if ((inputHeight == ShapedType::kDynamic) ||
3945 (inputWidth == ShapedType::kDynamic))
3948 SmallVector<int64_t> scaleInt, offsetInt, borderInt;
3959 const int64_t outputHeight =
3960 (((inputHeight - 1) * scaleInt[0] - offsetInt[0] + borderInt[0]) /
3964 const int64_t outputWidth =
3965 (((inputWidth - 1) * scaleInt[2] - offsetInt[1] + borderInt[1]) /
3969 if (outputHeight < 0 || outputWidth < 0) {
3972 "calculated output height and width must be non-negative, "
3974 outputHeight,
", width = ", outputWidth);
3977 outputShape[1] = outputHeight;
3978 outputShape[2] = outputWidth;
3979 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3983LogicalResult tosa::ResizeOp::verify() {
3984 const Value input = getInput();
3985 const Value output = getOutput();
3988 if (isa<BlockScaledType>(inputElementType) &&
3989 getMode() != ResizeMode::NEAREST_NEIGHBOR)
3990 return emitOpError(
"requires NEAREST_NEIGHBOR mode for block scaled input");
3992 const RankedTensorType inputType =
3993 llvm::dyn_cast<RankedTensorType>(input.
getType());
3994 const RankedTensorType outputType =
3995 llvm::dyn_cast<RankedTensorType>(output.
getType());
3997 SmallVector<int64_t> scaleValues;
3998 SmallVector<int64_t> offsetValues;
3999 SmallVector<int64_t> borderValues;
4007 if (llvm::any_of(scaleValues, [](int64_t s) {
return s <= 0; }))
4008 return emitOpError(
"expect all scale values to be > 0, got ")
4011 const int64_t scaleYN = scaleValues[0];
4012 const int64_t scaleYD = scaleValues[1];
4013 const int64_t scaleXN = scaleValues[2];
4014 const int64_t scaleXD = scaleValues[3];
4016 const int64_t offsetY = offsetValues[0];
4017 const int64_t offsetX = offsetValues[1];
4019 const int64_t borderY = borderValues[0];
4020 const int64_t borderX = borderValues[1];
4027 const int64_t oh = outputType.getDimSize(1);
4028 const int64_t ow = outputType.getDimSize(2);
4029 const int64_t ih = inputType.getDimSize(1);
4030 const int64_t iw = inputType.getDimSize(2);
4036 if (ih != ShapedType::kDynamic && ih != 1) {
4037 const std::optional<int64_t> calculatedOutHeightMinusOne =
4038 idivCheck((ih - 1) * scaleYN - offsetY + borderY, scaleYD);
4039 if (!calculatedOutHeightMinusOne.has_value())
4040 return emitOpError(
"expected (input_height - 1) * scale_y_n - offset_y + "
4042 <<
"to be wholly divisible by scale_y_d, got ((" << ih
4043 <<
" - 1) * " << scaleYN <<
" - " << offsetY <<
" + " << borderY
4044 <<
") / " << scaleYD;
4045 const int64_t calculatedOutHeight = calculatedOutHeightMinusOne.value() + 1;
4046 if (oh != ShapedType::kDynamic && calculatedOutHeight != oh)
4047 return emitOpError(
"calculated output height did not match expected: ")
4048 <<
"calculated=" << calculatedOutHeight <<
", expected=" << oh;
4055 if (iw != ShapedType::kDynamic && iw != 1) {
4056 const int64_t scaledInWidth = (iw - 1) * scaleXN - offsetX + borderX;
4057 const std::optional<int64_t> calculatedOutWidthMinusOne =
4059 if (!calculatedOutWidthMinusOne.has_value())
4060 return emitOpError(
"expected (input_width - 1) * scale_x_n - offset_x + "
4062 <<
"to be wholly divisible by scale_x_d, got ((" << iw
4063 <<
" - 1) * " << scaleXN <<
" - " << offsetX <<
" + " << borderX
4064 <<
") / " << scaleXD;
4065 const int64_t calculatedOutWidth = calculatedOutWidthMinusOne.value() + 1;
4066 if (ow != ShapedType::kDynamic && calculatedOutWidth != ow)
4067 return emitOpError(
"calculated output width did not match expected: ")
4068 <<
"calculated=" << calculatedOutWidth <<
", expected=" << ow;
4074LogicalResult tosa::ScatterOp::inferReturnTypeComponents(
4075 MLIRContext *context, ::std::optional<Location> location,
4076 ScatterOp::Adaptor adaptor,
4077 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4078 llvm::SmallVector<int64_t> outputShape;
4079 outputShape.resize(3, ShapedType::kDynamic);
4081 ShapeAdaptor valuesInShape(adaptor.getValuesIn().getType());
4082 if (valuesInShape.hasRank()) {
4083 outputShape[0] = valuesInShape.getDimSize(0);
4084 outputShape[1] = valuesInShape.getDimSize(1);
4085 outputShape[2] = valuesInShape.getDimSize(2);
4088 ShapeAdaptor indicesShape(adaptor.getIndices().getType());
4089 if (indicesShape.hasRank()) {
4090 if (outputShape[0] == ShapedType::kDynamic)
4091 outputShape[0] = indicesShape.getDimSize(0);
4094 ShapeAdaptor inputShape(adaptor.getInput().getType());
4095 if (inputShape.hasRank()) {
4096 if (outputShape[0] == ShapedType::kDynamic)
4097 outputShape[0] = inputShape.getDimSize(0);
4098 if (outputShape[2] == ShapedType::kDynamic)
4099 outputShape[2] = inputShape.getDimSize(2);
4102 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4106LogicalResult tosa::ScatterOp::verify() {
4116 const ShapeAdaptor valuesInShape(getValuesIn().
getType());
4118 const ShapeAdaptor inputShape(getInput().
getType());
4119 const ShapeAdaptor outputShape(getValuesOut().
getType());
4121 int64_t n = ShapedType::kDynamic;
4122 int64_t k = ShapedType::kDynamic;
4123 int64_t w = ShapedType::kDynamic;
4124 int64_t c = ShapedType::kDynamic;
4125 if (valuesInShape.hasRank()) {
4126 n = valuesInShape.getDimSize(0);
4127 k = valuesInShape.getDimSize(1);
4128 c = valuesInShape.getDimSize(2);
4130 if (indicesShape.hasRank()) {
4131 const int64_t indicesN = indicesShape.getDimSize(0);
4132 w = indicesShape.getDimSize(1);
4133 if (n == ShapedType::kDynamic)
4135 else if (indicesN != ShapedType::kDynamic && n != indicesN)
4136 return emitOpError() <<
"requires indices dimension 0 to have size " << n
4137 <<
", got " << indicesN;
4139 if (inputShape.hasRank()) {
4140 const int64_t inputN = inputShape.getDimSize(0);
4141 const int64_t inputW = inputShape.getDimSize(1);
4142 const int64_t inputC = inputShape.getDimSize(2);
4143 if (n == ShapedType::kDynamic)
4145 else if (inputN != ShapedType::kDynamic && n != inputN)
4146 return emitOpError() <<
"requires input dimension 0 to have size " << n
4147 <<
", got " << inputN;
4148 if (w == ShapedType::kDynamic)
4150 else if (inputW != ShapedType::kDynamic && w != inputW)
4151 return emitOpError() <<
"requires input dimension 1 to have size " << w
4152 <<
", got " << inputW;
4154 if (c == ShapedType::kDynamic)
4156 else if (inputC != ShapedType::kDynamic && c != inputC)
4157 return emitOpError() <<
"requires input dimension 2 to have size " << c
4158 <<
", got " << inputC;
4160 if (outputShape.hasRank()) {
4161 const int64_t outputN = outputShape.getDimSize(0);
4162 const int64_t outputK = outputShape.getDimSize(1);
4163 const int64_t outputC = outputShape.getDimSize(2);
4164 if (n != ShapedType::kDynamic && outputN != ShapedType::kDynamic &&
4166 return emitOpError() <<
"requires values_out dimension 0 to have size "
4167 << n <<
", got " << outputN;
4168 if (k == ShapedType::kDynamic)
4170 else if (outputK != ShapedType::kDynamic && k != outputK)
4171 return emitOpError() <<
"requires values_out dimension 1 to have size "
4172 << k <<
", got " << outputK;
4173 if (c != ShapedType::kDynamic && outputC != ShapedType::kDynamic &&
4175 return emitOpError() <<
"requires values_out dimension 2 to have size "
4176 << c <<
", got " << outputC;
4178 if (k != ShapedType::kDynamic && w != ShapedType::kDynamic && !(k >= w))
4179 return emitOpError() <<
"requires dimensions K >= W, got K=" << k
4188 int64_t axisVal = axis.getValue().getSExtValue();
4189 if (!operandShape.
hasRank() || operandShape.
getRank() <= axisVal) {
4195 operandShape.
getDims(outputShape);
4196 outputShape[axisVal] = 1;
4201#define COMPATIBLE_RETURN_TYPES(OP) \
4202 bool OP::isCompatibleReturnTypes(TypeRange l, TypeRange r) { \
4203 if (l.size() != r.size() || l.size() != 1) \
4205 if (getElementTypeOrSelf(l[0]) != getElementTypeOrSelf(r[0])) \
4207 return succeeded(verifyCompatibleShape(l[0], r[0])); \
4210#define REDUCE_SHAPE_INFER(OP) \
4211 LogicalResult OP::inferReturnTypeComponents( \
4212 MLIRContext *context, ::std::optional<Location> location, \
4213 OP::Adaptor adaptor, \
4214 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) { \
4216 llvm::cast<TensorType>(adaptor.getInput().getType()).getElementType(); \
4217 ShapeAdaptor inputShape(adaptor.getInput().getType()); \
4218 const Properties &prop = adaptor.getProperties(); \
4219 return ReduceInferReturnTypes(inputShape, inputType, prop.axis, \
4220 inferredReturnShapes); \
4222 COMPATIBLE_RETURN_TYPES(OP)
4230#undef REDUCE_SHAPE_INFER
4232#undef COMPATIBLE_RETURN_TYPES
4234template <
typename T>
4237 TensorType inputType = op.getInput().getType();
4238 TensorType outputType = op.getOutput().getType();
4239 int32_t reduceAxis = op.getAxis();
4241 if (reduceAxis < 0) {
4242 op.emitOpError(
"reduce axis must not be negative");
4246 int64_t inputRank = inputType.getRank();
4249 if (reduceAxis >= inputRank && (reduceAxis != 0 || inputRank != 0)) {
4250 op.emitOpError(
"expect input tensor rank (")
4251 << inputRank <<
") to be larger than reduce axis (" << reduceAxis
4257 int64_t outputRank = outputType.getRank();
4258 if (inputType.
hasRank() && outputRank != inputType.getRank()) {
4260 "expect output tensor rank to be equal to input tensor rank");
4263 if (reduceAxis >= outputRank && (reduceAxis != 0 || outputRank != 0)) {
4264 op.emitOpError(
"expect output tensor rank (")
4265 << outputRank <<
") to be larger than reduce axis (" << reduceAxis
4271 if (outputRank != 0) {
4272 auto outputShape = outputType.
getShape();
4273 if (!outputType.isDynamicDim(reduceAxis) &&
4274 outputShape[reduceAxis] != 1) {
4275 op.emitOpError(
"expect reduced dimension size to be 1, got ")
4276 << outputShape[reduceAxis];
4284LogicalResult tosa::ReduceAllOp::verify() {
return verifyReduceOp(*
this); }
4285LogicalResult tosa::ReduceAnyOp::verify() {
return verifyReduceOp(*
this); }
4286LogicalResult tosa::ReduceMaxOp::verify() {
return verifyReduceOp(*
this); }
4287LogicalResult tosa::ReduceMinOp::verify() {
return verifyReduceOp(*
this); }
4288LogicalResult tosa::ReduceProductOp::verify() {
return verifyReduceOp(*
this); }
4289LogicalResult tosa::ReduceSumOp::verify() {
return verifyReduceOp(*
this); }
4303#define NARY_SHAPE_INFER(OP) \
4304 LogicalResult OP::inferReturnTypeComponents( \
4305 MLIRContext *context, ::std::optional<Location> location, \
4306 ValueShapeRange operands, DictionaryAttr attributes, \
4307 PropertyRef properties, RegionRange regions, \
4308 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) { \
4309 return NAryInferReturnTypes(operands, inferredReturnShapes); \
4349#undef PRED_SHAPE_INFER
4351LogicalResult tosa::NegateOp::inferReturnTypeComponents(
4352 MLIRContext *context, ::std::optional<Location> location,
4353 NegateOp::Adaptor adaptor,
4355 ShapeAdaptor inputShape(adaptor.getInput1().getType());
4360LogicalResult tosa::NegateOp::verify() {
4362 const Type input1Type = getInput1().getType();
4363 const Type outputType = getOutput().getType();
4368 const SmallVector<Type, 2> types = {input1Type, outputType};
4370 return emitOpError() <<
"requires the same shape for input1 and output";
4373 const Type input1ZpEType =
4375 if (input1EType != input1ZpEType) {
4376 return emitOpError(
"expect both input1 and its zero point are the same "
4377 "element type, got ")
4378 << input1EType <<
" and " << input1ZpEType;
4381 const Type outputZpEType =
4383 if (outputEType != outputZpEType) {
4384 return emitOpError(
"expect both output and its zero point are the same "
4385 "element type, got ")
4386 << outputEType <<
" and " << outputZpEType;
4389 FailureOr<int64_t> maybeIZp = getInput1ZeroPoint();
4390 if (succeeded(maybeIZp) && verifyInput1ZeroPoint(*maybeIZp).failed())
4393 FailureOr<int64_t> maybeOZp = getOutputZeroPoint();
4394 if (succeeded(maybeOZp) && verifyOutputZeroPoint(*maybeOZp).failed())
4405 outputShape.resize(4, ShapedType::kDynamic);
4420 if (ShapedType::isStatic(height)) {
4421 int64_t padded = height + pad[0] + pad[1] - kernel[0];
4422 outputShape[1] = padded / stride[0] + 1;
4425 if (ShapedType::isStatic(width)) {
4426 int64_t padded = width + pad[2] + pad[3] - kernel[1];
4427 outputShape[2] = padded / stride[1] + 1;
4434template <
typename AdaptorT>
4440 if (ShapedType::isDynamic(current))
4441 current = candidate;
4450 : adaptor(adaptor) {}
4454 const ShapeAdaptor inputShape(adaptor.getInput().getType());
4462 outputShape[0] = outputBatch;
4463 inputSpatial[0] = inputHeight;
4464 inputSpatial[1] = inputWidth;
4469 const ShapeAdaptor weightShape(adaptor.getWeight().getType());
4477 outputShape[3] = outputChannels;
4478 weightSpatial[0] = kernelHeight;
4479 weightSpatial[1] = kernelWidth;
4488 padValues.assign(adaptor.getPad().begin(), adaptor.getPad().end());
4489 strideValues.assign(adaptor.getStride().begin(), adaptor.getStride().end());
4490 dilationValues.assign(adaptor.getDilation().begin(),
4491 adaptor.getDilation().end());
4496 Conv2DOp::Adaptor adaptor;
4504 : adaptor(adaptor) {}
4508 const ShapeAdaptor inputDataShape(adaptor.getInputData().getType());
4509 if (inputDataShape.
hasRank()) {
4514 outputShape[0] = outputBatch;
4515 inputSpatial[0] = inputHeight;
4516 inputSpatial[1] = inputWidth;
4519 const ShapeAdaptor inputScaleShape(adaptor.getInputScale().getType());
4520 if (!inputScaleShape.
hasRank())
4534 const ShapeAdaptor weightDataShape(adaptor.getWeightData().getType());
4535 if (weightDataShape.
hasRank()) {
4540 outputShape[3] = outputChannels;
4541 weightSpatial[0] = kernelHeight;
4542 weightSpatial[1] = kernelWidth;
4545 const ShapeAdaptor weightScaleShape(adaptor.getWeightScale().getType());
4546 if (!weightScaleShape.
hasRank())
4575 Conv2DBlockScaledOp::Adaptor adaptor;
4583 : adaptor(adaptor) {}
4587 const ShapeAdaptor inputShape(adaptor.getInput().getType());
4596 outputShape[0] = outputBatch;
4597 inputSpatial[0] = inputDepth;
4598 inputSpatial[1] = inputHeight;
4599 inputSpatial[2] = inputWidth;
4604 const ShapeAdaptor weightShape(adaptor.getWeight().getType());
4613 outputShape[4] = outputChannels;
4614 weightSpatial[0] = kernelDepth;
4615 weightSpatial[1] = kernelHeight;
4616 weightSpatial[2] = kernelWidth;
4625 padValues.assign(adaptor.getPad().begin(), adaptor.getPad().end());
4626 strideValues.assign(adaptor.getStride().begin(), adaptor.getStride().end());
4627 dilationValues.assign(adaptor.getDilation().begin(),
4628 adaptor.getDilation().end());
4633 Conv3DOp::Adaptor adaptor;
4636template <
typename AdaptorT>
4642 ShapedType::kDynamic);
4644 ShapedType::kDynamic);
4646 ShapedType::kDynamic);
4648 convShapeAdaptor.inferInputShape(outputShape, inputSpatial);
4649 convShapeAdaptor.inferWeightShape(outputShape, weightSpatial);
4651 const ShapeAdaptor biasShape = adaptor.getBias().getType();
4654 if (biasSize != 1) {
4655 const size_t outputChannelDim = convShapeAdaptor.getOutputRank() - 1;
4656 outputShape[outputChannelDim] =
4657 ShapedType::isDynamic(outputShape[outputChannelDim])
4659 : outputShape[outputChannelDim];
4666 if (failed(convShapeAdaptor.getSpatialParameters(padValues, strideValues,
4672 for (
int64_t dim = 0; dim < convShapeAdaptor.getNumSpatialDims(); ++dim) {
4673 if (!ShapedType::isStatic(inputSpatial[dim]) ||
4674 !ShapedType::isStatic(weightSpatial[dim]))
4677 inputSpatial[dim] + padValues[2 * dim] + padValues[2 * dim + 1];
4679 (weightSpatial[dim] - 1) * dilationValues[dim] + 1;
4680 const int64_t unstridedResult = inputSize - filterSize + 1;
4681 outputShape[dim + 1] = (unstridedResult - 1) / strideValues[dim] + 1;
4688LogicalResult Conv2DOp::inferReturnTypeComponents(
4689 MLIRContext *context, ::std::optional<Location> location,
4690 Conv2DOp::Adaptor adaptor,
4691 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4695LogicalResult Conv2DOp::verify() {
4702LogicalResult Conv2DBlockScaledOp::inferReturnTypeComponents(
4703 MLIRContext *context, ::std::optional<Location> location,
4704 Conv2DBlockScaledOp::Adaptor adaptor,
4705 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4709LogicalResult Conv2DBlockScaledOp::verify() {
4711 getWeightData().
getType(),
"input_data",
4714 getWeightScale().
getType(),
"input_scale",
4717 getOutput().
getType(),
"bias",
"output")))
4721 int64_t N = ShapedType::kDynamic;
4722 int64_t IH = ShapedType::kDynamic;
4723 int64_t IW = ShapedType::kDynamic;
4724 int64_t IC = ShapedType::kDynamic;
4725 int64_t multiplesOfIC = ShapedType::kDynamic;
4726 int64_t OC = ShapedType::kDynamic;
4727 int64_t KH = ShapedType::kDynamic;
4728 int64_t KW = ShapedType::kDynamic;
4730 const ShapeAdaptor inputDataShape(getInputData().
getType());
4731 if (inputDataShape.hasRank()) {
4732 N = inputDataShape.getDimSize(0);
4733 IH = inputDataShape.getDimSize(1);
4734 IW = inputDataShape.getDimSize(2);
4735 IC = inputDataShape.getDimSize(3);
4738 const ShapeAdaptor inputScaleShape(getInputScale().
getType());
4739 if (inputScaleShape.hasRank()) {
4741 "input_scale",
"batch size")) ||
4743 "input_scale",
"input height")) ||
4745 "input_scale",
"input width")))
4747 multiplesOfIC = inputScaleShape.getDimSize(3);
4750 const ShapeAdaptor weightDataShape(getWeightData().
getType());
4751 if (weightDataShape.hasRank()) {
4752 OC = weightDataShape.getDimSize(0);
4753 KH = weightDataShape.getDimSize(1);
4754 KW = weightDataShape.getDimSize(2);
4756 "weight_data",
"input channels")))
4760 const ShapeAdaptor weightScaleShape(getWeightScale().
getType());
4761 if (weightScaleShape.hasRank()) {
4763 "weight_scale",
"output channels")) ||
4765 "weight_scale",
"kernel height")) ||
4767 "weight_scale",
"kernel width")) ||
4769 weightScaleShape.getDimSize(3),
4770 "weight_scale",
"input channel blocks")))
4774 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
4775 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
4776 return emitOpError(
"expect block size to be 32, got ") << blockSize;
4778 if (ShapedType::isStatic(IC) && IC % blockSize != 0)
4779 return emitOpError(
"expect IC to be a multiple of block size, got IC=")
4780 << IC <<
", block_size=" << blockSize;
4783 if (ShapedType::isStatic(IC) && ShapedType::isStatic(multiplesOfIC) &&
4784 multiplesOfIC != IC / blockSize)
4786 "expect scale operands dimension 2 to equal IC/block_size (")
4787 << IC <<
"/" << blockSize <<
")"
4788 <<
", got " << multiplesOfIC;
4791 SmallVector<int64_t> padValues;
4793 if (llvm::any_of(padValues, [](int64_t p) {
return p < 0; }))
4794 return emitOpError(
"expect all padding values to be >= 0, got ")
4798 SmallVector<int64_t> strideValues;
4800 if (llvm::any_of(strideValues, [](int64_t s) {
return s < 1; }))
4801 return emitOpError(
"expect all stride values to be >= 1, got ")
4805 SmallVector<int64_t> dilationValues;
4808 if (llvm::any_of(dilationValues, [](int64_t d) {
return d < 1; }))
4809 return emitOpError(
"expect all dilation values to be >= 1, got ")
4814 const ShapeAdaptor outputShape(getOutput().
getType());
4815 if (!padValues.empty() && !strideValues.empty() && !dilationValues.empty() &&
4816 outputShape.hasRank()) {
4818 padValues[0], padValues[1], strideValues[0],
4819 dilationValues[0],
"height",
"y",
"top",
4822 padValues[2], padValues[3], strideValues[1],
4823 dilationValues[1],
"width",
"x",
"left",
4829 const ShapeAdaptor biasShape(getBias().
getType());
4830 if (biasShape.hasRank() && outputShape.hasRank()) {
4831 const int64_t biasChannels = biasShape.getDimSize(0);
4832 const int64_t outputChannels =
4833 outputShape.getDimSize(outputShape.getRank() - 1);
4834 if (biasChannels == ShapedType::kDynamic ||
4835 outputChannels == ShapedType::kDynamic)
4839 if (biasChannels != outputChannels && biasChannels != 1)
4841 "bias channels expected to be equal to output channels (")
4842 << outputChannels <<
") or 1, got " << biasChannels;
4848LogicalResult Conv3DOp::inferReturnTypeComponents(
4849 MLIRContext *context, ::std::optional<Location> location,
4850 Conv3DOp::Adaptor adaptor,
4851 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4855LogicalResult Conv3DOp::verify() {
4862LogicalResult AvgPool2dOp::inferReturnTypeComponents(
4863 MLIRContext *context, ::std::optional<Location> location,
4864 AvgPool2dOp::Adaptor adaptor,
4865 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4866 ShapeAdaptor inputShape(adaptor.getInput().getType());
4867 const Properties &prop = adaptor.getProperties();
4869 inferredReturnShapes);
4872LogicalResult AvgPool2dAdaptiveOp::inferReturnTypeComponents(
4873 MLIRContext *context, ::std::optional<Location> location,
4874 AvgPool2dAdaptiveOp::Adaptor adaptor,
4875 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4876 ShapeAdaptor inputShape(adaptor.getInput().getType());
4878 llvm::SmallVector<int64_t> kernelValues;
4879 llvm::SmallVector<int64_t> strideValues;
4880 llvm::SmallVector<int64_t> padValues;
4887 padValues, inferredReturnShapes);
4890 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4891 if (inputShape.hasRank()) {
4893 outputShape[0] = inputShape.getDimSize(0);
4894 outputShape[3] = inputShape.getDimSize(3);
4897 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4901LogicalResult MaxPool2dOp::inferReturnTypeComponents(
4902 MLIRContext *context, ::std::optional<Location> location,
4903 MaxPool2dOp::Adaptor adaptor,
4904 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4905 ShapeAdaptor inputShape(adaptor.getInput().getType());
4906 const Properties &prop = adaptor.getProperties();
4908 inferredReturnShapes);
4911LogicalResult MaxPool2dAdaptiveOp::inferReturnTypeComponents(
4912 MLIRContext *context, ::std::optional<Location> location,
4913 MaxPool2dAdaptiveOp::Adaptor adaptor,
4914 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4915 ShapeAdaptor inputShape(adaptor.getInput().getType());
4917 llvm::SmallVector<int64_t> kernelValues;
4918 llvm::SmallVector<int64_t> strideValues;
4919 llvm::SmallVector<int64_t> padValues;
4926 padValues, inferredReturnShapes);
4929 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4930 if (inputShape.hasRank()) {
4931 outputShape[0] = inputShape.getDimSize(0);
4932 outputShape[3] = inputShape.getDimSize(3);
4934 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4938LogicalResult MaxPool2dOp::verify() {
4949LogicalResult MaxPool2dAdaptiveOp::verify() {
4954 AdaptivePoolingConstShapeValues values;
4958 values.pad, getInput(), getOutput())))
4964LogicalResult DepthwiseConv2DOp::inferReturnTypeComponents(
4965 MLIRContext *context, ::std::optional<Location> location,
4966 DepthwiseConv2DOp::Adaptor adaptor,
4967 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4968 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4970 int64_t inputWidth = ShapedType::kDynamic;
4971 int64_t inputHeight = ShapedType::kDynamic;
4972 int64_t inputChannels = ShapedType::kDynamic;
4974 int64_t weightWidth = ShapedType::kDynamic;
4975 int64_t weightHeight = ShapedType::kDynamic;
4976 int64_t depthChannels = ShapedType::kDynamic;
4979 ShapeAdaptor inputShape(adaptor.getInput().getType());
4980 if (inputShape.hasRank()) {
4981 outputShape[0] = inputShape.getDimSize(0);
4982 inputHeight = inputShape.getDimSize(1);
4983 inputWidth = inputShape.getDimSize(2);
4984 inputChannels = inputShape.getDimSize(3);
4988 ShapeAdaptor weightShape(adaptor.getWeight().getType());
4989 if (weightShape.hasRank()) {
4990 weightHeight = weightShape.getDimSize(0);
4991 weightWidth = weightShape.getDimSize(1);
4992 inputChannels = ShapedType::isDynamic(inputChannels)
4993 ? weightShape.getDimSize(2)
4995 depthChannels = weightShape.getDimSize(3);
5000 if (ShapedType::isStatic(inputChannels) &&
5001 ShapedType::isStatic(depthChannels)) {
5002 outputShape[3] = inputChannels * depthChannels;
5006 ShapeAdaptor biasShape(adaptor.getBias().getType());
5007 if (biasShape.hasRank() && ShapedType::isDynamic(outputShape[3])) {
5008 int64_t bc = biasShape.getDimSize(0);
5009 if (bc != ShapedType::kDynamic && bc != 1)
5010 outputShape[3] = bc;
5013 llvm::ArrayRef<int64_t> dilation = adaptor.getDilation();
5014 llvm::ArrayRef<int64_t> padding = adaptor.getPad();
5015 llvm::ArrayRef<int64_t> stride = adaptor.getStride();
5017 if (ShapedType::isStatic(inputHeight) && ShapedType::isStatic(weightHeight)) {
5018 int64_t inputSize = inputHeight + padding[0] + padding[1];
5019 int64_t filterSize = (weightHeight - 1) * dilation[0] + 1;
5020 int64_t unstridedResult = inputSize - filterSize + 1;
5021 outputShape[1] = (unstridedResult - 1) / stride[0] + 1;
5024 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(weightWidth)) {
5025 int64_t inputSize = inputWidth + padding[2] + padding[3];
5026 int64_t filterSize = (weightWidth - 1) * dilation[1] + 1;
5027 int64_t unstridedResult = inputSize - filterSize + 1;
5028 outputShape[2] = (unstridedResult - 1) / stride[1] + 1;
5031 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
5035LogicalResult DepthwiseConv2DOp::verify() {
5042LogicalResult TransposeConv2DOp::inferReturnTypeComponents(
5043 MLIRContext *context, ::std::optional<Location> location,
5044 TransposeConv2DOp::Adaptor adaptor,
5045 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5046 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
5048 int64_t inputWidth = ShapedType::kDynamic;
5049 int64_t inputHeight = ShapedType::kDynamic;
5050 int64_t weightWidth = ShapedType::kDynamic;
5051 int64_t weightHeight = ShapedType::kDynamic;
5054 ShapeAdaptor inputShape(adaptor.getInput().getType());
5055 if (inputShape.hasRank()) {
5056 outputShape[0] = ShapedType::isDynamic(outputShape[0])
5057 ? inputShape.getDimSize(0)
5059 inputHeight = inputShape.getDimSize(1);
5060 inputWidth = inputShape.getDimSize(2);
5064 ShapeAdaptor weightShape(adaptor.getWeight().getType());
5065 if (weightShape.hasRank()) {
5066 outputShape[3] = ShapedType::isDynamic(outputShape[3])
5067 ? weightShape.getDimSize(0)
5069 weightHeight = weightShape.getDimSize(1);
5070 weightWidth = weightShape.getDimSize(2);
5074 ShapeAdaptor biasShape(adaptor.getBias().getType());
5075 if (biasShape.hasRank() && ShapedType::isDynamic(outputShape[3])) {
5076 int64_t bc = biasShape.getDimSize(0);
5077 if (bc != ShapedType::kDynamic && bc != 1)
5078 outputShape[3] = bc;
5081 llvm::ArrayRef<int64_t> padding = adaptor.getOutPad();
5082 llvm::ArrayRef<int64_t> stride = adaptor.getStride();
5084 if (ShapedType::isStatic(inputHeight) && ShapedType::isStatic(weightHeight)) {
5085 int64_t calculateSize =
5086 (inputHeight - 1) * stride[0] + padding[0] + padding[1] + weightHeight;
5088 ShapedType::isDynamic(outputShape[1]) ? calculateSize : outputShape[1];
5091 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(weightWidth)) {
5092 int64_t calculateSize =
5093 (inputWidth - 1) * stride[1] + padding[2] + padding[3] + weightWidth;
5095 ShapedType::isDynamic(outputShape[2]) ? calculateSize : outputShape[2];
5098 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
5102LogicalResult TransposeConv2DOp::verify() {
5106 const llvm::ArrayRef<int64_t> strides = getStride();
5107 const int64_t strideY = strides[0];
5108 const int64_t strideX = strides[1];
5110 if (strideY < 1 || strideX < 1)
5111 return emitOpError(
"expect all stride values to be >= 1, got [")
5114 const auto checkPadAgainstKernelDim =
5115 [
this](int64_t padValue, int64_t kernelDimSize, llvm::StringRef padName,
5116 llvm::StringRef kernelDimName) -> LogicalResult {
5117 if (padValue <= -kernelDimSize)
5119 << padName <<
" > -" << kernelDimName <<
", but got: " << padName
5120 <<
"=" << padValue <<
" and " << kernelDimName <<
"="
5125 const llvm::ArrayRef<int64_t> padding = getOutPad();
5126 const int64_t outPadTop = padding[0];
5127 const int64_t outPadBottom = padding[1];
5128 const int64_t outPadLeft = padding[2];
5129 const int64_t outPadRight = padding[3];
5131 const auto weightType =
5132 llvm::dyn_cast<RankedTensorType>(getWeight().
getType());
5135 const int64_t kernelHeight = weightType.getDimSize(1);
5136 if (ShapedType::isStatic(kernelHeight)) {
5137 if (
failed(checkPadAgainstKernelDim(outPadTop, kernelHeight,
5138 "out_pad_top",
"KH")))
5141 if (
failed(checkPadAgainstKernelDim(outPadBottom, kernelHeight,
5142 "out_pad_bottom",
"KH")))
5146 const int64_t kernelWidth = weightType.getDimSize(2);
5147 if (ShapedType::isStatic(kernelWidth)) {
5148 if (
failed(checkPadAgainstKernelDim(outPadLeft, kernelWidth,
5149 "out_pad_left",
"KW")))
5152 if (
failed(checkPadAgainstKernelDim(outPadRight, kernelWidth,
5153 "out_pad_right",
"KW")))
5159 const auto outputType =
5160 llvm::dyn_cast<RankedTensorType>(getOutput().
getType());
5164 const auto inputType = llvm::dyn_cast<RankedTensorType>(getInput().
getType());
5165 if (inputType && weightType) {
5166 const int64_t inputHeight = inputType.getDimSize(1);
5167 const int64_t kernelHeight = weightType.getDimSize(1);
5168 const int64_t outputHeight = outputType.getDimSize(1);
5170 if (ShapedType::isStatic(inputHeight) &&
5171 ShapedType::isStatic(outputHeight)) {
5173 (inputHeight - 1) * strideY + outPadTop + outPadBottom + kernelHeight)
5175 "dimension mismatch: expected OH == (IH - 1) * stride_y "
5176 "+ out_pad_top + out_pad_bottom + KH, but got ")
5177 << outputHeight <<
" != (" << inputHeight <<
" - 1) * "
5178 << strideY <<
" + " << outPadTop <<
" + " << outPadBottom
5179 <<
" + " << kernelHeight;
5182 const int64_t inputWidth = inputType.getDimSize(2);
5183 const int64_t kernelWidth = weightType.getDimSize(2);
5184 const int64_t outputWidth = outputType.getDimSize(2);
5186 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(outputWidth)) {
5188 (inputWidth - 1) * strideX + outPadLeft + outPadRight + kernelWidth)
5190 "dimension mismatch: expected OW == (IW - 1) * stride_x "
5191 "+ out_pad_left + out_pad_right + KW, but got ")
5192 << outputWidth <<
" != (" << inputWidth <<
" - 1) * " << strideX
5193 <<
" + " << outPadLeft <<
" + " << outPadRight <<
" + "
5198 const auto biasType = llvm::dyn_cast<RankedTensorType>(getBias().
getType());
5203 const int64_t biasChannels = biasType.getDimSize(0);
5206 if (biasChannels == ShapedType::kDynamic)
5209 const int64_t outputChannels = outputType.getDimSize(3);
5210 if (!ShapedType::isDynamic(outputChannels) &&
5211 biasChannels != outputChannels && biasChannels != 1)
5213 "bias channels expected to be equal to output channels (")
5214 << outputChannels <<
") or 1, got " << biasChannels;
5219LogicalResult RescaleOp::verify() {
5220 const auto inputType = llvm::cast<ShapedType>(getInput().
getType());
5221 auto inputElementType =
5223 if (!mlir::isa<IntegerType>(inputElementType)) {
5224 emitOpError(
"expect input to have integer element type, got ")
5225 << inputElementType;
5229 const auto outputType = llvm::cast<ShapedType>(getOutput().
getType());
5230 auto outputElementType =
5232 if (!mlir::isa<IntegerType>(outputElementType)) {
5233 emitOpError(
"expect output to have integer element type, got ")
5234 << outputElementType;
5246 FailureOr<int64_t> maybeIZp = getInputZeroPoint();
5247 if (succeeded(maybeIZp) && verifyInputZeroPoint(*maybeIZp).failed())
5250 FailureOr<int64_t> maybeOZp = getOutputZeroPoint();
5251 if (succeeded(maybeOZp) && verifyOutputZeroPoint(*maybeOZp).failed())
5254 const auto multiplierType = llvm::cast<ShapedType>(getMultiplier().
getType());
5256 if (getScale32() && !multiplierType.getElementType().isInteger(32)) {
5257 emitOpError(
"expect i32 element type for multiplier for scale32=true, got ")
5258 << multiplierType.getElementType();
5263 if (!getScale32() && !multiplierType.getElementType().isInteger(16)) {
5265 "expect i16 element type for multiplier for scale32=false, got ")
5266 << multiplierType.getElementType();
5270 if (!inputType.hasRank())
5276 int64_t numChannels = 1;
5277 if (getPerChannel()) {
5278 if (inputType.getRank() < 1) {
5279 emitOpError(
"requires input to be at least rank 1 when per_channel is "
5280 "true, but got rank ")
5281 << inputType.getRank();
5284 numChannels = inputType.getDimSize(inputType.getRank() - 1);
5287 if (outputType.hasRank()) {
5289 getOperation(), outputType, inputType.getShape())))
5293 if (multiplierType.hasRank()) {
5294 ArrayRef<int64_t> multiplierShape = multiplierType.getShape();
5296 if (multiplierShape[0] != ShapedType::kDynamic &&
5297 multiplierShape[0] != numChannels) {
5299 << numChannels <<
" } for multiplier input, got { "
5300 << multiplierShape[0] <<
" }";
5305 const auto shiftType = llvm::cast<ShapedType>(getShift().
getType());
5306 if (shiftType.hasRank()) {
5307 ArrayRef<int64_t> shiftShape = shiftType.getShape();
5309 if (shiftShape[0] != ShapedType::kDynamic && shiftShape[0] != numChannels) {
5311 << numChannels <<
" } for shift input, got { " << shiftShape[0]
5320LogicalResult RescaleOp::inferReturnTypeComponents(
5321 MLIRContext *context, ::std::optional<Location> location,
5322 RescaleOp::Adaptor adaptor,
5323 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5324 ShapeAdaptor inputShape(adaptor.getInput().getType());
5325 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5329LogicalResult CastOp::verify() {
5330 const ShapedType inputType = llvm::cast<ShapedType>(getInput().
getType());
5331 const ShapedType outputType = llvm::cast<ShapedType>(
getType());
5332 const Type inputElementType = inputType.getElementType();
5333 const Type outputElementType = outputType.getElementType();
5335 const bool inputIsBlockScaled = llvm::isa<BlockScaledType>(inputElementType);
5336 const bool outputIsBlockScaled =
5337 llvm::isa<BlockScaledType>(outputElementType);
5338 if (!inputIsBlockScaled && !outputIsBlockScaled)
5341 if (inputIsBlockScaled && outputIsBlockScaled)
5343 <<
"requires exactly one of input or output to have block scaled "
5346 const Type scalarElementType =
5347 inputIsBlockScaled ? outputElementType : inputElementType;
5348 if (!llvm::isa<FloatType>(scalarElementType))
5350 <<
"requires non-block-scaled element type to be floating-point "
5351 "when casting to or from block scaled element type, got "
5352 << scalarElementType;
5357LogicalResult CastFromBlockScaledOp::inferReturnTypeComponents(
5358 MLIRContext *context, ::std::optional<Location> location,
5359 CastFromBlockScaledOp::Adaptor adaptor,
5360 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5361 const ShapeAdaptor inputShape(adaptor.getInputData().getType());
5362 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5366LogicalResult CastFromBlockScaledOp::verify() {
5367 const Type inputDataType = getInputData().getType();
5368 const Type outputDataType = getResult().getType();
5370 return emitOpError() <<
"require compatible shapes for input_data ("
5371 << inputDataType <<
") and " <<
"output_data ("
5372 << outputDataType <<
")";
5374 const ShapeAdaptor inputDataShape = ShapeAdaptor(inputDataType);
5376 if (inputDataShape.
hasRank()) {
5377 const unsigned int blockSize =
5379 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
5380 return emitOpError(
"expect block size to be 32, got ") << blockSize;
5381 const int64_t inputDataLastDim =
5383 if (inputDataLastDim % blockSize != 0)
5384 return emitOpError() <<
"expect last dimension of input_data ("
5386 <<
") to be divisible by block_size (" << blockSize
5389 const Type inputScaleType = getInputScale().getType();
5390 const ShapeAdaptor inputScaleShape = ShapeAdaptor(inputScaleType);
5392 if (inputScaleShape.
hasRank()) {
5393 SmallVector<int64_t> inputDataDims, inputScaleDims;
5394 inputDataShape.
getDims(inputDataDims);
5395 inputScaleShape.
getDims(inputScaleDims);
5397 if (inputDataDims.size() != inputScaleDims.size() ||
5399 ArrayRef<int64_t>(inputDataDims).drop_back(1),
5400 ArrayRef<int64_t>(inputScaleDims).drop_back(1))))
5402 <<
"require compatible shapes for input_data (" << inputDataType
5403 <<
") and " <<
"input_scale (" << inputScaleType
5404 <<
") except for the last dimension";
5406 const SmallVector<int64_t, 2> dimsToCheck{inputDataLastDim / blockSize,
5407 inputScaleDims.back()};
5408 if (ShapedType::isStatic(inputDataLastDim) &&
5411 <<
"expect last dimension of input_scale ("
5412 << inputScaleDims.back()
5413 <<
") to be equal to last dimension of input_data / block_size ("
5414 << inputDataDims.back() / blockSize <<
")";
5421LogicalResult CastToBlockScaledOp::inferReturnTypeComponents(
5422 MLIRContext *context, ::std::optional<Location> location,
5423 CastToBlockScaledOp::Adaptor adaptor,
5424 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5425 const ShapeAdaptor inputShape(adaptor.getInputData().getType());
5426 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5427 if (!inputShape.hasRank())
5431 SmallVector<int64_t> outputScaleShape;
5432 inputShape.getDims(outputScaleShape);
5433 const int64_t lastDimLoc = inputShape.getRank() - 1;
5434 const int64_t lastDimSize = inputShape.getDimSize(lastDimLoc);
5435 if (ShapedType::isStatic(lastDimSize)) {
5436 const unsigned int blockSize =
5437 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
5438 outputScaleShape[lastDimLoc] = lastDimSize / blockSize;
5440 inferredReturnShapes.push_back(ShapedTypeComponents(outputScaleShape));
5444LogicalResult CastToBlockScaledOp::verify() {
5445 const Type inputDataType = getInputData().getType();
5446 const Type outputDataType = getResult(0).getType();
5448 return emitOpError() <<
"require compatible shapes for input_data ("
5449 << inputDataType <<
") and " <<
"output_data ("
5450 << outputDataType <<
")";
5452 const unsigned int blockSize =
5454 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
5455 return emitOpError(
"expect block size to be 32, got ") << blockSize;
5456 const ShapeAdaptor inputDataShape = ShapeAdaptor(inputDataType);
5457 if (inputDataShape.
hasRank()) {
5458 const int64_t inputDataLastDim =
5460 if (ShapedType::isStatic(inputDataLastDim) &&
5461 inputDataLastDim % blockSize != 0)
5462 return emitOpError() <<
"expect last dimension of input_data ("
5464 <<
") to be divisible by block_size (" << blockSize
5468 const ShapeAdaptor outputDataShape = ShapeAdaptor(outputDataType);
5469 const Type outputScaleType = getResult(1).getType();
5470 const ShapeAdaptor outputScaleShape = ShapeAdaptor(outputScaleType);
5472 SmallVector<int64_t> outputDataDims, outputScaleDims;
5473 outputDataShape.
getDims(outputDataDims);
5474 outputScaleShape.
getDims(outputScaleDims);
5476 if (outputDataDims.size() != outputScaleDims.size() ||
5478 ArrayRef<int64_t>(outputDataDims).drop_back(1),
5479 ArrayRef<int64_t>(outputScaleDims).drop_back(1))))
5480 return emitOpError() <<
"require compatible shapes for output_data ("
5481 << outputDataType <<
") and " <<
"output_scale ("
5483 <<
") except for the last dimension";
5485 const int64_t outputDataLastDim = outputDataDims.back();
5486 const SmallVector<int64_t, 2> dimsToCheck{outputDataLastDim / blockSize,
5487 outputScaleDims.back()};
5488 if (ShapedType::isStatic(outputDataLastDim) &&
5491 <<
"expect last dimension of output_scale ("
5492 << outputScaleDims.back()
5493 <<
") to be equal to last dimension of output_data / block_size ("
5494 << outputDataDims.back() / blockSize <<
")";
5500LogicalResult IfOp::inferReturnTypeComponents(
5501 MLIRContext *context, ::std::optional<Location> location,
5502 IfOp::Adaptor adaptor,
5503 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5504 llvm::SmallVector<tosa::YieldOp> yieldOps;
5505 for (Region *region : adaptor.getRegions()) {
5506 for (
auto &block : *region)
5507 if (
auto returnOp = dyn_cast<tosa::YieldOp>(block.getTerminator()))
5508 yieldOps.push_back(returnOp);
5511 if (yieldOps.empty())
5515 llvm::SmallVector<ValueKnowledge> resultKnowledge;
5516 resultKnowledge.reserve(yieldOps.front().getNumOperands());
5517 for (
auto operand : yieldOps.front().getOperands()) {
5518 resultKnowledge.push_back(
5522 for (
auto yieldOp : yieldOps) {
5523 if (resultKnowledge.size() != yieldOp.getNumOperands())
5526 for (
const auto &it : llvm::enumerate(yieldOp.getOperands())) {
5527 int32_t index = it.index();
5529 resultKnowledge[index],
5533 resultKnowledge[index] = meet;
5537 for (
const ValueKnowledge &
result : resultKnowledge) {
5538 inferredReturnShapes.push_back(
result.getShapedTypeComponents());
5544LogicalResult WhileOp::inferReturnTypeComponents(
5545 MLIRContext *context, ::std::optional<Location> location,
5546 WhileOp::Adaptor adaptor,
5547 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5548 llvm::SmallVector<tosa::YieldOp> yieldOps;
5549 for (
auto &block : adaptor.getBodyGraph())
5550 if (
auto returnOp = dyn_cast<tosa::YieldOp>(block.getTerminator()))
5551 yieldOps.push_back(returnOp);
5555 if (yieldOps.empty())
5559 llvm::SmallVector<ValueKnowledge> resultKnowledge;
5560 resultKnowledge.reserve(yieldOps.front().getNumOperands());
5561 for (
auto operand : yieldOps.front().getOperands()) {
5562 resultKnowledge.push_back(
5566 for (
auto yieldOp : yieldOps) {
5567 if (resultKnowledge.size() != yieldOp.getNumOperands())
5570 for (
const auto &it : llvm::enumerate(yieldOp.getOperands())) {
5571 int32_t index = it.index();
5573 resultKnowledge[index],
5575 resultKnowledge[index] = meet;
5580 for (
const ValueKnowledge &
result : resultKnowledge) {
5581 inferredReturnShapes.push_back(
result.getShapedTypeComponents());
5587std::optional<SmallVector<int64_t, 4>> ApplyScaleOp::getShapeForUnroll() {
5588 if (
auto vt = llvm::dyn_cast<VectorType>(
getType()))
5589 return llvm::to_vector<4>(vt.getShape());
5590 return std::nullopt;
5596 StringRef prefix =
"") {
5597 assert(blocksArgs.size() == initializers.size() &&
5598 "expected same length of arguments and initializers");
5599 if (initializers.empty())
5602 parser << prefix <<
'(';
5603 llvm::interleaveComma(
5604 llvm::zip(blocksArgs, initializers), parser,
5605 [&](
auto it) { parser << std::get<0>(it) <<
" = " << std::get<1>(it); });
5610ParseResult IfOp::parse(OpAsmParser &parser, OperationState &
result) {
5612 result.regions.reserve(2);
5613 Region *thenRegion =
result.addRegion();
5614 Region *elseRegion =
result.addRegion();
5616 OpAsmParser::UnresolvedOperand cond;
5621 SmallVector<OpAsmParser::Argument, 4> regionArgs;
5622 SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
5625 OptionalParseResult listResult =
5633 "expected type for condition operand");
5639 "expected type for condition operand");
5647 FunctionType functionType;
5651 <<
"expected list of types for block arguments "
5652 <<
"followed by arrow type and list of return types";
5654 result.addTypes(functionType.getResults());
5656 if (functionType.getNumInputs() != operands.size()) {
5658 <<
"expected as many input types as operands " <<
"(expected "
5659 << operands.size() <<
" got " << functionType.getNumInputs()
5690void IfOp::print(OpAsmPrinter &p) {
5691 p <<
" " << getCondition();
5694 getInputList(),
" ");
5696 p << getCondition().getType();
5698 if (!getInputList().empty()) {
5700 llvm::interleaveComma(getInputList().getTypes(), p);
5709 auto &elseRegion = getElseGraph();
5710 if (!elseRegion.
empty()) {
5718LogicalResult IfOp::verify() {
5720 "'then_graph' arguments", getInputList(),
5726 "'else_graph' arguments", getInputList(),
5732 if (getThenGraph().front().mightHaveTerminator()) {
5734 dyn_cast<tosa::YieldOp>(getThenGraph().front().getTerminator());
5736 *
this, thenYield.getInputs(),
"'then_graph' results",
5737 getOutputList(),
"'output_list'")
5743 if (getElseGraph().front().mightHaveTerminator()) {
5745 dyn_cast<tosa::YieldOp>(getElseGraph().front().getTerminator());
5747 *
this, elseYield.getInputs(),
"'else_graph' results",
5748 getOutputList(),
"'output_list'")
5753 auto condType = getCondition().getType();
5755 return emitOpError() <<
"'condition' must be a size 1 tensor, got "
5761LogicalResult WhileOp::verify() {
5763 getOutputList(),
"'output_list'")
5768 "'cond_graph' arguments", getInputList(),
5774 "'body_graph' arguments", getInputList(),
5779 if (getBodyGraph().front().mightHaveTerminator()) {
5781 dyn_cast<tosa::YieldOp>(getBodyGraph().front().getTerminator());
5783 "'body_graph' results",
5784 getInputList(),
"'input_list'")
5791 if (!getCondGraph().front().mightHaveTerminator())
5795 dyn_cast<tosa::YieldOp>(getCondGraph().front().getTerminator());
5799 if (condYield.getInputs().size() != 1)
5800 return emitOpError() <<
"require 'cond_graph' only have one result";
5802 auto condOutType = condYield.getInputs()[0].getType();
5804 return emitOpError() <<
"'cond_graph' result must be a size 1 tensor, got "
5808 return emitOpError() <<
"'cond_graph' result must be a boolean tensor, got "
5814LogicalResult ReverseOp::verify() {
5815 TensorType inputType = getInput1().getType();
5816 int32_t reverseAxis = getAxis();
5818 if (reverseAxis < 0)
5819 return emitOpError(
"expected non-negative reverse axis");
5821 int64_t inputRank = inputType.getRank();
5824 if (reverseAxis >= inputRank && (reverseAxis != 0 || inputRank != 0))
5826 << inputRank <<
") to be larger than reverse axis (" << reverseAxis
5833LogicalResult tosa::SelectOp::verify() {
5844 auto predicateType = llvm::dyn_cast<ShapedType>(getPred().
getType());
5845 if (!predicateType) {
5846 return emitOpError(
"expect shaped tensor for input1, got ")
5847 << getInput1().getType();
5849 auto predicateElementType = predicateType.getElementType();
5850 if (!predicateElementType.isInteger(1)) {
5851 return emitOpError(
"expect element type of bool for input1, got ")
5852 << predicateElementType;
5858LogicalResult tosa::VariableReadOp::verify() {
5866LogicalResult tosa::VariableWriteOp::verify() {
5875ParseResult WhileOp::parse(OpAsmParser &parser, OperationState &
result) {
5876 SmallVector<OpAsmParser::Argument, 4> regionArgs;
5877 SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
5878 Region *cond =
result.addRegion();
5879 Region *body =
result.addRegion();
5881 OptionalParseResult listResult =
5886 FunctionType functionType;
5891 result.addTypes(functionType.getResults());
5893 if (functionType.getNumInputs() != operands.size()) {
5895 <<
"expected as many input types as operands " <<
"(expected "
5896 << operands.size() <<
" got " << functionType.getNumInputs() <<
")";
5906 for (
size_t i = 0, e = regionArgs.size(); i != e; ++i)
5907 regionArgs[i].type = functionType.getInput(i);
5909 return failure(parser.
parseRegion(*cond, regionArgs) ||
5914void WhileOp::print(OpAsmPrinter &parser) {
5916 getInputList(),
" ");
5919 getResults().getTypes());
5933 auto zpType = mlir::RankedTensorType::get({1}, srcElemType);
5934 if (llvm::isa<FloatType>(srcElemType)) {
5936 zpType, builder.
getFloatAttr(srcElemType,
static_cast<double>(zp)));
5937 return tosa::ConstOp::create(builder, loc, zpType, zpAttr);
5939 if (llvm::isa<IntegerType>(srcElemType)) {
5942 return tosa::ConstOp::create(builder, loc, zpType, zpAttr);
5944 llvm::errs() <<
"zero point is not allowed for unsupported data types\n";
5945 return std::nullopt;
5953 return mlir::isa<tosa::shapeType>(t);
5960 return emitError() <<
"invalid rank (must be >= 0): " << rank;
5966 if (mlir::isa<::mlir::tosa::shapeType>(v.getType())) {
5967 Operation *definingOp = v.getDefiningOp();
5969 return op->
emitOpError(
"shape operand is not compile time resolvable");
5982 auto getRank = [](
const Type type) {
5983 return mlir::cast<mlir::tosa::shapeType>(type).getRank();
5989 for (
auto type : operandTypes) {
5990 if (getRank(type) != rank) {
5991 return op->
emitOpError(
"operands don't have matching ranks");
5994 for (
auto type : resultTypes) {
5995 if (getRank(type) != rank) {
5996 return op->
emitOpError(
"result shape has different rank than operands");
6006LogicalResult tosa::ConstShapeOp::verify() {
6008 auto valuesRank = getValues().getType().getRank();
6009 if (valuesRank != 1)
6010 return emitOpError(
"expect elements in attribute values with rank 1");
6012 auto count = getValues().getNumElements();
6013 auto rank = (cast<tosa::shapeType>(getResult().
getType())).getRank();
6014 if (count != rank && (count != 1 || rank != 0)) {
6015 return emitOpError(
"expect number of elements in attribute values (")
6016 << count <<
") to be equal to the rank (" << rank
6017 <<
") for the result shape type";
6022LogicalResult tosa::DimOp::verify() {
6023 const tosa::shapeType outShapeType =
6024 cast<tosa::shapeType>(getResult().
getType());
6025 if (outShapeType.getRank() != 1)
6026 return emitOpError(
"expect output shape type to contain one element, got ")
6031 const int64_t inputRank = inputType.getRank();
6032 const int64_t axis = getAxisAttr().getInt();
6033 if (axis < 0 || axis >= inputRank)
6034 return emitOpError(
"expect axis to be in the range [0, ")
6035 << inputRank <<
"), got " << axis;
6040LogicalResult tosa::ConcatShapeOp::verify() {
6041 const tosa::shapeType outShapeType =
6042 cast<tosa::shapeType>(getResult().
getType());
6043 const int64_t outputRank = outShapeType.getRank();
6046 if (inputList.size() == 0)
6047 return emitOpError(
"requires at least one input shape");
6049 if (llvm::any_of(inputList, [](Value v) {
6050 return cast<tosa::shapeType>(v.
getType()).getRank() == 0;
6052 return emitOpError(
"requires all inputs shapes have a rank greater than 0");
6054 const int64_t inputsRank =
6055 llvm::accumulate(inputList, 0, [](int64_t acc,
const Value &input) {
6056 const tosa::shapeType inShapeType =
6057 cast<tosa::shapeType>(input.
getType());
6058 return acc + inShapeType.getRank();
6060 if (outputRank != inputsRank)
6061 return emitOpError(
"requires output shape rank to be equal to the sum of "
6062 "the input shape ranks (")
6063 << inputsRank <<
"), got " << outputRank;
6068LogicalResult tosa::SliceShapeOp::verify() {
6069 std::optional<int32_t> start;
6070 DenseIntElementsAttr startAttr;
6072 start = startAttr.getValues<int32_t>()[0];
6073 if (start && start.value() < 0)
6074 return emitOpError(
"expected non-negative start index, got ")
6077 std::optional<int32_t> size;
6078 DenseIntElementsAttr sizeAttr;
6080 size = sizeAttr.getValues<int32_t>()[0];
6081 if (size && size.value() <= 0)
6082 return emitOpError(
"expected positive size, got ") << size.value();
6087 const tosa::shapeType outShapeType =
6088 cast<tosa::shapeType>(getResult().
getType());
6089 const int64_t outputRank = outShapeType.getRank();
6090 if (outputRank != size)
6092 "expected output type size to be equal to size attribute, got ")
6093 << outputRank <<
" vs " << size.value();
6098 const tosa::shapeType inShapeType =
6099 cast<tosa::shapeType>(getInput().
getType());
6100 const int64_t inputRank = inShapeType.getRank();
6101 const int64_t sliceSize = start.value() + size.value();
6102 if (sliceSize > inputRank)
6103 return emitOpError(
"expected start + size to be less than or equal to "
6104 "input shape rank (")
6105 << inputRank <<
"), got " << sliceSize;
6114#define GET_ATTRDEF_CLASSES
6115#include "mlir/Dialect/Tosa/IR/TosaAttributes.cpp.inc"
6120#define GET_TYPEDEF_CLASSES
6121#include "mlir/Dialect/Tosa/IR/TosaOpsTypesBase.cpp.inc"
6127#define GET_OP_CLASSES
6128#include "mlir/Dialect/Tosa/IR/TosaOps.cpp.inc"
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
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 std::string diag(const llvm::Value &value)
static Type getValueType(Attribute attr)
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")
LogicalResult inferConvReturnTypeComponents(AdaptorT adaptor, SmallVectorImpl< ShapedTypeComponents > &inferredReturnShapes)
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 LogicalResult errorIfShapeNotSizeOne(Operation *op, Type type)
static LogicalResult verifyMatMulZeroPointType(T op, Value input, Value zp, StringRef inputName, StringRef zpName)
static ParseResult parseScaleValues(AsmParser &parser, SmallVector< Attribute > &scaleValues, Type scaleType)
#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.
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 verifyConvOpModes(T op)
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 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 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 void buildMatMulTOpWithQuantInfo(OpBuilder &builder, OperationState &result, Type outputType, Value a, Value b)
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 parseOptionalRBrace()=0
Parse a } token if present.
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 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 parseRBrace()=0
Parse a } token.
virtual ParseResult parseEqual()=0
Parse a = token.
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 parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=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.
virtual ParseResult parseOptionalLBrace()=0
Parse a { token if present.
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
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.
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.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
NamedAttribute represents a combination of a name and an Attribute value.
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
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...
void printOperands(const ContainerType &container)
Print a comma separated list of operands.
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.
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
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.
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...
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)
LogicalResult verifyBlockScaledTensorType(mlir::Type type, bool allowScaleValues)
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)
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)