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/TosaAvailability.cpp.inc"
48#include "mlir/Dialect/Tosa/IR/TosaEnums.cpp.inc"
49#include "mlir/Dialect/Tosa/IR/TosaInterfaces.cpp.inc"
50#include "mlir/Dialect/Tosa/IR/TosaOpAvailabilityImpl.inc"
53#include "mlir/Dialect/Tosa/IR/TosaDialectBytecode.cpp.inc"
58struct TosaInlinerInterface :
public DialectInlinerInterface {
59 using DialectInlinerInterface::DialectInlinerInterface;
67 IRMapping &map)
const final {
73 IRMapping &map)
const final {
74 return (isa<tosa::IfOp>(dest->getParentOp()) ||
75 isa<tosa::WhileOp>(dest->getParentOp()));
80struct TosaDialectBytecodeInterface :
public BytecodeDialectInterface {
81 TosaDialectBytecodeInterface(Dialect *dialect)
82 : BytecodeDialectInterface(dialect) {}
87 Attribute readAttribute(DialectBytecodeReader &reader)
const override {
91 LogicalResult writeAttribute(Attribute attr,
92 DialectBytecodeWriter &writer)
const override {
93 return ::writeAttribute(attr, writer);
99 Type readType(DialectBytecodeReader &reader)
const override {
103 LogicalResult writeType(Type type,
104 DialectBytecodeWriter &writer)
const override {
105 return ::writeType(type, writer);
108 void writeVersion(DialectBytecodeWriter &writer)
const final {
112 std::unique_ptr<DialectVersion>
113 readVersion(DialectBytecodeReader &reader)
const final {
115 reader.
emitError(
"Dialect does not support versioning");
119 LogicalResult upgradeFromVersion(Operation *topLevelOp,
120 const DialectVersion &version)
const final {
133 return {&getBodyGraph()};
142 return dim == -1 ? ShapedType::kDynamic : dim;
148 Type elementType = variableOp.getType();
151 return RankedTensorType::get(
shape, elementType);
158void TosaDialect::initialize() {
160#define GET_TYPEDEF_LIST
161#include "mlir/Dialect/Tosa/IR/TosaOpsTypesBase.cpp.inc"
165#include "mlir/Dialect/Tosa/IR/TosaOps.cpp.inc"
168#define GET_ATTRDEF_LIST
169#include "mlir/Dialect/Tosa/IR/TosaAttributes.cpp.inc"
171 addInterfaces<TosaDialectBytecodeInterface, TosaInlinerInterface>();
172 declarePromisedInterfaces<
173 shard::ShardingInterface, ClampOp, SigmoidOp, TanhOp, AddOp,
174 ArithmeticRightShiftOp, BitwiseAndOp, BitwiseOrOp, BitwiseXorOp, IntDivOp,
175 LogicalAndOp, LogicalLeftShiftOp, LogicalRightShiftOp, LogicalOrOp,
176 LogicalXorOp, MaximumOp, MinimumOp, MulOp, PowOp, SubOp, AbsOp,
177 BitwiseNotOp, CeilOp, ClzOp, ExpOp, FloorOp, LogOp, LogicalNotOp,
178 NegateOp, ReciprocalOp, RsqrtOp, SelectOp, EqualOp, GreaterOp,
179 GreaterEqualOp, MatMulOp>();
186 if (llvm::isa<shapeType>(type) && llvm::isa<DenseIntElementsAttr>(value)) {
187 return tosa::ConstShapeOp::create(builder, loc, type,
188 llvm::cast<DenseIntElementsAttr>(value));
190 if (llvm::isa<ElementsAttr>(value))
191 return tosa::ConstOp::create(builder, loc, type,
192 llvm::cast<ElementsAttr>(value));
202ParseResult getShapeAndElementType(
OpAsmParser &parser,
Type parsedType,
204 TypeAttr &typeAttr) {
205 if (
auto shapedType = dyn_cast<ShapedType>(parsedType)) {
206 if (!shapedType.hasRank())
208 <<
"expected ranked type";
210 auto elementType = shapedType.getElementType();
211 typeAttr = TypeAttr::get(elementType);
218 <<
"expected shaped type";
235 <<
"expected attribute";
237 if (
auto typedAttr = dyn_cast<TypedAttr>(initialValueAttr)) {
238 return getShapeAndElementType(parser, typedAttr.getType(), varShapeAttr,
242 <<
"expected Typed attr";
245 initialValueAttr =
nullptr;
249 <<
"expected type after colon";
251 return getShapeAndElementType(parser, parsedType, varShapeAttr, typeAttr);
256 TypeAttr typeAttr,
Attribute initialValueAttr) {
257 bool needsSpace =
false;
258 if (!dyn_cast_or_null<TypedAttr>(initialValueAttr)) {
261 Type elementType = typeAttr.getValue();
262 RankedTensorType tensorType =
264 auto tensorTypeAttr = TypeAttr::get(tensorType);
269 if (initialValueAttr) {
280template <
typename EnumType>
281ParseResult parseAttrEntryWithEnumHandling(
OpAsmParser &parser,
283 llvm::StringRef name;
290 if constexpr (std::is_same_v<EnumType, tosa::RoundingMode>) {
291 if (name ==
"rounding_mode" &&
293 auto sym = symbolizeRoundingMode(kw);
296 <<
"invalid rounding_mode value: " << kw;
297 auto attr = RoundingModeAttr::get(parser.
getContext(), sym.value());
303 if constexpr (std::is_same_v<EnumType, tosa::ResizeMode>) {
305 auto sym = symbolizeResizeMode(kw);
308 <<
"invalid resize mode value: " << kw;
309 auto attr = ResizeModeAttr::get(parser.
getContext(), sym.value());
316 if constexpr (std::is_same_v<EnumType, tosa::NanPropagationMode>) {
318 auto sym = symbolizeNanPropagationMode(kw);
321 <<
"invalid nan_mode value: " << kw;
322 auto attr = NanPropagationModeAttr::get(parser.
getContext(), sym.value());
329 if constexpr (std::is_same_v<EnumType, tosa::BlockSize>) {
331 auto sym = symbolizeBlockSize(kw);
334 <<
"invalid block_size value: " << kw;
335 auto attr = BlockSizeAttr::get(parser.
getContext(), sym.value());
347template <
typename EnumType>
352 [&]() { return parser.parseOperand(operands.emplace_back()); }))
360 if (parseAttrEntryWithEnumHandling<EnumType>(parser, attrs))
377 result.addTypes(fnTy.getResults());
378 result.addAttributes(attrs);
384 parser << namedAttr.
getName().strref() <<
" = ";
386 if (
auto roundingModeAttr = dyn_cast<tosa::RoundingModeAttr>(attr)) {
387 parser << roundingModeAttr.getValue();
388 }
else if (
auto resizeModeAttr = dyn_cast<tosa::ResizeModeAttr>(attr)) {
389 parser << resizeModeAttr.getValue();
390 }
else if (
auto nanPropagationModeAttr =
391 dyn_cast<tosa::NanPropagationModeAttr>(attr)) {
392 parser << nanPropagationModeAttr.getValue();
393 }
else if (
auto blockSizeAttr = dyn_cast<tosa::BlockSizeAttr>(attr)) {
394 parser << blockSizeAttr.getValue();
407 const auto kDefaultNanValue = NanPropagationMode::PROPAGATE;
409 if (
auto nanAttr = dyn_cast<NanPropagationModeAttr>(attr.getValue())) {
410 if (nanAttr.getValue() == kDefaultNanValue) {
412 toPrint.erase(attr.getName());
418 if (!toPrint.empty()) {
420 llvm::interleaveComma(toPrint, parser, [&](
const NamedAttribute namedAttr) {
421 printNamedAttr(parser, namedAttr);
437 llvm::interleaveComma(op->
getAttrs(), parser,
439 printNamedAttr(parser, namedAttr);
451 return parseWithEnumHandling<tosa::RoundingMode>(parser,
result);
455 printWithEnumHandling(parser, *
this);
459 return parseWithEnumHandling<tosa::RoundingMode>(parser,
result);
463 printWithEnumHandling(parser, *
this);
467 return parseWithEnumHandling<tosa::ResizeMode>(parser,
result);
471 printWithEnumHandling(parser, *
this);
475 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
479 printWithNanPropagationHandling(parser, *
this);
483 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
487 printWithNanPropagationHandling(parser, *
this);
490ParseResult MaxPool2dAdaptiveOp::parse(
OpAsmParser &parser,
492 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
496 printWithNanPropagationHandling(parser, *
this);
500 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
504 printWithNanPropagationHandling(parser, *
this);
508 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
512 printWithNanPropagationHandling(parser, *
this);
516 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
520 printWithNanPropagationHandling(parser, *
this);
524 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
528 printWithNanPropagationHandling(parser, *
this);
532 return parseWithEnumHandling<tosa::NanPropagationMode>(parser,
result);
536 printWithNanPropagationHandling(parser, *
this);
539ParseResult MatmulTBlockScaledOp::parse(
OpAsmParser &parser,
541 return parseWithEnumHandling<tosa::BlockSize>(parser,
result);
545 printWithEnumHandling(parser, *
this);
548ParseResult CastFromBlockScaledOp::parse(
OpAsmParser &parser,
550 return parseWithEnumHandling<tosa::BlockSize>(parser,
result);
553void CastFromBlockScaledOp::print(
OpAsmPrinter &parser) {
554 printWithEnumHandling(parser, *
this);
557ParseResult CastToBlockScaledOp::parse(
OpAsmParser &parser,
559 return parseWithEnumHandling<tosa::BlockSize>(parser,
result);
563 printWithEnumHandling(parser, *
this);
566ParseResult Conv2DBlockScaledOp::parse(
OpAsmParser &parser,
568 return parseWithEnumHandling<tosa::BlockSize>(parser,
result);
572 printWithEnumHandling(parser, *
this);
587 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(srcType))
597 Value valZp, StringRef name) {
602 mlir::isa<IntegerType>(eType) && mlir::isa<IntegerType>(eZpType);
606 if (!bothInts || !sameBitWidth) {
608 <<
"expected " << name <<
" and " << name
609 <<
"_zp to both be integer of the same bitwidth, but got " << eType
610 <<
" vs. " << eZpType;
617 Value src, int32_t val) {
620 const auto padConstType = mlir::RankedTensorType::get({1}, srcType);
621 const auto padConstEType = mlir::RankedTensorType::get({1}, srcElemType);
622 const auto padConstAttr{
623 llvm::isa<FloatType>(srcElemType)
628 return tosa::ConstOp::create(builder, loc, padConstType, padConstAttr);
632 if (
auto blockScaledTy = dyn_cast<tosa::BlockScaledType>(type))
634 if (dyn_cast<tosa::mxint8Type>(type))
643 const StringRef operandName,
644 const StringRef dimName) {
645 if (ShapedType::isDynamic(currDim)) {
648 }
else if (ShapedType::isStatic(newDim) && currDim != newDim) {
650 << dimName <<
" of " << operandName <<
" to match size " << currDim
651 <<
", got " << newDim;
658 auto printDim = [&](
int64_t dim) {
659 if (ShapedType::isDynamic(dim))
665 llvm::interleaveComma(
shape,
diag, printDim);
671 StringRef outputName =
"output") {
672 assert(outputType.hasRank() &&
"expected output type to be ranked");
678 diag << outputName <<
" shape ";
680 diag <<
" to be compatible with inferred shape ";
688 const int64_t stride,
const int64_t dilation,
const llvm::StringRef dimName,
689 const llvm::StringRef dimAxis,
const llvm::StringRef padBeforeName,
690 const llvm::StringRef padAfterName) {
691 if (inputSize == ShapedType::kDynamic || kernelSize == ShapedType::kDynamic)
696 const std::optional<int64_t> calculatedOutSizeMinusOne =
idivCheck(
697 inputSize - 1 + padBefore + padAfter - (kernelSize - 1) * dilation,
699 if (!calculatedOutSizeMinusOne.has_value())
701 << dimName <<
" - 1 + pad_" << padBeforeName <<
" + pad_"
702 << padAfterName <<
" - (kernel_" << dimName <<
" - 1) * dilation_"
703 << dimAxis <<
" to be wholly divisible by stride_" << dimAxis
704 <<
", got (" << inputSize <<
" - 1 + " << padBefore <<
" + "
705 << padAfter <<
" - (" << kernelSize <<
" - 1) * " << dilation
708 const int64_t calculatedOutSize = calculatedOutSizeMinusOne.value() + 1;
709 if (outputSize != ShapedType::kDynamic && calculatedOutSize != outputSize)
711 << dimName <<
" did not match expected: "
712 <<
"calculated=" << calculatedOutSize <<
", expected=" << outputSize;
720size_t mlir::tosa::mxint8Type::getDenseElementBitSize()
const {
return 8; }
723mlir::tosa::mxint8Type::convertToAttribute(
ArrayRef<char> rawData)
const {
724 assert(rawData.size() == 1 &&
"expected 1 byte for tosa.mxint8 element");
725 const auto intType = IntegerType::get(
getContext(), 8);
726 return intType.convertToAttribute(rawData);
729LogicalResult mlir::tosa::mxint8Type::convertFromAttribute(
731 const auto intAttr = dyn_cast<IntegerAttr>(attr);
734 const Type attrType = intAttr.getType();
737 return cast<IntegerType>(attrType).convertFromAttribute(attr,
result);
745 bool allowScaleValues) {
746 const auto tensorType = llvm::cast<ShapedType>(type);
747 const BlockScaledType elemType =
748 llvm::dyn_cast<BlockScaledType>(tensorType.getElementType());
752 if (!allowScaleValues && elemType.hasScaleValues())
755 if (!tensorType.hasRank())
758 if (tensorType.getRank() == 0)
762 const uint32_t blockSize =
763 BlockShapeAttr::getBlockShapeValue(elemType.getBlockShape());
765 if (allowScaleValues && elemType.hasScaleValues() &&
766 tensorType.hasStaticShape()) {
767 const size_t numBlocks = tensorType.getNumElements() / blockSize;
768 if (elemType.getScaleValues().size() != numBlocks)
772 const int64_t blockedDimension = tensorShape.back();
773 if (ShapedType::isDynamic(blockedDimension))
775 if (blockedDimension % blockSize != 0)
784 const auto parseScaleValue = [&]() -> ParseResult {
791 if (floatValue < 0.0)
792 return parser.
emitError(loc,
"scale value must be non-negative, got ")
795 Type attrType = scaleType;
799 if (attrType != scaleType)
800 return parser.
emitError(loc,
"parsed attribute type ")
801 << attrType <<
" does not match expected scale type " << scaleType;
803 scaleValues.push_back(FloatAttr::get(attrType, floatValue));
812 llvm::interleaveComma(scaleValues, printer, [&](
Attribute scaleValue) {
817size_t mlir::tosa::BlockScaledType::getDenseElementBitSize()
const {
819 if (isa<tosa::mxint8Type>(valueType))
825mlir::tosa::BlockScaledType::convertToAttribute(
ArrayRef<char> rawData)
const {
829 assert(rawData.size() == 1 &&
"expected 1 byte for block_scaled element");
831 if (
const auto mxint8Value = dyn_cast<tosa::mxint8Type>(valueType))
832 return mxint8Value.convertToAttribute(rawData);
833 if (!isa<FloatType>(valueType))
838LogicalResult mlir::tosa::BlockScaledType::convertFromAttribute(
841 if (
const auto mxint8Value = dyn_cast<tosa::mxint8Type>(valueType))
842 return mxint8Value.convertFromAttribute(attr,
result);
844 const auto floatAttr = dyn_cast<FloatAttr>(attr);
845 if (!floatAttr || floatAttr.getType() != valueType)
858 const auto inputType = llvm::dyn_cast<TensorType>(op.getInput().getType());
859 const auto weightType = llvm::dyn_cast<TensorType>(op.getWeight().getType());
861 auto inputEType = inputType.getElementType();
862 auto weightEType = weightType.getElementType();
864 llvm::cast<ShapedType>(op.getBias().getType()).getElementType();
866 llvm::cast<ShapedType>(op.getResult().getType()).getElementType();
867 bool biasIsFloat = llvm::isa<FloatType>(biasEType);
868 bool resultIsFloat = llvm::isa<FloatType>(resultEType);
870 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(inputEType))
873 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(weightEType))
876 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(biasEType))
879 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(resultEType))
882 if (biasIsFloat && resultIsFloat && (biasEType != resultEType)) {
886 "expect both bias and result to have same element type, got ")
887 << biasEType <<
" and " << resultEType;
891 const bool isInputBlockScaled = llvm::isa<BlockScaledType>(inputEType);
892 const bool isWeightBlockScaled = llvm::isa<BlockScaledType>(weightEType);
893 const bool isInputFloat = llvm::isa<FloatType>(inputEType);
894 const bool isWeightFloat = llvm::isa<FloatType>(weightEType);
896 const bool isInputBSorFloat = isInputBlockScaled || isInputFloat;
897 const bool isWeightBSorFloat = isWeightBlockScaled || isWeightFloat;
900 if (isInputBSorFloat != isWeightBSorFloat) {
902 "expect both input and weight to be float or not together, got ")
903 << inputEType <<
" and " << weightEType;
908 if (!isInputBlockScaled && inputEType != inputZpEType) {
909 return op.emitOpError(
"expect both input and its zero point are the same "
910 "element type, got ")
911 << inputEType <<
" and " << inputZpEType;
913 if (isInputBlockScaled && !llvm::isa<Float32Type>(inputZpEType)) {
914 return op.emitOpError(
915 "expect block scaled input to have fp32 zero point, got ")
916 << inputEType <<
" and " << inputZpEType;
920 if (!isWeightBlockScaled && weightEType != weightZpEType) {
921 return op.emitOpError(
"expect both weight and its zero point are the same "
922 "element type, got ")
923 << weightEType <<
" and " << weightZpEType;
925 if (isWeightBlockScaled && !llvm::isa<Float32Type>(weightZpEType)) {
926 return op.emitOpError(
927 "expect block scaled weight to have fp32 zero point, got ")
928 << weightEType <<
" and " << weightZpEType;
931 FailureOr<int64_t> maybeIZp = op.getInputZeroPoint();
932 if (succeeded(maybeIZp) && op.verifyInputZeroPoint(*maybeIZp).failed())
935 FailureOr<int64_t> maybeWZp = op.getWeightZeroPoint();
936 if (succeeded(maybeWZp) && op.verifyWeightZeroPoint(*maybeWZp).failed())
942LogicalResult tosa::ConstOp::verify() {
944 auto attrType = llvm::dyn_cast<TensorType>(getValuesAttr().
getType());
945 auto outputType = llvm::dyn_cast<TensorType>(getOutput().
getType());
947 if (!attrType || !outputType) {
948 emitOpError(
"expected tensors for attr/result type");
952 const Type attrElemType = attrType.getElementType();
953 const Type resultElemType = outputType.getElementType();
956 llvm::dyn_cast<mlir::quant::QuantizedType>(resultElemType)) {
961 if (
auto attrBlockScaledType =
962 llvm::dyn_cast<mlir::tosa::BlockScaledType>(attrElemType)) {
963 if (!attrBlockScaledType.hasScaleValues())
965 "attribute block scaled type must have scale values");
968 return op.
emitOpError(
"block scaled attribute type is not valid, got ")
971 const BlockScaledType resultBlockScaledType =
972 llvm::dyn_cast<mlir::tosa::BlockScaledType>(resultElemType);
973 if (!resultBlockScaledType)
975 "result type must be block scaled type if attribute is block "
978 if (attrBlockScaledType.getValueType() !=
979 resultBlockScaledType.getValueType() ||
980 attrBlockScaledType.getScaleType() !=
981 resultBlockScaledType.getScaleType() ||
982 attrBlockScaledType.getBlockShape() !=
983 resultBlockScaledType.getBlockShape())
985 "expected block scaled element type to be compatible "
986 "between attr and result, got ")
987 << attrBlockScaledType <<
" vs. " << resultBlockScaledType;
992 if (attrElemType != resultElemType)
993 return emitOpError(
"expected same attr/result element types");
1001 llvm::cast<ShapedType>(op.getInput().getType()).getElementType();
1003 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(inputEType))
1007 llvm::cast<ShapedType>(op.getResult().getType()).getElementType();
1009 if (
auto quantType = llvm::dyn_cast<mlir::quant::QuantizedType>(resultEType))
1020template <
typename T>
1023 if (llvm::any_of(padding, [](
int64_t p) {
return p < 0; }))
1024 return op.emitOpError(
"expect all padding values to be >= 0, got ")
1028 if (llvm::any_of(strides, [](
int64_t s) {
return s < 1; }))
1029 return op.emitOpError(
"expect all stride values to be >= 1, got ")
1033 if (llvm::any_of(dilations, [](
int64_t d) {
return d < 1; }))
1034 return op.emitOpError(
"expect all dilation values to be >= 1, got ")
1037 const RankedTensorType outputType =
1038 llvm::dyn_cast<RankedTensorType>(op.getOutput().getType());
1043 const RankedTensorType inputType =
1044 llvm::dyn_cast<RankedTensorType>(op.getInput().getType());
1045 const RankedTensorType weightType =
1046 llvm::dyn_cast<RankedTensorType>(op.getWeight().getType());
1048 if (inputType && weightType) {
1050 if constexpr (std::is_same<T, tosa::Conv2DOp>::value) {
1052 op, inputType.getDimSize(1), weightType.getDimSize(1),
1053 outputType.getDimSize(1), padding[0], padding[1], strides[0],
1054 dilations[0],
"height",
"y",
"top",
"bottom")))
1058 op, inputType.getDimSize(2), weightType.getDimSize(2),
1059 outputType.getDimSize(2), padding[2], padding[3], strides[1],
1060 dilations[1],
"width",
"x",
"left",
"right")))
1065 if constexpr (std::is_same<T, tosa::DepthwiseConv2DOp>::value) {
1067 op, inputType.getDimSize(1), weightType.getDimSize(0),
1068 outputType.getDimSize(1), padding[0], padding[1], strides[0],
1069 dilations[0],
"height",
"y",
"top",
"bottom")))
1073 op, inputType.getDimSize(2), weightType.getDimSize(1),
1074 outputType.getDimSize(2), padding[2], padding[3], strides[1],
1075 dilations[1],
"width",
"x",
"left",
"right")))
1080 if constexpr (std::is_same<T, tosa::Conv3DOp>::value) {
1082 op, inputType.getDimSize(1), weightType.getDimSize(1),
1083 outputType.getDimSize(1), padding[0], padding[1], strides[0],
1084 dilations[0],
"depth",
"d",
"front",
"back")))
1088 op, inputType.getDimSize(2), weightType.getDimSize(2),
1089 outputType.getDimSize(2), padding[2], padding[3], strides[1],
1090 dilations[1],
"height",
"y",
"top",
"bottom")))
1094 op, inputType.getDimSize(3), weightType.getDimSize(3),
1095 outputType.getDimSize(3), padding[4], padding[5], strides[2],
1096 dilations[2],
"width",
"x",
"left",
"right")))
1101 const RankedTensorType biasType =
1102 llvm::dyn_cast<RankedTensorType>(op.getBias().getType());
1107 const int64_t biasChannels = biasType.getDimSize(0);
1108 const int64_t outputChannels =
1109 outputType.getDimSize(outputType.getRank() - 1);
1110 if (biasChannels == ShapedType::kDynamic ||
1111 outputChannels == ShapedType::kDynamic)
1115 if (biasChannels != outputChannels && biasChannels != 1)
1116 return op.emitOpError(
1117 "bias channels expected to be equal to output channels (")
1118 << outputChannels <<
") or 1, got " << biasChannels;
1125 StringRef name1,
Type type2,
1127 auto shapeType1 = dyn_cast<ShapedType>(type1);
1128 auto shapeType2 = dyn_cast<ShapedType>(type2);
1129 if (!shapeType1 || !shapeType2)
1132 auto elemType1 = shapeType1.getElementType();
1133 auto elemType2 = shapeType2.getElementType();
1134 if (elemType1 != elemType2)
1136 <<
"require same element type for " << name1 <<
" (" << elemType1
1137 <<
") and " << name2 <<
" (" << elemType2 <<
")";
1141 <<
"require same shapes for " << name1 <<
" (" << type1 <<
") and "
1142 << name2 <<
" (" << type2 <<
")";
1152 if (list1.size() != list2.size())
1154 <<
"require same number of values in " << name1 <<
" ("
1155 << list1.size() <<
") and " << name2 <<
" (" << list2.size() <<
")";
1157 for (
auto [type1, type2] :
1174template <
typename T>
1177 op->template getParentWithTrait<OpTrait::SymbolTable>();
1184 const auto varOp = symTable.
lookup<tosa::VariableOp>(op.getName());
1188 return op->emitOpError(
"'")
1189 << op.getName() <<
"' has not been declared by 'tosa.variable'";
1203 StringRef aName =
"input",
1204 StringRef bName =
"output") {
1205 auto aTType = llvm::dyn_cast<TensorType>(aType);
1206 auto bTType = llvm::dyn_cast<TensorType>(bType);
1208 op->
emitOpError(
"expect shaped tensor for") << aName <<
", got " << aType;
1212 op->
emitOpError(
"expect shaped tensor for") << bName <<
", got" << bType;
1215 auto aElementType = aTType.getElementType();
1216 auto bElementType = bTType.getElementType();
1218 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(aElementType);
1220 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(bElementType);
1221 if ((aElementType.isIntOrIndexOrFloat() || aQuantType) &&
1222 (bElementType.isIntOrIndexOrFloat() || bQuantType) &&
1223 aElementType != bElementType) {
1229 << aName <<
" and " << bName <<
" to have same element type, got "
1230 << aElementType <<
" and " << bElementType;
1236LogicalResult tosa::ArgMaxOp::verify() {
1237 const ShapedType resultType = llvm::cast<ShapedType>(
getType());
1240 if (
const auto resultETy = resultType.getElementType();
1241 !resultETy.isIntOrIndex())
1242 return emitOpError(
"result tensor is not of integer type");
1244 const auto inputType = llvm::cast<ShapedType>(getInput().
getType());
1245 if (!inputType.hasRank())
1249 const int64_t axis = getAxisAttr().getInt();
1250 if (((axis < 0) || axis >= inputType.getRank()))
1251 return emitOpError(
"specified axis is outside the rank of the tensor");
1253 if (!resultType.hasRank())
1259 expectedOutputShape.erase(expectedOutputShape.begin() + axis);
1262 << expectedOutputShape <<
"', got '" << outputShape <<
"'";
1275 const bool hasKernel = kernel.size() > 0;
1276 const bool hasStrides = strides.size() > 0;
1277 const bool hasPad = padding.size() > 0;
1279 if (hasKernel && llvm::any_of(kernel, [](
int64_t s) {
return s < 1; }))
1280 return op->
emitOpError(
"expect all kernel values to be >= 1, got ")
1283 if (hasStrides && llvm::any_of(strides, [](
int64_t s) {
return s < 1; }))
1284 return op->
emitOpError(
"expect all stride values to be >= 1, got ")
1287 if (hasPad && llvm::any_of(padding, [](
int64_t p) {
return p < 0; }))
1288 return op->
emitOpError(
"expect all padding values to be >= 0, got ")
1291 if (hasKernel && hasPad) {
1293 const int64_t kernelX = kernel[1];
1294 const int64_t padLeft = padding[2];
1295 const int64_t padRight = padding[3];
1296 if (padRight >= kernelX || padLeft >= kernelX)
1297 return op->
emitOpError(
"expected left/right padding to be less than the "
1298 "width of the kernel, got pad_left=")
1299 << padLeft <<
", pad_right=" << padRight
1300 <<
", kernel_x=" << kernelX;
1302 const int64_t kernelY = kernel[0];
1303 const int64_t padTop = padding[0];
1304 const int64_t padBottom = padding[1];
1305 if (padTop >= kernelY || padBottom >= kernelY)
1306 return op->
emitOpError(
"expected top/bottom padding to be less than the "
1307 "height of the kernel, got pad_top=")
1308 << padTop <<
", pad_bottom=" << padBottom
1309 <<
", kernel_y=" << kernelY;
1312 const auto inputType = llvm::dyn_cast<RankedTensorType>(input.
getType());
1313 const auto outputType = llvm::dyn_cast<RankedTensorType>(output.
getType());
1314 if (!inputType || !outputType)
1317 if (hasKernel && hasStrides && hasPad) {
1318 const auto verifyOutputSize =
1322 const llvm::StringRef dimName,
const llvm::StringRef dimAxis,
1323 const llvm::StringRef padBeforeName,
1324 const llvm::StringRef padAfterName) -> LogicalResult {
1325 if (ShapedType::isDynamic(inputSize))
1328 const std::optional<int64_t> calculatedOutSizeMinusOne =
1329 idivCheck(inputSize + padBefore + padAfter - kernelSize, strideSize);
1330 if (!calculatedOutSizeMinusOne.has_value())
1332 << dimName <<
" + pad_" << padBeforeName <<
" + pad_"
1333 << padAfterName <<
" - kernel_" << dimAxis
1334 <<
" to be wholly divisible by stride_" << dimAxis <<
", got ("
1335 << inputSize <<
" + " << padBefore <<
" + " << padAfter <<
" - "
1336 << kernelSize <<
") / " << strideSize;
1338 const int64_t calculatedOutSize = calculatedOutSizeMinusOne.value() + 1;
1339 if (ShapedType::isStatic(outputSize) && calculatedOutSize != outputSize)
1341 << dimName <<
" did not match expected: " <<
"calculated="
1342 << calculatedOutSize <<
", expected=" << outputSize;
1347 if (failed(verifyOutputSize(inputType.getDimSize(1),
1348 outputType.getDimSize(1), kernel[0], strides[0],
1349 padding[0], padding[1],
"height",
"y",
"top",
1353 if (failed(verifyOutputSize(
1354 inputType.getDimSize(2), outputType.getDimSize(2), kernel[1],
1355 strides[1], padding[2], padding[3],
"width",
"x",
"left",
"right")))
1361template <
typename T>
1364 op.getPad(), op.getInput(), op.getOutput());
1367template <
typename T>
1371 const Type inputZpETy =
1373 const Type outputZpETy =
1376 auto accType = op.getAccType();
1377 if (llvm::isa<IntegerType>(inputETy) && !accType.isInteger(32))
1378 return op.emitOpError(
"accumulator type for integer tensor is not i32");
1380 if (inputETy.
isF16() && !(accType.isF16() || accType.isF32()))
1381 return op.emitOpError(
"accumulator type for f16 tensor is not f16/f32");
1383 if (inputETy.
isBF16() && !accType.isF32())
1384 return op.emitOpError(
"accumulator type for bf16 tensor is not f32");
1386 if (inputETy.
isF32() && !accType.isF32())
1387 return op.emitOpError(
"accumulator type for f32 tensor is not f32");
1389 if (inputETy != inputZpETy)
1390 return op.emitOpError(
"expect both input and its zero point are the same "
1391 "element type, got ")
1392 << inputETy <<
" and " << inputZpETy;
1394 if (resultETy != outputZpETy)
1395 return op.emitOpError(
"expect both output and its zero point are the same "
1396 "element type, got ")
1397 << resultETy <<
" and " << outputZpETy;
1399 FailureOr<int64_t> maybeIZp = op.getInputZeroPoint();
1400 if (succeeded(maybeIZp) && op.verifyInputZeroPoint(*maybeIZp).failed())
1403 FailureOr<int64_t> maybeOZp = op.getOutputZeroPoint();
1404 if (succeeded(maybeOZp) && op.verifyOutputZeroPoint(*maybeOZp).failed())
1411struct AdaptivePoolingConstShapeValues {
1412 llvm::SmallVector<int64_t> kernel;
1413 llvm::SmallVector<int64_t> stride;
1414 llvm::SmallVector<int64_t> pad;
1418template <
typename T>
1420 std::is_same_v<T, tosa::AvgPool2dAdaptiveOp> ||
1421 std::is_same_v<T, tosa::MaxPool2dAdaptiveOp>;
1423template <
typename T,
1424 typename std::enable_if<IsSupportedAdaptivePoolConstShapeVerifyOp<T>,
1427 T op, AdaptivePoolingConstShapeValues &values) {
1433LogicalResult tosa::AvgPool2dOp::verify() {
1441LogicalResult tosa::AvgPool2dAdaptiveOp::verify() {
1442 AdaptivePoolingConstShapeValues values;
1451 values.pad, getInput(), getOutput())))
1460LogicalResult tosa::ClampOp::verify() {
1462 llvm::cast<ShapedType>(getInput().
getType()).getElementType();
1463 if (
auto quantType =
1464 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(inputETy)) {
1468 llvm::cast<ShapedType>(getOutput().
getType()).getElementType();
1469 if (
auto quantType =
1470 llvm::dyn_cast<mlir::quant::UniformQuantizedType>(outputETy)) {
1473 if (inputETy != outputETy)
1474 return emitOpError(
"input/output element types are incompatible.");
1476 auto maxValAttr = getMaxValAttr();
1477 auto minValAttr = getMinValAttr();
1481 if (inputETy.
isInteger(dataTypeBitWidth)) {
1485 auto intMaxValAttr = mlir::dyn_cast<mlir::IntegerAttr>(maxValAttr);
1486 auto intMinValAttr = mlir::dyn_cast<mlir::IntegerAttr>(minValAttr);
1487 if (!intMaxValAttr || !intMinValAttr ||
1488 (intMaxValAttr.getType() != intMinValAttr.getType()) ||
1489 (intMaxValAttr.getType() != inputETy))
1490 return emitOpError(
"min/max attributes types are incompatible with "
1491 "input/output element types.");
1494 const bool isBoolean = inputETy.
isInteger(1);
1495 const APInt minVal = intMinValAttr.getValue();
1496 const APInt maxVal = intMaxValAttr.getValue();
1497 if ((isUnsigned || isBoolean) ? maxVal.ult(minVal) : maxVal.slt(minVal))
1498 return emitOpError(
"expected min_val <= max_val, got min_val=")
1499 << minValAttr <<
", max_val=" << maxValAttr;
1504 auto floatMaxValAttr = mlir::dyn_cast<mlir::FloatAttr>(maxValAttr);
1505 auto floatMinValAttr = mlir::dyn_cast<mlir::FloatAttr>(minValAttr);
1506 if (!floatMaxValAttr || !floatMinValAttr ||
1507 (floatMaxValAttr.getType() != floatMinValAttr.getType()) ||
1508 (floatMaxValAttr.getType() != inputETy))
1509 return emitOpError(
"min/max attributes types are incompatible with "
1510 "input/output element types.");
1512 const APFloat minVal = floatMinValAttr.getValue();
1513 const APFloat maxVal = floatMaxValAttr.getValue();
1514 if (minVal.isNaN() || maxVal.isNaN())
1515 return emitOpError(
"min/max attributes should not be 'NaN', got min_val=")
1516 << minValAttr <<
", max_val=" << maxValAttr;
1518 if (maxVal < minVal)
1519 return emitOpError(
"expected min_val <= max_val, got min_val=")
1520 << minValAttr <<
", max_val=" << maxValAttr;
1540 result.addOperands({input, weight, bias, zps.first, zps.second});
1541 result.addAttribute(
"pad", pad);
1542 result.addAttribute(
"stride", stride);
1543 result.addAttribute(
"dilation", dilation);
1544 result.addAttribute(
"acc_type", accType);
1545 Type finalOutputType = outputType;
1551 result.addTypes(finalOutputType);
1562 result.addOperands({input, weight, bias, zps.first, zps.second});
1563 result.addAttribute(
"out_pad", outpad);
1564 result.addAttribute(
"stride", stride);
1565 result.addAttribute(
"acc_type", accType);
1566 Type finalOutputType = outputType;
1572 result.addTypes(finalOutputType);
1579 result.addOperands({a,
b, zps.first, zps.second});
1581 Type finalOutputType{outputType};
1584 auto inputBits = eType.getIntOrFloatBitWidth();
1586 auto outputShapedType = llvm::dyn_cast<ShapedType>(outputType);
1587 assert(outputShapedType &&
"Output must be a shaped type");
1589 IntegerType accElementType;
1590 if (inputBits == 16)
1595 finalOutputType = outputShapedType.clone(accElementType);
1597 result.addTypes(finalOutputType);
1618 DenseArrayAttr kernel, DenseArrayAttr stride,
1619 DenseArrayAttr pad, TypeAttr accType) {
1624 if (
auto quantAttr =
1626 inputZp = quantAttr.getInputZp();
1627 outputZp = quantAttr.getOutputZp();
1629 const std::optional<Value> inputZpOp =
1634 "Failed to create input zero point tensor for quantized AVG_POOL2D op");
1636 const std::optional<Value> outputZpOp =
1639 (
void)
emitError(loc,
"Failed to create output zero point tensor for "
1640 "quantized AVG_POOL2D op");
1643 if (inputZpOp && outputZpOp) {
1644 result.addOperands({input, inputZpOp.value(), outputZpOp.value()});
1649 result.addOperands({input});
1651 result.addAttribute(
"kernel", kernel);
1652 result.addAttribute(
"stride", stride);
1653 result.addAttribute(
"pad", pad);
1654 result.addAttribute(
"acc_type", accType);
1655 result.types.push_back(outputType);
1668 if (
auto quantAttr =
1670 inputZp = quantAttr.getInputZp();
1671 outputZp = quantAttr.getOutputZp();
1673 const std::optional<Value> inputZpOp =
1677 "Failed to create input zero point tensor for quantized "
1678 "AVG_POOL2D_ADAPTIVE op");
1680 const std::optional<Value> outputZpOp =
1683 (
void)
emitError(loc,
"Failed to create output zero point tensor for "
1684 "quantized AVG_POOL2D_ADAPTIVE op");
1687 if (inputZpOp && outputZpOp) {
1692 result.addOperands({input, inputZpOp.value(), outputZpOp.value(),
1693 kernelShape, strideShape, padShape});
1698 result.addOperands({input});
1700 result.addAttribute(
"acc_type", accType);
1701 result.types.push_back(outputType);
1715 input1Zp = quantAttr.getInputZp();
1716 outputZp = quantAttr.getOutputZp();
1718 const std::optional<Value> input1ZpOp =
1722 loc,
"Failed to create input1 zero point for quantized NEGATE op");
1725 const std::optional<Value> outputZpOp =
1729 loc,
"Failed to create output zero point for quantized NEGATE op");
1732 if (input1ZpOp && outputZpOp) {
1733 result.addOperands({input, input1ZpOp.value(), outputZpOp.value()});
1738 result.addOperands({input});
1741 result.types.push_back(outputType);
1754 zp =
static_cast<int32_t
>(quantAttr.getInputZp());
1757 result.addOperands({input, paddings, padConstOp});
1758 result.types.push_back(outputType);
1762 StringRef name,
Type variableType,
1767 auto shapedType = dyn_cast<ShapedType>(variableType);
1769 (
void)
emitError(loc,
"variable type must be a shaped type");
1772 if (!shapedType.hasRank()) {
1773 (
void)
emitError(loc,
"variable type must be a ranked type");
1777 auto elementType = shapedType.getElementType();
1778 auto elementTypeAttr = TypeAttr::get(elementType);
1782 result.addAttribute(
"sym_name", nameAttr);
1783 result.addAttribute(
"var_shape", varShapeAttr);
1784 result.addAttribute(
"type", elementTypeAttr);
1785 result.addAttribute(
"initial_value", initialValue);
1798 if (ShapedType::isStatic(dim1) && ShapedType::isStatic(dim2) && dim1 != dim2)
1802 return ShapedType::isDynamic(dim1) ? dim2 : dim1;
1808 for (
int i = 0, e = operands.size(); i != e; ++i) {
1810 if (!
shape.hasRank()) {
1815 outRank = std::max<int64_t>(outRank,
shape.getRank());
1818 outShape.resize(outRank, 1);
1820 for (
int i = 0, e = operands.size(); i != e; ++i) {
1822 auto rankDiff = outShape.size() -
shape.getRank();
1824 for (
size_t i = 0, e =
shape.getRank(); i < e; ++i) {
1825 auto dim1 = outShape[i + rankDiff];
1826 auto dim2 =
shape.getDimSize(i);
1828 const FailureOr<int64_t> maybeResolvedDim =
1830 if (failed(maybeResolvedDim))
1832 const int64_t resolvedDim = *maybeResolvedDim;
1833 outShape[i + rankDiff] = resolvedDim;
1840LogicalResult tosa::ArgMaxOp::inferReturnTypeComponents(
1841 MLIRContext *context, ::std::optional<Location> location,
1842 ArgMaxOp::Adaptor adaptor,
1845 IntegerAttr axis = adaptor.getProperties().axis;
1846 int32_t axisVal = axis.getValue().getSExtValue();
1848 if (!inputShape.hasRank()) {
1854 outShape.reserve(inputShape.getRank() - 1);
1855 for (
int i = 0, s = inputShape.getRank(); i < s; i++) {
1858 outShape.push_back(inputShape.getDimSize(i));
1865LogicalResult tosa::RFFT2dOp::inferReturnTypeComponents(
1866 MLIRContext *context, ::std::optional<Location> location,
1867 RFFT2dOp::Adaptor adaptor,
1869 ShapeAdaptor inputShape(adaptor.getInputReal().getType());
1871 if (!inputShape.hasRank())
1875 outputShape.resize(3, ShapedType::kDynamic);
1876 outputShape[0] = inputShape.getDimSize(0);
1877 outputShape[1] = inputShape.getDimSize(1);
1878 int64_t inWidth = inputShape.getDimSize(2);
1882 if (inWidth != ShapedType::kDynamic)
1883 outputShape[2] = inWidth / 2 + 1;
1892 const llvm::StringRef dimName) {
1893 const bool isPowerOfTwo = (dimSize & (dimSize - 1)) == 0 && dimSize > 0;
1896 << dimName <<
" to be a power of two, got " << dimSize;
1901LogicalResult tosa::RFFT2dOp::verify() {
1902 const auto outputTypes = getResultTypes();
1904 return emitOpError(
"expected output shapes to match, got ") << outputTypes;
1906 const auto inputType =
1907 llvm::dyn_cast<RankedTensorType>(getInputReal().
getType());
1911 const int64_t height = inputType.getDimSize(1);
1912 if (ShapedType::isStatic(height) &&
1916 const int64_t width = inputType.getDimSize(2);
1917 if (ShapedType::isStatic(width) &&
1921 const auto outputType = llvm::dyn_cast<RankedTensorType>(outputTypes[0]);
1927 outputType.getShape().drop_back())))
1928 return emitOpError(
"expected batch and height dimensions of input/output "
1929 "to match, got input=")
1930 << inputType <<
" output=" << outputType;
1933 const int64_t outputWidth = outputType.getDimSize(2);
1934 if (ShapedType::isStatic(width) && ShapedType::isStatic(outputWidth) &&
1935 (outputWidth != (width / 2) + 1))
1937 "expected output width to be equal to input_width / 2 + 1, got ")
1943LogicalResult tosa::FFT2dOp::inferReturnTypeComponents(
1944 MLIRContext *context, ::std::optional<Location> location,
1945 FFT2dOp::Adaptor adaptor,
1947 inferredReturnShapes.push_back(
1949 inferredReturnShapes.push_back(
1954LogicalResult tosa::FFT2dOp::verify() {
1955 const auto inputRealType =
1956 llvm::dyn_cast<RankedTensorType>(getInputReal().
getType());
1957 const auto inputImagType =
1958 llvm::dyn_cast<RankedTensorType>(getInputImag().
getType());
1959 if (!inputRealType || !inputImagType)
1962 const auto trySelectStaticDim = [](
const int64_t a,
const int64_t b) {
1963 return ShapedType::isDynamic(a) ? a :
b;
1966 const int64_t height = trySelectStaticDim(inputRealType.getDimSize(1),
1967 inputImagType.getDimSize(1));
1968 if (ShapedType::isStatic(height) &&
1972 const int64_t width = trySelectStaticDim(inputRealType.getDimSize(2),
1973 inputImagType.getDimSize(2));
1974 if (ShapedType::isStatic(width) &&
1981LogicalResult tosa::ConcatOp::inferReturnTypeComponents(
1982 MLIRContext *context, ::std::optional<Location> location,
1983 ConcatOp::Adaptor adaptor,
1986 const Properties &prop = adaptor.getProperties();
1987 int32_t axis = prop.axis.getValue().getSExtValue();
1989 bool hasRankedInput =
false;
1990 for (
auto operand : adaptor.getOperands()) {
1992 if (!operandShape.hasRank())
1996 if (!hasRankedInput)
1997 outputShape.resize(operandShape.getRank(), ShapedType::kDynamic);
2000 for (
int i = 0, s = operandShape.getRank(); i < s; i++) {
2001 if (i == axis || operandShape.isDynamicDim(i))
2003 if (outputShape[i] == ShapedType::kDynamic)
2004 outputShape[i] = operandShape.getDimSize(i);
2005 if (outputShape[i] != operandShape.getDimSize(i))
2007 "Cannot concat tensors with different sizes"
2008 " on the non-axis dimension ",
2012 hasRankedInput =
true;
2015 if (adaptor.getInput1().empty())
2019 llvm::cast<TensorType>(adaptor.getInput1().getType()[0]).getElementType();
2020 if (!hasRankedInput) {
2027 for (
auto operand : adaptor.getOperands()) {
2032 if (!operandShape.hasRank() || operandShape.isDynamicDim(axis)) {
2033 concatDimSize = ShapedType::kDynamic;
2037 concatDimSize += operandShape.getDimSize(axis);
2040 outputShape[axis] = concatDimSize;
2046LogicalResult tosa::ConcatOp::verify() {
2048 auto outType = getOutput().getType();
2052 if (inputList.empty())
2055 if (!llvm::all_of(inputList, [&](
auto input) {
2057 *
this, input.getType(), outType));
2062 const int32_t axis = getAxis();
2064 for (
const auto &input : inputList) {
2065 const Type inputType = input.getType();
2067 if (currShape.hasRank()) {
2068 firstRankedInputShape = currShape;
2070 if (axis < 0 || axis >= firstRankedInputShape.
getRank())
2071 return emitOpError(
"expect axis to be within range 0 < axis < "
2072 "rank(input1[firstRankedTensorIdx]), got ")
2078 const auto allOperandsHasRank = [](
const Value input) {
2081 if (llvm::all_of(inputList, allOperandsHasRank)) {
2084 for (
const auto &[
index, input] : llvm::enumerate(inputList.drop_front())) {
2086 const int64_t inputRank = inputShape.getRank();
2087 const size_t operandNum =
index + 1;
2090 if (inputRank != firstInputRank)
2092 "expect all operands to have the same rank, but got ")
2093 << firstInputRank <<
" vs " << inputRank <<
" on operands 0 and "
2097 for (
int i = 0; i < inputRank; i++) {
2098 const int64_t inputDim = inputShape.getDimSize(i);
2100 if (i == axis || firstRankedInputShape.
isDynamicDim(i) ||
2101 inputShape.isDynamicDim(i))
2103 if (inputDim != firstInputDim)
2104 return emitOpError(
"expect all operand shapes to have the same sizes "
2105 "on non-axis dimensions, but got ")
2106 << inputDim <<
" vs " << firstInputDim <<
" at index " << i
2107 <<
" on operands 0 and " << operandNum;
2112 if (outputShape.hasRank() && outputShape.getRank() != firstInputRank)
2113 return emitOpError(
"expect output rank to match inputs rank, got ")
2114 << outputShape.getRank() <<
" vs " << firstInputRank;
2118 for (
const auto &input : inputList) {
2120 if (inputShape.isDynamicDim(axis)) {
2125 axisSum += inputShape.getDimSize(axis);
2128 if (axisSum >= 0 && outputShape.hasRank() &&
2129 !outputShape.isDynamicDim(axis) &&
2130 axisSum != outputShape.getDimSize(axis))
2131 return emitOpError(
"requires sum of axis dimensions of input1 "
2132 "equal to output axis dimension, got ")
2133 << axisSum <<
" and " << outputShape.getDimSize(axis);
2139LogicalResult tosa::EqualOp::inferReturnTypeComponents(
2140 MLIRContext *context, ::std::optional<Location> location,
2144 auto elementType = IntegerType::get(context, 1);
2157 if (l.size() != r.size() || l.size() != 1)
2162LogicalResult tosa::MatMulOp::inferReturnTypeComponents(
2163 MLIRContext *context, ::std::optional<Location> location,
2164 MatMulOp::Adaptor adaptor,
2171 outShape.resize(3, ShapedType::kDynamic);
2173 if (lhsShape.hasRank()) {
2174 outShape[0] = lhsShape.getDimSize(0);
2175 outShape[1] = lhsShape.getDimSize(1);
2178 if (rhsShape.hasRank()) {
2179 outShape[0] = outShape[0] == ShapedType::kDynamic ? rhsShape.getDimSize(0)
2181 outShape[2] = rhsShape.getDimSize(2);
2188template <
typename T>
2190 Type bElementType) {
2191 const auto aQuantizedEType =
2192 llvm::dyn_cast<quant::UniformQuantizedType>(aElementType);
2193 const auto bQuantizedEType =
2194 llvm::dyn_cast<quant::UniformQuantizedType>(bElementType);
2196 if (aQuantizedEType || bQuantizedEType) {
2197 if (!aQuantizedEType || !bQuantizedEType) {
2198 return op.emitOpError(
"expect operands to be both quantized or both not "
2200 << aElementType <<
" and " << bElementType;
2203 auto aQuantWidth = aQuantizedEType.getStorageTypeIntegralWidth();
2204 auto bQuantWidth = bQuantizedEType.getStorageTypeIntegralWidth();
2205 if (aQuantWidth != bQuantWidth) {
2206 return op.emitOpError(
"expect quantized operands to have same widths, "
2208 << aQuantWidth <<
" and " << bQuantWidth;
2215template <
typename T>
2217 StringRef inputName,
2222 Type expectedElementType = inputStorageElementType;
2224 if (isa<BlockScaledType>(inputElementType))
2225 expectedElementType = Float32Type::get(op.getContext());
2227 if (expectedElementType == zpElementType)
2231 diag << inputName <<
" and " << zpName;
2232 if (isa<BlockScaledType>(inputElementType))
2233 diag <<
" have compatible element types, got " << inputElementType
2234 <<
" and " << zpElementType;
2236 diag <<
" have the same element type, got " << inputStorageElementType
2237 <<
" and " << zpElementType;
2241LogicalResult MatMulOp::verify() {
2244 const Type aElementType = aShape.getElementType();
2245 const Type bElementType = bShape.getElementType();
2255 FailureOr<int64_t> maybeAZp = getAZeroPoint();
2256 if (succeeded(maybeAZp) && verifyAZeroPoint(*maybeAZp).failed())
2259 FailureOr<int64_t> maybeBZp = getBZeroPoint();
2260 if (succeeded(maybeBZp) && verifyBZeroPoint(*maybeBZp).failed())
2264 int64_t N = ShapedType::kDynamic;
2265 int64_t H = ShapedType::kDynamic;
2269 if (aShape.hasRank()) {
2270 N = aShape.getDimSize(0);
2271 H = aShape.getDimSize(1);
2272 C = aShape.getDimSize(2);
2275 if (bShape.hasRank()) {
2281 W = bShape.getDimSize(2);
2285 const auto outputType = cast<ShapedType>(getResult().
getType());
2286 if (outputType.hasRank() &&
2288 expectedOutputShape)))
2294LogicalResult tosa::MatMulTOp::inferReturnTypeComponents(
2295 MLIRContext *context, ::std::optional<Location> location,
2296 MatMulTOp::Adaptor adaptor,
2303 if (lhsShape.hasRank()) {
2304 outShape[0] = lhsShape.getDimSize(0);
2305 outShape[1] = lhsShape.getDimSize(1);
2308 if (rhsShape.hasRank()) {
2309 const int64_t bBatchSize = rhsShape.getDimSize(0);
2310 if (bBatchSize != 1 && ShapedType::isDynamic(outShape[0]))
2311 outShape[0] = bBatchSize;
2312 outShape[2] = rhsShape.getDimSize(1);
2319LogicalResult MatMulTOp::verify() {
2322 const Type aElementType = aShape.getElementType();
2323 const Type bElementType = bShape.getElementType();
2333 FailureOr<int64_t> maybeAZp = getAZeroPoint();
2334 if (succeeded(maybeAZp) && verifyAZeroPoint(*maybeAZp).failed())
2337 FailureOr<int64_t> maybeBZp = getBZeroPoint();
2338 if (succeeded(maybeBZp) && verifyBZeroPoint(*maybeBZp).failed())
2342 int64_t N = ShapedType::kDynamic;
2343 int64_t D = ShapedType::kDynamic;
2344 int64_t H = ShapedType::kDynamic;
2348 if (aShape.hasRank()) {
2349 N = aShape.getDimSize(0);
2350 H = aShape.getDimSize(1);
2351 C = aShape.getDimSize(2);
2354 if (bShape.hasRank()) {
2355 D = bShape.getDimSize(0);
2356 W = bShape.getDimSize(1);
2363 if (ShapedType::isStatic(N) && ShapedType::isStatic(D) && N != D && D != 1)
2364 return emitOpError(
"expect B matrix batch size to be broadcast compatible "
2366 << D <<
" vs N=" << N;
2368 if (ShapedType::isDynamic(N) && ShapedType::isStatic(D) && D != 1)
2372 const auto outputType = cast<ShapedType>(getResult().
getType());
2373 if (outputType.hasRank() &&
2375 expectedOutputShape)))
2381LogicalResult tosa::MatmulTBlockScaledOp::inferReturnTypeComponents(
2382 MLIRContext *context, ::std::optional<Location> location,
2383 MatmulTBlockScaledOp::Adaptor adaptor,
2387 const auto aDataShape = cast<ShapedType>(adaptor.getAData().getType());
2388 if (aDataShape.hasRank()) {
2389 outShape[0] = aDataShape.getDimSize(0);
2390 outShape[1] = aDataShape.getDimSize(1);
2393 const auto aScaleShape = cast<ShapedType>(adaptor.getAScale().getType());
2394 if (aScaleShape.hasRank()) {
2395 outShape[0] = ShapedType::isDynamic(outShape[0]) ? aScaleShape.getDimSize(0)
2397 outShape[1] = ShapedType::isDynamic(outShape[1]) ? aScaleShape.getDimSize(1)
2402 const auto bDataShape = cast<ShapedType>(adaptor.getBData().getType());
2403 if (bDataShape.hasRank()) {
2404 const int64_t bDataBatchSize = bDataShape.getDimSize(0);
2405 if (bDataBatchSize != 1)
2407 ShapedType::isDynamic(outShape[0]) ? bDataBatchSize : outShape[0];
2408 outShape[2] = bDataShape.getDimSize(1);
2411 const auto bScaleShape = cast<ShapedType>(adaptor.getBScale().getType());
2412 if (bScaleShape.hasRank()) {
2413 const int64_t bScaleBatchSize = bScaleShape.getDimSize(0);
2414 if (bScaleBatchSize != 1)
2416 ShapedType::isDynamic(outShape[0]) ? bScaleBatchSize : outShape[0];
2417 outShape[2] = ShapedType::isDynamic(outShape[2]) ? bScaleShape.getDimSize(1)
2425LogicalResult MatmulTBlockScaledOp::verify() {
2427 const Type aDataType = getAData().getType();
2428 const Type bDataType = getBData().getType();
2434 int64_t N = ShapedType::kDynamic;
2435 int64_t D = ShapedType::kDynamic;
2436 int64_t H = ShapedType::kDynamic;
2439 int64_t multiplesOfC = ShapedType::kDynamic;
2451 "a_scale",
"batch")) ||
2453 "a_scale",
"height")))
2461 "b_data",
"batch")) ||
2463 "b_data",
"channels")))
2471 "b_scale",
"batch")) ||
2473 "b_scale",
"width")) ||
2481 if (ShapedType::isStatic(N) && ShapedType::isStatic(D) && N != D && D != 1)
2482 return emitOpError(
"expect B matrix batch size to be broadcast compatible "
2484 << D <<
" vs N=" << N;
2487 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
2488 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
2489 return emitOpError(
"expect block size to be 32, got ") << blockSize;
2490 if (ShapedType::isStatic(C) && C % blockSize != 0)
2491 return emitOpError(
"expect C to be a multiple of block size, got C=")
2492 <<
C <<
", block_size=" << blockSize;
2495 if (ShapedType::isStatic(C) && ShapedType::isStatic(multiplesOfC) &&
2496 multiplesOfC != C / blockSize)
2498 "expect scale operands dimension 2 to equal C/block_size (")
2499 <<
C <<
"/" << blockSize <<
")" <<
", got " << multiplesOfC;
2502 N = ShapedType::isDynamic(N) ? D : N;
2504 const auto outputType = cast<ShapedType>(getResult().
getType());
2505 if (outputType.hasRank() &&
2510 opError <<
" to be compatible with expected output shape ";
2518LogicalResult tosa::PadOp::inferReturnTypeComponents(
2519 MLIRContext *context, ::std::optional<Location> location,
2520 PadOp::Adaptor adaptor,
2522 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2524 cast<tosa::shapeType>(adaptor.getPadding().getType()).getRank();
2529 if (!inputShape.hasRank()) {
2530 outputShape.resize(paddingRank / 2, ShapedType::kDynamic);
2539 outputShape.resize(inputShape.getRank(), ShapedType::kDynamic);
2544 outputShape.reserve(inputShape.getRank());
2545 for (
int i = 0, s = inputShape.getRank(); i < s; i++) {
2546 if (inputShape.isDynamicDim(i)) {
2547 outputShape.push_back(ShapedType::kDynamic);
2550 auto padFront = paddingValues[i * 2];
2551 auto padBack = paddingValues[i * 2 + 1];
2552 if (padFront < 0 || padBack < 0) {
2554 outputShape.push_back(ShapedType::kDynamic);
2558 outputShape.push_back(inputShape.getDimSize(i) + padFront + padBack);
2565LogicalResult tosa::PadOp::verify() {
2572 if (
auto padConst = getPadConst()) {
2580 RankedTensorType inputType =
2581 llvm::dyn_cast<RankedTensorType>(getInput1().
getType());
2582 RankedTensorType outputType =
2583 llvm::dyn_cast<RankedTensorType>(getOutput().
getType());
2584 if (!inputType || !outputType)
2591 auto inputRank = inputType.getRank();
2596 auto paddingValues = paddingAttr.getValues<APInt>();
2597 if (paddingValues.size() !=
static_cast<size_t>(inputRank * 2))
2598 return emitOpError() <<
"padding tensor must have " << inputRank
2599 <<
" * 2 = " << inputRank * 2 <<
" elements, but got "
2600 << paddingValues.size();
2602 auto inputShape = inputType.getShape();
2603 auto outputShape = outputType.getShape();
2605 for (
int64_t i = 0; i < inputRank; ++i) {
2606 int64_t padStart = paddingValues[i * 2].getSExtValue();
2607 int64_t padEnd = paddingValues[i * 2 + 1].getSExtValue();
2609 if ((padStart < 0 && padStart != -1) || (padEnd < 0 && padEnd != -1)) {
2611 <<
"invalid padding values at dimension " << i
2612 <<
": values must be non-negative or -1 for dynamic padding, got ["
2613 << padStart <<
", " << padEnd <<
"]";
2617 if (inputShape[i] == ShapedType::kDynamic ||
2618 outputShape[i] == ShapedType::kDynamic)
2621 if (outputShape[i] != inputShape[i] + padStart + padEnd) {
2622 return emitOpError() <<
"mismatch in output shape at dimension " << i
2623 <<
": expected " << inputShape[i] <<
" + "
2624 << padStart <<
" + " << padEnd <<
" = "
2625 << (inputShape[i] + padStart + padEnd)
2626 <<
", but got " << outputShape[i];
2633LogicalResult tosa::SliceOp::inferReturnTypeComponents(
2634 MLIRContext *context, ::std::optional<Location> location,
2635 SliceOp::Adaptor adaptor,
2644 auto rank = cast<tosa::shapeType>(adaptor.getSize().getType()).getRank();
2652 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2655 if (inputShape.hasRank()) {
2656 for (
size_t i = 0; i < size.size(); i++) {
2657 if (size[i] != 0 && size[i] >= -1 && start[i] >= 0 &&
2658 (ShapedType::isDynamic(inputShape.getDimSize(i)) ||
2659 start[i] < inputShape.getDimSize(i))) {
2661 if (ShapedType::isDynamic(inputShape.getDimSize(i))) {
2664 outputShape[i] = size[i];
2668 if (size[i] == -1) {
2669 outputShape[i] = inputShape.getDimSize(i) - start[i];
2670 }
else if (start[i] + size[i] <= inputShape.getDimSize(i)) {
2672 outputShape[i] = size[i];
2684LogicalResult tosa::SliceOp::verify() {
2685 const Value input = getInput1();
2686 const Value output = getOutput();
2692 const Value start = getStart();
2693 const Value size = getSize();
2697 if (inputShape.hasRank()) {
2698 const auto inputRank = inputShape.getRank();
2699 if (outputShape.hasRank() && inputRank != outputShape.getRank())
2701 "expect input1 and output to have the same ranks, got ")
2702 << inputRank <<
" and " << outputShape.getRank();
2704 const auto startShapeRank =
2705 llvm::cast<tosa::shapeType>(start.
getType()).getRank();
2706 if (inputRank != startShapeRank)
2707 return emitOpError(
"length of start is not equal to rank of input shape");
2709 const auto sizeShapeRank =
2710 llvm::cast<tosa::shapeType>(size.
getType()).getRank();
2711 if (inputRank != sizeShapeRank)
2712 return emitOpError(
"length of size is not equal to rank of input shape");
2717 if (startValues.size()) {
2718 if (llvm::any_of(startValues, [](
const int64_t v) {
2721 return emitOpError(
"start values must be non-negative, got [")
2722 << startValues <<
"]";
2729 if (llvm::any_of(sizeValues, [](
const int64_t v) {
2732 return emitOpError(
"size values must be > 0, got [") << sizeValues <<
"]";
2733 if (outputShape.hasRank()) {
2735 outputShape.getDims(outputDims);
2736 const bool hasNoInferableDims = llvm::all_of(
2738 if (hasNoInferableDims &&
2740 return emitOpError(
"expected output shape to match size values, got ")
2741 << output.
getType() <<
" vs [" << sizeValues <<
"]";
2744 if (inputShape.hasRank() && startValues.size()) {
2746 inputShape.getDims(inputDims);
2747 for (
const auto &[
index, vals] :
2748 llvm::enumerate(llvm::zip_equal(startValues, sizeValues, inputDims))) {
2749 const auto &[start, size, inputDim] = vals;
2751 ShapedType::isDynamic(inputDim))
2753 if (start + size > inputDim)
2754 return emitOpError(
"start + size must be less than or equal to input "
2755 "dimension size, got start=")
2756 << start <<
", size=" << size
2757 <<
" vs input dim size=" << inputDim <<
" at dimension "
2765LogicalResult tosa::MulOp::inferReturnTypeComponents(
2766 MLIRContext *context, ::std::optional<Location> location,
2781LogicalResult tosa::MulOp::verify() {
2782 const Value output = getOutput();
2787 if (
auto resIntType = dyn_cast<IntegerType>(resElemType)) {
2788 IntegerType lhsIntType =
2790 IntegerType rhsIntType =
2792 if (!lhsIntType || !rhsIntType || lhsIntType != rhsIntType)
2793 return emitOpError(
"requires the same element type for all operands");
2798 if (lhsIntType.getWidth() > resIntType.getWidth())
2799 return emitOpError(
"invalid data type size for operands or result");
2804 for (
int i = 0; i < 2; ++i) {
2807 "requires the same element type for all operands and results");
2811 ElementsAttr shiftElem;
2813 int32_t shift = shiftElem.getValues<IntegerAttr>()[0].getInt();
2815 return emitOpError() <<
"require shift to be 0 for float type";
2823 TypeRange operandTypes = getOperandTypes();
2824 ShapedType aType = cast<ShapedType>(operandTypes[0]);
2825 ShapedType bType = cast<ShapedType>(operandTypes[1]);
2827 const bool aHasRank = aType.hasRank();
2828 const bool bHasRank = bType.hasRank();
2830 bool hasExpectedOutputShape =
false;
2833 if (aHasRank && bHasRank) {
2834 const int64_t aRank = aType.getRank();
2835 const int64_t bRank = bType.getRank();
2837 return emitOpError(
"a and b operands don't have matching ranks, got ")
2838 << aRank <<
" and " << bRank;
2842 aType.getShape(), bType.getShape(), expectedOutputShape))
2843 return emitOpError(
"a and b operands don't have broadcast-compatible "
2845 << aType <<
" and " << bType;
2846 hasExpectedOutputShape =
true;
2849 ShapedType resultType = cast<ShapedType>(output.
getType());
2850 if (!resultType.hasRank())
2853 const int64_t resultRank = resultType.getRank();
2854 if (aHasRank && resultRank != aType.getRank())
2855 return emitOpError(
"result type has different rank than a, got ")
2856 << resultRank <<
" vs " << aType.getRank();
2857 if (bHasRank && resultRank != bType.getRank())
2858 return emitOpError(
"result type has different rank than b, got ")
2859 << resultRank <<
" vs " << bType.getRank();
2861 if (hasExpectedOutputShape &&
2863 expectedOutputShape)))
2869LogicalResult tosa::TableOp::inferReturnTypeComponents(
2870 MLIRContext *context, ::std::optional<Location> location,
2871 TableOp::Adaptor adaptor,
2873 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2875 if (!inputShape.hasRank()) {
2880 inferredReturnShapes.resize(1);
2881 inputShape.getDims(inferredReturnShapes[0]);
2885LogicalResult tosa::TableOp::verify() {
2886 const TensorType inputType = getInput1().getType();
2887 const TensorType outputType = getOutput().getType();
2896 auto inputDims = inputType.
getShape();
2897 auto outputDims = outputType.
getShape();
2898 for (
auto it : llvm::enumerate(llvm::zip(inputDims, outputDims))) {
2900 auto [inputDim, outputDim] = it.value();
2901 if (ShapedType::isStatic(outputDim) && outputDim != inputDim) {
2902 return emitOpError() <<
"dim(result, " << dim <<
") = " << outputDim
2903 <<
" doesn't match dim(input, " << dim
2904 <<
") = " << inputDim;
2917 llvm::map_to_vector(multiplesAttr.getValues<APInt>(),
2918 [](
const APInt &val) { return val.getSExtValue(); });
2922LogicalResult tosa::TileOp::inferReturnTypeComponents(
2923 MLIRContext *context, ::std::optional<Location> location,
2924 TileOp::Adaptor adaptor,
2931 cast<tosa::shapeType>(adaptor.getMultiples().getType()).getRank();
2938 ShapeAdaptor inputShape(adaptor.getInput1().getType());
2940 if (!inputShape.hasRank()) {
2941 outputShape.resize(multiples.size(), ShapedType::kDynamic);
2942 inferredReturnShapes.push_back(
2946 if (
static_cast<size_t>(inputShape.getRank()) != multiples.size())
2950 outputShape.reserve(multiples.size());
2951 for (
int i = 0, s = inputShape.getRank(); i < s; i++) {
2952 if (multiples[i] == ShapedType::kDynamic) {
2953 outputShape.push_back(ShapedType::kDynamic);
2955 int64_t dim = inputShape.getDimSize(i);
2956 if (dim != ShapedType::kDynamic)
2957 dim *= multiples[i];
2958 outputShape.push_back(dim);
2966LogicalResult tosa::TileOp::verify() {
2972 ShapedType inputType = llvm::cast<ShapedType>(getInput1().
getType());
2973 ShapedType outputType = llvm::cast<ShapedType>(
getType());
2975 shapeType multiplesType =
2976 llvm::cast<tosa::shapeType>(getMultiples().
getType());
2978 auto multiplesRank = multiplesType.getRank();
2980 if (inputType.hasRank()) {
2981 if (inputType.getRank() != multiplesRank)
2982 return emitOpError(
"expect 'multiples' to have rank ")
2983 << inputType.getRank() <<
" but got " << multiplesRank <<
".";
2984 if (outputType.hasRank() &&
2988 }
else if (outputType.hasRank() && outputType.getRank() != multiplesRank)
2989 return emitOpError(
"expect 'multiples' array to have length ")
2990 << outputType.getRank() <<
" but got " << multiplesRank <<
".";
2993 if (getConstantMultiples(multiples).succeeded() &&
2994 llvm::any_of(multiples, [](
int64_t v) {
return v <= 0 && v != -1; }))
2996 "expect element of 'multiples' to be positive integer or -1.");
3002 if (l.size() != r.size() || l.size() != 1)
3007LogicalResult tosa::ReshapeOp::inferReturnTypeComponents(
3008 MLIRContext *context, ::std::optional<Location> location,
3009 ReshapeOp::Adaptor adaptor,
3011 ShapeAdaptor inputShape(adaptor.getInput1().getType());
3016 auto rank = cast<tosa::shapeType>(adaptor.getShape().getType()).getRank();
3025 if (!inputShape.hasRank() || !inputShape.hasStaticShape()) {
3026 inferredReturnShapes.push_back(
3034 int64_t numElements = inputShape.getNumElements();
3036 for (
auto val : newShapeValue) {
3037 if (ShapedType::isStatic(val)) {
3043 for (
auto &val : newShapeValue) {
3044 if (ShapedType::isDynamic(val))
3045 val = numElements / staticMul;
3048 inferredReturnShapes.push_back(
3053llvm::LogicalResult tosa::ReshapeOp::verify() {
3059 TensorType inputType = getInput1().getType();
3064 return mlir::success();
3068 if (missingDims > 1)
3069 return emitOpError() <<
"expected at most one target dimension to be "
3072 const auto outputType = dyn_cast<RankedTensorType>(
getType());
3076 if ((
int64_t)shapeValues.size() != outputType.getRank())
3077 return emitOpError() <<
"new shape does not match result rank";
3079 for (
auto [newShapeDim, outputShapeDim] :
3080 zip(shapeValues, outputType.getShape())) {
3082 newShapeDim != ShapedType::kDynamic &&
3083 outputShapeDim != ShapedType::kDynamic && newShapeDim != outputShapeDim)
3084 return emitOpError() <<
"new shape is inconsistent with result shape";
3087 return emitOpError() <<
"new shape has invalid tensor dimension size "
3091 if (inputType.hasStaticShape()) {
3092 int64_t inputElementsNum = inputType.getNumElements();
3093 if (outputType.hasStaticShape()) {
3094 int64_t outputElementsNum = outputType.getNumElements();
3095 if (inputElementsNum != outputElementsNum) {
3096 return emitOpError() <<
"cannot reshape " << inputElementsNum
3097 <<
" elements into " << outputElementsNum;
3103 return (dim > 0) ?
acc * dim :
acc;
3105 bool isStaticNewShape =
3106 llvm::all_of(shapeValues, [](
int64_t s) {
return s > 0; });
3107 if ((isStaticNewShape && inputElementsNum != newShapeElementsNum) ||
3108 (!isStaticNewShape && newShapeElementsNum > inputElementsNum)) {
3109 return emitOpError() <<
"cannot reshape " << inputElementsNum
3110 <<
" elements into " << newShapeElementsNum;
3114 return mlir::success();
3117bool tosa::ReshapeBlockScaledOp::isCompatibleReturnTypes(
TypeRange l,
3119 if (l.size() != r.size() || l.size() < 1 || l.size() > 2)
3127LogicalResult tosa::ReshapeBlockScaledOp::inferReturnTypeComponents(
3128 MLIRContext *context, ::std::optional<Location> location,
3129 ReshapeBlockScaledOp::Adaptor adaptor,
3132 const auto numInputs = adaptor.getInput().size();
3133 ShapeAdaptor inputShape(adaptor.getInput()[0].getType());
3136 const auto newShape = adaptor.getNewValueShape();
3138 auto rank = cast<tosa::shapeType>(newShape.getType()).getRank();
3147 const uint32_t blockSize =
3148 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
3151 if (numInputs == 2) {
3152 newScaleShapeValue.assign(newShapeValue.begin(), newShapeValue.end());
3153 if (ShapedType::isStatic(newScaleShapeValue.back()))
3154 newScaleShapeValue.back() /= blockSize;
3157 inferredReturnShapes.push_back(
3159 if (numInputs == 2) {
3161 for (
size_t idx = 0; idx < newShapeValue.size(); idx++) {
3162 if (ShapedType::isDynamic(newScaleShapeValue[idx])) {
3163 newScaleShapeValue[idx] = newShapeValue[idx];
3164 if (idx == (newShapeValue.size() - 1))
3165 newScaleShapeValue[idx] /= blockSize;
3176llvm::LogicalResult tosa::ReshapeBlockScaledOp::verify() {
3180 if (inputList.size() == 0)
3181 return emitOpError(
"requires at least one input");
3183 if (inputList.size() > 2)
3184 return emitOpError(
"requires at most two inputs");
3186 if (inputList.size() != outputList.size())
3187 return emitOpError(
"requires number of results to match inputs");
3195 const auto inputType = llvm::cast<ShapedType>(inputList[0].
getType());
3196 if (!inputType.hasRank())
3198 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
3200 if (inputList.size() == 2) {
3201 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
3202 return emitOpError(
"expect block size to be 32, got ") << blockSize;
3203 if (llvm::any_of(inputList, [](
Value v) {
3204 const auto input = cast<ShapedType>(v.
getType());
3205 return input.hasRank() && input.getRank() == 0;
3208 "requires all input shapes have a rank greater than 0");
3209 if (llvm::any_of(outputList, [](
Value v) {
3210 const auto output = cast<ShapedType>(v.
getType());
3211 return output.hasRank() && output.getRank() == 0;
3214 "requires all result shapes have a rank greater than 0");
3222 const auto inputScaleType = llvm::cast<ShapedType>(inputList[1].
getType());
3223 if (inputScaleType.hasRank()) {
3224 if (inputType.getRank() != inputScaleType.getRank())
3225 return emitOpError(
"input shapes do not have same rank");
3228 for (
auto dimIdx = 0; dimIdx < inputType.getRank() - 1; dimIdx++) {
3229 const int64_t inputValueDim = inputType.getDimSize(dimIdx);
3230 const int64_t inputScaleDim = inputScaleType.getShape()[dimIdx];
3231 if (ShapedType::isStatic(inputValueDim) &&
3232 ShapedType::isStatic(inputScaleDim) &&
3233 inputValueDim != inputScaleDim)
3234 return emitOpError(
"input shapes for data and scale do not match on "
3241 inputType.getDimSize(inputType.getRank() - 1);
3242 if (ShapedType::isStatic(lastValueDim)) {
3243 if (lastValueDim % blockSize != 0)
3244 return emitOpError(
"expect last dimension of input_data (")
3245 << lastValueDim <<
") to be divisible by block_size ("
3246 << blockSize <<
")";
3249 inputScaleType.getDimSize(inputScaleType.getRank() - 1);
3251 if (ShapedType::isStatic(lastScaleDim) &&
3252 lastScaleDim != lastValueDim / blockSize)
3253 return emitOpError(
"expect last dimension of scale_data (")
3254 << lastScaleDim <<
") to be " << lastValueDim <<
"/"
3259 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_1))
3260 return emitOpError(
"expect block size to be 1, got ") << blockSize;
3268 return mlir::success();
3271 if (inputList.size() == 2) {
3272 if (
static_cast<int64_t>(shapeValues.size()) == 0)
3273 return emitOpError(
"requires new shape to have a rank greater than 0");
3275 const int64_t lastShapeDim = shapeValues.back();
3276 if (ShapedType::isStatic(lastShapeDim) && lastShapeDim % blockSize != 0)
3277 return emitOpError(
"expect last dimension of new shape (")
3278 << lastShapeDim <<
") to be divisible by block_size (" << blockSize
3282 const auto outputType = llvm::cast<ShapedType>(outputList[0].
getType());
3283 if (!outputType.hasRank())
3286 if (
static_cast<int64_t>(shapeValues.size()) != outputType.getRank())
3287 return emitOpError() <<
"result does not match new shape rank";
3289 for (
auto [newShapeDim, outputShapeDim] :
3290 zip(shapeValues, outputType.getShape())) {
3291 if (ShapedType::isStatic(newShapeDim) &&
3292 ShapedType::isStatic(outputShapeDim) && newShapeDim != outputShapeDim)
3293 return emitOpError() <<
"result shape is inconsistent with new shape";
3296 if (outputList.size() == 2) {
3300 scaleShapeValues.back() /= blockSize;
3302 const auto outputScaleType =
3303 llvm::cast<ShapedType>(outputList[1].
getType());
3304 if (outputScaleType.hasRank()) {
3305 if ((
int64_t)scaleShapeValues.size() != outputScaleType.getRank())
3306 return emitOpError() <<
"result scale does not match new shape rank";
3308 for (
auto [newScaleShapeDim, outputScaleShapeDim] :
3309 zip(scaleShapeValues, outputScaleType.getShape())) {
3310 if (ShapedType::isStatic(newScaleShapeDim) &&
3311 ShapedType::isStatic(outputScaleShapeDim) &&
3312 newScaleShapeDim != outputScaleShapeDim)
3314 <<
"result scale shape is inconsistent with new shape";
3319 if (inputType.hasStaticShape()) {
3320 int64_t inputElementsNum = inputType.getNumElements();
3321 if (outputType.hasStaticShape()) {
3322 int64_t outputElementsNum = outputType.getNumElements();
3323 if (inputElementsNum != outputElementsNum) {
3324 return emitOpError() <<
"cannot reshape " << inputElementsNum
3325 <<
" elements into " << outputElementsNum;
3331 return (dim > 0) ?
acc * dim :
acc;
3333 bool isStaticNewShape =
3334 llvm::all_of(shapeValues, [](
int64_t s) {
return s > 0; });
3335 if ((isStaticNewShape && inputElementsNum != newShapeElementsNum) ||
3336 (!isStaticNewShape && newShapeElementsNum > inputElementsNum)) {
3337 return emitOpError() <<
"cannot reshape " << inputElementsNum
3338 <<
" elements into " << newShapeElementsNum;
3342 return mlir::success();
3349 ElementsAttr zpAttr;
3354 Type zpElemType = zpAttr.getElementType();
3356 if (llvm::isa<FloatType>(zpElemType)) {
3357 if (zpAttr.getValues<APFloat>()[0].isZero()) {
3364 if (llvm::isa<IntegerType>(zpElemType)) {
3366 return zpAttr.getValues<APInt>()[0].getSExtValue();
3367 return zpAttr.getValues<APInt>()[0].getZExtValue();
3374template <
typename T>
3376 const std::string &operand) {
3379 if (!zpElemType.
isInteger(8) && zp != 0) {
3381 std::string lower = operand;
3382 llvm::transform(lower, lower.begin(), ::tolower);
3383 return op.emitOpError()
3384 << lower <<
" zero point must be zero for non-int8 integer types";
3392 const std::string &operand) {
3393 bool isInputZp = (operand ==
"Input");
3395 bool tensorUnsigned =
3396 isInputZp ? op.getInputUnsigned() : op.getOutputUnsigned();
3397 StringRef tensorName = isInputZp ?
"input" :
"output";
3403 !(zpElemType.
isInteger(16) && tensorUnsigned)) {
3404 return op.emitOpError()
3405 <<
"expect " << tensorName <<
"_zp of 0, got " << zp;
3407 if (zpElemType.
isInteger(16) && tensorUnsigned && zp != 32768) {
3408 return op.emitOpError() <<
"expect " << tensorName
3409 <<
"_zp of 0 or 32768 for unsigned int16 "
3410 << tensorName <<
", got " << zp;
3417#define ZERO_POINT_HELPER(OP, OPERAND_NAME, SIGN_EXTEND) \
3418 FailureOr<int64_t> tosa::OP::get##OPERAND_NAME##ZeroPoint() { \
3419 return getZeroPoint(get##OPERAND_NAME##Zp(), SIGN_EXTEND); \
3421 LogicalResult tosa::OP::verify##OPERAND_NAME##ZeroPoint(int64_t zp) { \
3422 return verifyZeroPoint(*this, get##OPERAND_NAME##Zp(), zp, #OPERAND_NAME); \
3445#undef ZERO_POINT_HELPER
3447LogicalResult tosa::TransposeOp::inferReturnTypeComponents(
3448 MLIRContext *context, ::std::optional<Location> location,
3449 TransposeOp::Adaptor adaptor,
3451 ShapeAdaptor inputShape(adaptor.getInput1().getType());
3460 const auto inputRank = inputShape.
getRank();
3464 if (adaptor.getPerms().size() !=
static_cast<size_t>(inputRank)) {
3470 if (inputRank == 0) {
3476 bool allTheSame =
true;
3477 for (
int i = 1, s = inputRank; i < s; i++) {
3487 outputShape.resize(inputRank, inputShape.
getDimSize(0));
3492 outputShape.resize(inputRank, ShapedType::kDynamic);
3495 if (llvm::any_of(adaptor.getPerms(),
3496 [inputRank](
const auto i) { return i >= inputRank; }))
3499 outputShape.reserve(inputRank);
3500 for (
int i = 0, s = inputRank; i < s; i++) {
3501 outputShape[i] = inputShape.
getDimSize(adaptor.getPerms()[i]);
3508LogicalResult tosa::TransposeOp::verify() {
3520 if (inputShape.hasRank() &&
3521 constantPerms.size() !=
static_cast<size_t>(inputShape.getRank()))
3522 return emitOpError() <<
"expected perms attribute to have size "
3523 << inputShape.getRank()
3524 <<
" (input rank) but got size "
3525 << constantPerms.size();
3527 if (inputShape.hasRank() && outputShape.hasRank() &&
3528 inputShape.getRank() != outputShape.getRank())
3530 <<
"expected input tensor rank to equal result tensor rank";
3532 if (outputShape.hasRank() &&
3533 constantPerms.size() !=
static_cast<size_t>(outputShape.getRank()))
3534 return emitOpError() <<
"expected perms attribute to have size "
3535 << outputShape.getRank()
3536 <<
" (output rank) but got size "
3537 << constantPerms.size();
3539 if (!llvm::all_of(constantPerms,
3540 [&constantPerms](int32_t s) {
3542 static_cast<size_t>(s) < constantPerms.size();
3545 constantPerms, [](int32_t v) ->
int64_t {
return v; })))
3546 return emitOpError() <<
"expected valid permutation indices";
3549 if (inputShape.hasStaticShape() && outputShape.hasStaticShape() &&
3550 inputShape.getNumElements() != outputShape.getNumElements())
3551 return emitOpError() <<
"expected input1 and output to have same numbers "
3553 << inputShape.getNumElements() <<
" and "
3554 << outputShape.getNumElements();
3558 if (inputShape.hasRank() && outputShape.hasRank()) {
3559 for (
auto i = 0; i < outputShape.getRank(); i++) {
3560 if (inputShape.isDynamicDim(constantPerms[i]) ||
3561 outputShape.isDynamicDim(i))
3564 if (inputShape.getDimSize(constantPerms[i]) != outputShape.getDimSize(i))
3566 <<
"expected output tensor dim " << i <<
" to match "
3567 <<
"input dim " << constantPerms[i] <<
" with value of "
3568 << inputShape.getDimSize(constantPerms[i]);
3575LogicalResult TransposeOp::reifyResultShapes(
3578 const llvm::ArrayRef<int32_t> transposePerms = getPerms();
3580 Value input = getInput1();
3581 auto inputType = cast<TensorType>(input.
getType());
3583 SmallVector<OpFoldResult> returnedDims(inputType.getRank());
3584 for (
auto dim : transposePerms) {
3585 int32_t dimInInput = transposePerms[dim];
3586 if (inputType.isDynamicDim(dimInInput))
3588 tensor::DimOp::create(builder, getLoc(), input, dimInInput)
3592 builder.
getIndexAttr(inputType.getDimSize(dimInInput));
3595 reifiedReturnShapes.emplace_back(std::move(returnedDims));
3599LogicalResult tosa::GatherOp::inferReturnTypeComponents(
3600 MLIRContext *context, ::std::optional<Location> location,
3601 GatherOp::Adaptor adaptor,
3602 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3603 llvm::SmallVector<int64_t> outputShape;
3604 outputShape.resize(3, ShapedType::kDynamic);
3606 ShapeAdaptor valuesShape(adaptor.getValues().getType());
3607 if (valuesShape.hasRank()) {
3608 outputShape[0] = valuesShape.getDimSize(0);
3609 outputShape[2] = valuesShape.getDimSize(2);
3612 ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3613 if (indicesShape.hasRank()) {
3614 if (outputShape[0] == ShapedType::kDynamic)
3615 outputShape[0] = indicesShape.getDimSize(0);
3616 if (outputShape[1] == ShapedType::kDynamic)
3617 outputShape[1] = indicesShape.getDimSize(1);
3620 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3624LogicalResult tosa::RowGatherOp::inferReturnTypeComponents(
3625 MLIRContext *context, ::std::optional<Location> location,
3626 RowGatherOp::Adaptor adaptor,
3627 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3628 llvm::SmallVector<int64_t> outputShape;
3629 outputShape.resize(3, ShapedType::kDynamic);
3631 const ShapeAdaptor valuesShape(adaptor.getValues().getType());
3632 if (valuesShape.hasRank()) {
3633 outputShape[0] = valuesShape.getDimSize(0);
3634 outputShape[2] = valuesShape.getDimSize(2);
3637 const ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3638 if (indicesShape.hasRank()) {
3639 if (outputShape[0] == ShapedType::kDynamic)
3640 outputShape[0] = indicesShape.getDimSize(0);
3642 const FailureOr<int32_t> maybeRowCount =
3644 if (succeeded(maybeRowCount)) {
3645 const int64_t indicesW = indicesShape.getDimSize(1);
3646 if (ShapedType::isStatic(indicesW))
3647 outputShape[1] = indicesW * maybeRowCount.value();
3651 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3655LogicalResult tosa::RowGatherBlockScaledOp::inferReturnTypeComponents(
3656 MLIRContext *context, ::std::optional<Location> location,
3657 RowGatherBlockScaledOp::Adaptor adaptor,
3658 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3659 const auto values = adaptor.getValues();
3663 SmallVector<int64_t> dataShape(3, ShapedType::kDynamic);
3664 const ShapeAdaptor valuesShape(values.front().getType());
3665 if (valuesShape.hasRank()) {
3666 dataShape[0] = valuesShape.getDimSize(0);
3667 dataShape[2] = valuesShape.getDimSize(2);
3670 const ShapeAdaptor indicesShape(adaptor.getIndices().getType());
3671 if (indicesShape.hasRank()) {
3672 if (dataShape[0] == ShapedType::kDynamic)
3673 dataShape[0] = indicesShape.getDimSize(0);
3677 succeeded(rowCount) && rowCount.value() > 0) {
3678 const int64_t indicesW = indicesShape.getDimSize(1);
3679 if (ShapedType::isStatic(indicesW))
3680 dataShape[1] = indicesW * rowCount.value();
3684 inferredReturnShapes.push_back(ShapedTypeComponents(dataShape));
3685 if (values.size() == 1)
3688 SmallVector<int64_t> scaleShape = dataShape;
3689 const uint32_t blockSize =
3690 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
3691 if (ShapedType::isStatic(dataShape[2]))
3692 scaleShape[2] = dataShape[2] / blockSize;
3694 inferredReturnShapes.push_back(ShapedTypeComponents(scaleShape));
3698LogicalResult tosa::GatherOp::verify() {
3705 const ShapeAdaptor valuesShape(getValues().
getType());
3707 const ShapeAdaptor outputShape(getOutput().
getType());
3709 int64_t n = ShapedType::kDynamic;
3710 int64_t w = ShapedType::kDynamic;
3711 int64_t c = ShapedType::kDynamic;
3713 if (valuesShape.hasRank()) {
3714 n = valuesShape.getDimSize(0);
3715 c = valuesShape.getDimSize(2);
3717 if (indicesShape.hasRank()) {
3718 const int64_t indicesN = indicesShape.getDimSize(0);
3719 w = indicesShape.getDimSize(1);
3720 if (n == ShapedType::kDynamic)
3722 else if (indicesN != ShapedType::kDynamic && n != indicesN)
3723 return emitOpError() <<
"requires indices dimension 0 to have size " << n
3724 <<
", got " << indicesN;
3726 if (outputShape.hasRank()) {
3727 const int64_t outputN = outputShape.getDimSize(0);
3728 const int64_t outputW = outputShape.getDimSize(1);
3729 const int64_t outputC = outputShape.getDimSize(2);
3730 if (n != ShapedType::kDynamic && outputN != ShapedType::kDynamic &&
3732 return emitOpError() <<
"requires output dimension 0 to have size " << n
3733 <<
", got " << outputN;
3735 if (w != ShapedType::kDynamic && outputW != ShapedType::kDynamic &&
3737 return emitOpError() <<
"requires output dimension 1 to have size " << w
3738 <<
", got " << outputW;
3739 if (c != ShapedType::kDynamic && outputC != ShapedType::kDynamic &&
3741 return emitOpError() <<
"requires output dimension 2 to have size " << c
3742 <<
", got " << outputC;
3747LogicalResult tosa::RowGatherOp::verify() {
3752 const FailureOr<int32_t> maybeRowCount =
3754 if (succeeded(maybeRowCount) && maybeRowCount.value() <= 0)
3755 return emitOpError() <<
"requires row_count to be > 0, got "
3756 << maybeRowCount.value();
3758 int64_t n = ShapedType::kDynamic;
3759 int64_t c = ShapedType::kDynamic;
3760 int64_t w = ShapedType::kDynamic;
3762 const ShapeAdaptor valuesShape(getValues().
getType());
3763 if (valuesShape.hasRank()) {
3764 n = valuesShape.getDimSize(0);
3765 c = valuesShape.getDimSize(2);
3769 if (indicesShape.hasRank()) {
3771 "indices",
"batch")))
3773 w = indicesShape.getDimSize(1);
3776 const ShapeAdaptor outputShape(getOutput().
getType());
3777 if (outputShape.hasRank()) {
3779 "output",
"batch")) ||
3781 "output",
"channels")))
3784 if (succeeded(maybeRowCount) && maybeRowCount.value() > 0 &&
3785 ShapedType::isStatic(w)) {
3786 const int64_t expectedOutputRows = w * maybeRowCount.value();
3787 if (ShapedType::isStatic(outputShape.getDimSize(1)) &&
3788 outputShape.getDimSize(1) != expectedOutputRows)
3790 <<
"requires output dimension to be equal to "
3791 "indices[1]*row_count ("
3792 << expectedOutputRows <<
"), got " << outputShape.getDimSize(1);
3799LogicalResult tosa::RowGatherBlockScaledOp::verify() {
3800 const OperandRange values = getValues();
3801 const ResultRange output = getOutput();
3802 if (values.empty() || values.size() > 2)
3804 <<
"expects values tensor list length to be 1 or 2, got "
3806 if (output.size() != values.size())
3808 <<
"expects output tensor list length to match values tensor list "
3810 << output.size() <<
" results for " << values.size()
3811 <<
" input tensors";
3813 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
3814 if (values.size() == 1 && blockSize != 1)
3816 <<
"requires block_size to be BLOCK_SIZE_1 when values tensor list "
3818 if (values.size() == 2 && blockSize == 1)
3820 <<
"requires block_size to not be BLOCK_SIZE_1 when values tensor "
3824 output[0].
getType(),
"values[0]",
3829 "values[1]",
"output[1]")))
3833 succeeded(rowCount) && rowCount.value() <= 0)
3834 return emitOpError() <<
"requires row_count to be > 0, got "
3835 << rowCount.value();
3837 int64_t n = ShapedType::kDynamic;
3838 int64_t k = ShapedType::kDynamic;
3839 int64_t c = ShapedType::kDynamic;
3840 int64_t w = ShapedType::kDynamic;
3841 int64_t multiplesOfC = ShapedType::kDynamic;
3843 const ShapeAdaptor valuesDataShape(values[0].
getType());
3844 if (valuesDataShape.hasRank()) {
3845 n = valuesDataShape.getDimSize(0);
3846 k = valuesDataShape.getDimSize(1);
3847 c = valuesDataShape.getDimSize(2);
3850 if (ShapedType::isStatic(c) && c % blockSize != 0)
3851 return emitOpError() <<
"expects channels of values[0] (" << c
3852 <<
") to be divisible by block_size (" << blockSize
3856 if (indicesShape.hasRank()) {
3858 "indices",
"batch")))
3860 w = indicesShape.getDimSize(1);
3863 const ShapeAdaptor outputDataShape(output[0].
getType());
3864 if (outputDataShape.hasRank()) {
3866 "output[0]",
"batch")) ||
3868 "output[0]",
"channels")))
3872 succeeded(rowCount) && rowCount.value() > 0 &&
3873 ShapedType::isStatic(w)) {
3874 const int64_t expectedOutputRows = w * rowCount.value();
3875 if (ShapedType::isStatic(outputDataShape.getDimSize(1)) &&
3876 outputDataShape.getDimSize(1) != expectedOutputRows)
3877 return emitOpError() <<
"requires output[0] dimension 1 to have size "
3878 << expectedOutputRows <<
", got "
3879 << outputDataShape.getDimSize(1);
3883 if (values.size() == 2) {
3884 const ShapeAdaptor valuesScaleShape(values[1].
getType());
3885 if (valuesScaleShape.hasRank()) {
3887 "values[1]",
"batch")) ||
3889 "values[1]",
"rows")))
3891 multiplesOfC = valuesScaleShape.getDimSize(2);
3894 const ShapeAdaptor outputScaleShape(output[1].
getType());
3895 if (outputScaleShape.hasRank()) {
3897 "output[1]",
"batch")))
3901 succeeded(rowCount) && rowCount.value() > 0 &&
3902 ShapedType::isStatic(w)) {
3903 const int64_t expectedOutputRows = w * rowCount.value();
3904 if (ShapedType::isStatic(outputScaleShape.getDimSize(1)) &&
3905 outputScaleShape.getDimSize(1) != expectedOutputRows)
3906 return emitOpError() <<
"requires output[1] dimension 1 to have size "
3907 << expectedOutputRows <<
", got "
3908 << outputScaleShape.getDimSize(1);
3911 if (ShapedType::isDynamic(multiplesOfC))
3912 multiplesOfC = outputScaleShape.getDimSize(2);
3913 else if (ShapedType::isStatic(outputScaleShape.getDimSize(2)) &&
3914 multiplesOfC != outputScaleShape.getDimSize(2))
3916 <<
"expected channels of output[1] to match size "
3917 << multiplesOfC <<
", got " << outputScaleShape.getDimSize(2);
3920 if (ShapedType::isStatic(c) && ShapedType::isStatic(multiplesOfC) &&
3921 multiplesOfC != c / blockSize)
3923 <<
"expects channels of scale tensors to equal C/block_size (" << c
3924 <<
"/" << blockSize <<
"), got " << multiplesOfC;
3930LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
3931 MLIRContext *context, ::std::optional<Location> location,
3932 ResizeOp::Adaptor adaptor,
3933 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
3934 llvm::SmallVector<int64_t, 4> outputShape;
3935 outputShape.resize(4, ShapedType::kDynamic);
3937 ShapeAdaptor inputShape(adaptor.getInput().getType());
3938 if (!inputShape.hasRank())
3941 outputShape[0] = inputShape.getDimSize(0);
3942 outputShape[3] = inputShape.getDimSize(3);
3943 int64_t inputHeight = inputShape.getDimSize(1);
3944 int64_t inputWidth = inputShape.getDimSize(2);
3946 if ((inputHeight == ShapedType::kDynamic) ||
3947 (inputWidth == ShapedType::kDynamic))
3950 SmallVector<int64_t> scaleInt, offsetInt, borderInt;
3961 const int64_t outputHeight =
3962 (((inputHeight - 1) * scaleInt[0] - offsetInt[0] + borderInt[0]) /
3966 const int64_t outputWidth =
3967 (((inputWidth - 1) * scaleInt[2] - offsetInt[1] + borderInt[1]) /
3971 if (outputHeight < 0 || outputWidth < 0) {
3974 "calculated output height and width must be non-negative, "
3976 outputHeight,
", width = ", outputWidth);
3979 outputShape[1] = outputHeight;
3980 outputShape[2] = outputWidth;
3981 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
3985LogicalResult tosa::ResizeOp::verify() {
3986 const Value input = getInput();
3987 const Value output = getOutput();
3988 const RankedTensorType inputType =
3989 llvm::dyn_cast<RankedTensorType>(input.
getType());
3990 const RankedTensorType outputType =
3991 llvm::dyn_cast<RankedTensorType>(output.
getType());
3993 SmallVector<int64_t> scaleValues;
3994 SmallVector<int64_t> offsetValues;
3995 SmallVector<int64_t> borderValues;
4003 if (llvm::any_of(scaleValues, [](int64_t s) {
return s <= 0; }))
4004 return emitOpError(
"expect all scale values to be > 0, got ")
4007 const int64_t scaleYN = scaleValues[0];
4008 const int64_t scaleYD = scaleValues[1];
4009 const int64_t scaleXN = scaleValues[2];
4010 const int64_t scaleXD = scaleValues[3];
4012 const int64_t offsetY = offsetValues[0];
4013 const int64_t offsetX = offsetValues[1];
4015 const int64_t borderY = borderValues[0];
4016 const int64_t borderX = borderValues[1];
4023 const int64_t oh = outputType.getDimSize(1);
4024 const int64_t ow = outputType.getDimSize(2);
4025 const int64_t ih = inputType.getDimSize(1);
4026 const int64_t iw = inputType.getDimSize(2);
4032 if (ih != ShapedType::kDynamic && ih != 1) {
4033 const std::optional<int64_t> calculatedOutHeightMinusOne =
4034 idivCheck((ih - 1) * scaleYN - offsetY + borderY, scaleYD);
4035 if (!calculatedOutHeightMinusOne.has_value())
4036 return emitOpError(
"expected (input_height - 1) * scale_y_n - offset_y + "
4038 <<
"to be wholly divisible by scale_y_d, got ((" << ih
4039 <<
" - 1) * " << scaleYN <<
" - " << offsetY <<
" + " << borderY
4040 <<
") / " << scaleYD;
4041 const int64_t calculatedOutHeight = calculatedOutHeightMinusOne.value() + 1;
4042 if (oh != ShapedType::kDynamic && calculatedOutHeight != oh)
4043 return emitOpError(
"calculated output height did not match expected: ")
4044 <<
"calculated=" << calculatedOutHeight <<
", expected=" << oh;
4051 if (iw != ShapedType::kDynamic && iw != 1) {
4052 const int64_t scaledInWidth = (iw - 1) * scaleXN - offsetX + borderX;
4053 const std::optional<int64_t> calculatedOutWidthMinusOne =
4055 if (!calculatedOutWidthMinusOne.has_value())
4056 return emitOpError(
"expected (input_width - 1) * scale_x_n - offset_x + "
4058 <<
"to be wholly divisible by scale_x_d, got ((" << iw
4059 <<
" - 1) * " << scaleXN <<
" - " << offsetX <<
" + " << borderX
4060 <<
") / " << scaleXD;
4061 const int64_t calculatedOutWidth = calculatedOutWidthMinusOne.value() + 1;
4062 if (ow != ShapedType::kDynamic && calculatedOutWidth != ow)
4063 return emitOpError(
"calculated output width did not match expected: ")
4064 <<
"calculated=" << calculatedOutWidth <<
", expected=" << ow;
4070LogicalResult tosa::ScatterOp::inferReturnTypeComponents(
4071 MLIRContext *context, ::std::optional<Location> location,
4072 ScatterOp::Adaptor adaptor,
4073 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4074 llvm::SmallVector<int64_t> outputShape;
4075 outputShape.resize(3, ShapedType::kDynamic);
4077 ShapeAdaptor valuesInShape(adaptor.getValuesIn().getType());
4078 if (valuesInShape.hasRank()) {
4079 outputShape[0] = valuesInShape.getDimSize(0);
4080 outputShape[1] = valuesInShape.getDimSize(1);
4081 outputShape[2] = valuesInShape.getDimSize(2);
4084 ShapeAdaptor indicesShape(adaptor.getIndices().getType());
4085 if (indicesShape.hasRank()) {
4086 if (outputShape[0] == ShapedType::kDynamic)
4087 outputShape[0] = indicesShape.getDimSize(0);
4090 ShapeAdaptor inputShape(adaptor.getInput().getType());
4091 if (inputShape.hasRank()) {
4092 if (outputShape[0] == ShapedType::kDynamic)
4093 outputShape[0] = inputShape.getDimSize(0);
4094 if (outputShape[2] == ShapedType::kDynamic)
4095 outputShape[2] = inputShape.getDimSize(2);
4098 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4102LogicalResult tosa::ScatterOp::verify() {
4112 const ShapeAdaptor valuesInShape(getValuesIn().
getType());
4114 const ShapeAdaptor inputShape(getInput().
getType());
4115 const ShapeAdaptor outputShape(getValuesOut().
getType());
4117 int64_t n = ShapedType::kDynamic;
4118 int64_t k = ShapedType::kDynamic;
4119 int64_t w = ShapedType::kDynamic;
4120 int64_t c = ShapedType::kDynamic;
4121 if (valuesInShape.hasRank()) {
4122 n = valuesInShape.getDimSize(0);
4123 k = valuesInShape.getDimSize(1);
4124 c = valuesInShape.getDimSize(2);
4126 if (indicesShape.hasRank()) {
4127 const int64_t indicesN = indicesShape.getDimSize(0);
4128 w = indicesShape.getDimSize(1);
4129 if (n == ShapedType::kDynamic)
4131 else if (indicesN != ShapedType::kDynamic && n != indicesN)
4132 return emitOpError() <<
"requires indices dimension 0 to have size " << n
4133 <<
", got " << indicesN;
4135 if (inputShape.hasRank()) {
4136 const int64_t inputN = inputShape.getDimSize(0);
4137 const int64_t inputW = inputShape.getDimSize(1);
4138 const int64_t inputC = inputShape.getDimSize(2);
4139 if (n == ShapedType::kDynamic)
4141 else if (inputN != ShapedType::kDynamic && n != inputN)
4142 return emitOpError() <<
"requires input dimension 0 to have size " << n
4143 <<
", got " << inputN;
4144 if (w == ShapedType::kDynamic)
4146 else if (inputW != ShapedType::kDynamic && w != inputW)
4147 return emitOpError() <<
"requires input dimension 1 to have size " << w
4148 <<
", got " << inputW;
4150 if (c == ShapedType::kDynamic)
4152 else if (inputC != ShapedType::kDynamic && c != inputC)
4153 return emitOpError() <<
"requires input dimension 2 to have size " << c
4154 <<
", got " << inputC;
4156 if (outputShape.hasRank()) {
4157 const int64_t outputN = outputShape.getDimSize(0);
4158 const int64_t outputK = outputShape.getDimSize(1);
4159 const int64_t outputC = outputShape.getDimSize(2);
4160 if (n != ShapedType::kDynamic && outputN != ShapedType::kDynamic &&
4162 return emitOpError() <<
"requires values_out dimension 0 to have size "
4163 << n <<
", got " << outputN;
4164 if (k == ShapedType::kDynamic)
4166 else if (outputK != ShapedType::kDynamic && k != outputK)
4167 return emitOpError() <<
"requires values_out dimension 1 to have size "
4168 << k <<
", got " << outputK;
4169 if (c != ShapedType::kDynamic && outputC != ShapedType::kDynamic &&
4171 return emitOpError() <<
"requires values_out dimension 2 to have size "
4172 << c <<
", got " << outputC;
4174 if (k != ShapedType::kDynamic && w != ShapedType::kDynamic && !(k >= w))
4175 return emitOpError() <<
"requires dimensions K >= W, got K=" << k
4184 int64_t axisVal = axis.getValue().getSExtValue();
4185 if (!operandShape.
hasRank() || operandShape.
getRank() <= axisVal) {
4191 operandShape.
getDims(outputShape);
4192 outputShape[axisVal] = 1;
4197#define COMPATIBLE_RETURN_TYPES(OP) \
4198 bool OP::isCompatibleReturnTypes(TypeRange l, TypeRange r) { \
4199 if (l.size() != r.size() || l.size() != 1) \
4201 if (getElementTypeOrSelf(l[0]) != getElementTypeOrSelf(r[0])) \
4203 return succeeded(verifyCompatibleShape(l[0], r[0])); \
4206#define REDUCE_SHAPE_INFER(OP) \
4207 LogicalResult OP::inferReturnTypeComponents( \
4208 MLIRContext *context, ::std::optional<Location> location, \
4209 OP::Adaptor adaptor, \
4210 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) { \
4212 llvm::cast<TensorType>(adaptor.getInput().getType()).getElementType(); \
4213 ShapeAdaptor inputShape(adaptor.getInput().getType()); \
4214 const Properties &prop = adaptor.getProperties(); \
4215 return ReduceInferReturnTypes(inputShape, inputType, prop.axis, \
4216 inferredReturnShapes); \
4218 COMPATIBLE_RETURN_TYPES(OP)
4226#undef REDUCE_SHAPE_INFER
4228#undef COMPATIBLE_RETURN_TYPES
4230template <
typename T>
4233 TensorType inputType = op.getInput().getType();
4234 TensorType outputType = op.getOutput().getType();
4235 int32_t reduceAxis = op.getAxis();
4237 if (reduceAxis < 0) {
4238 op.emitOpError(
"reduce axis must not be negative");
4242 int64_t inputRank = inputType.getRank();
4245 if (reduceAxis >= inputRank && (reduceAxis != 0 || inputRank != 0)) {
4246 op.emitOpError(
"expect input tensor rank (")
4247 << inputRank <<
") to be larger than reduce axis (" << reduceAxis
4253 int64_t outputRank = outputType.getRank();
4254 if (inputType.
hasRank() && outputRank != inputType.getRank()) {
4256 "expect output tensor rank to be equal to input tensor rank");
4259 if (reduceAxis >= outputRank && (reduceAxis != 0 || outputRank != 0)) {
4260 op.emitOpError(
"expect output tensor rank (")
4261 << outputRank <<
") to be larger than reduce axis (" << reduceAxis
4267 if (outputRank != 0) {
4268 auto outputShape = outputType.
getShape();
4269 if (!outputType.isDynamicDim(reduceAxis) &&
4270 outputShape[reduceAxis] != 1) {
4271 op.emitOpError(
"expect reduced dimension size to be 1, got ")
4272 << outputShape[reduceAxis];
4280LogicalResult tosa::ReduceAllOp::verify() {
return verifyReduceOp(*
this); }
4281LogicalResult tosa::ReduceAnyOp::verify() {
return verifyReduceOp(*
this); }
4282LogicalResult tosa::ReduceMaxOp::verify() {
return verifyReduceOp(*
this); }
4283LogicalResult tosa::ReduceMinOp::verify() {
return verifyReduceOp(*
this); }
4284LogicalResult tosa::ReduceProductOp::verify() {
return verifyReduceOp(*
this); }
4285LogicalResult tosa::ReduceSumOp::verify() {
return verifyReduceOp(*
this); }
4299#define NARY_SHAPE_INFER(OP) \
4300 LogicalResult OP::inferReturnTypeComponents( \
4301 MLIRContext *context, ::std::optional<Location> location, \
4302 ValueShapeRange operands, DictionaryAttr attributes, \
4303 PropertyRef properties, RegionRange regions, \
4304 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) { \
4305 return NAryInferReturnTypes(operands, inferredReturnShapes); \
4345#undef PRED_SHAPE_INFER
4347LogicalResult tosa::NegateOp::inferReturnTypeComponents(
4348 MLIRContext *context, ::std::optional<Location> location,
4349 NegateOp::Adaptor adaptor,
4351 ShapeAdaptor inputShape(adaptor.getInput1().getType());
4356LogicalResult tosa::NegateOp::verify() {
4358 const Type input1Type = getInput1().getType();
4359 const Type outputType = getOutput().getType();
4364 const SmallVector<Type, 2> types = {input1Type, outputType};
4366 return emitOpError() <<
"requires the same shape for input1 and output";
4369 const Type input1ZpEType =
4371 if (input1EType != input1ZpEType) {
4372 return emitOpError(
"expect both input1 and its zero point are the same "
4373 "element type, got ")
4374 << input1EType <<
" and " << input1ZpEType;
4377 const Type outputZpEType =
4379 if (outputEType != outputZpEType) {
4380 return emitOpError(
"expect both output and its zero point are the same "
4381 "element type, got ")
4382 << outputEType <<
" and " << outputZpEType;
4385 FailureOr<int64_t> maybeIZp = getInput1ZeroPoint();
4386 if (succeeded(maybeIZp) && verifyInput1ZeroPoint(*maybeIZp).failed())
4389 FailureOr<int64_t> maybeOZp = getOutputZeroPoint();
4390 if (succeeded(maybeOZp) && verifyOutputZeroPoint(*maybeOZp).failed())
4401 outputShape.resize(4, ShapedType::kDynamic);
4416 if (ShapedType::isStatic(height)) {
4417 int64_t padded = height + pad[0] + pad[1] - kernel[0];
4418 outputShape[1] = padded / stride[0] + 1;
4421 if (ShapedType::isStatic(width)) {
4422 int64_t padded = width + pad[2] + pad[3] - kernel[1];
4423 outputShape[2] = padded / stride[1] + 1;
4430template <
typename AdaptorT>
4436 if (ShapedType::isDynamic(current))
4437 current = candidate;
4446 : adaptor(adaptor) {}
4450 const ShapeAdaptor inputShape(adaptor.getInput().getType());
4458 outputShape[0] = outputBatch;
4459 inputSpatial[0] = inputHeight;
4460 inputSpatial[1] = inputWidth;
4465 const ShapeAdaptor weightShape(adaptor.getWeight().getType());
4473 outputShape[3] = outputChannels;
4474 weightSpatial[0] = kernelHeight;
4475 weightSpatial[1] = kernelWidth;
4484 padValues.assign(adaptor.getPad().begin(), adaptor.getPad().end());
4485 strideValues.assign(adaptor.getStride().begin(), adaptor.getStride().end());
4486 dilationValues.assign(adaptor.getDilation().begin(),
4487 adaptor.getDilation().end());
4492 Conv2DOp::Adaptor adaptor;
4500 : adaptor(adaptor) {}
4504 const ShapeAdaptor inputDataShape(adaptor.getInputData().getType());
4505 if (inputDataShape.
hasRank()) {
4510 outputShape[0] = outputBatch;
4511 inputSpatial[0] = inputHeight;
4512 inputSpatial[1] = inputWidth;
4515 const ShapeAdaptor inputScaleShape(adaptor.getInputScale().getType());
4516 if (!inputScaleShape.
hasRank())
4530 const ShapeAdaptor weightDataShape(adaptor.getWeightData().getType());
4531 if (weightDataShape.
hasRank()) {
4536 outputShape[3] = outputChannels;
4537 weightSpatial[0] = kernelHeight;
4538 weightSpatial[1] = kernelWidth;
4541 const ShapeAdaptor weightScaleShape(adaptor.getWeightScale().getType());
4542 if (!weightScaleShape.
hasRank())
4571 Conv2DBlockScaledOp::Adaptor adaptor;
4579 : adaptor(adaptor) {}
4583 const ShapeAdaptor inputShape(adaptor.getInput().getType());
4592 outputShape[0] = outputBatch;
4593 inputSpatial[0] = inputDepth;
4594 inputSpatial[1] = inputHeight;
4595 inputSpatial[2] = inputWidth;
4600 const ShapeAdaptor weightShape(adaptor.getWeight().getType());
4609 outputShape[4] = outputChannels;
4610 weightSpatial[0] = kernelDepth;
4611 weightSpatial[1] = kernelHeight;
4612 weightSpatial[2] = kernelWidth;
4621 padValues.assign(adaptor.getPad().begin(), adaptor.getPad().end());
4622 strideValues.assign(adaptor.getStride().begin(), adaptor.getStride().end());
4623 dilationValues.assign(adaptor.getDilation().begin(),
4624 adaptor.getDilation().end());
4629 Conv3DOp::Adaptor adaptor;
4632template <
typename AdaptorT>
4638 ShapedType::kDynamic);
4640 ShapedType::kDynamic);
4642 ShapedType::kDynamic);
4644 convShapeAdaptor.inferInputShape(outputShape, inputSpatial);
4645 convShapeAdaptor.inferWeightShape(outputShape, weightSpatial);
4647 const ShapeAdaptor biasShape = adaptor.getBias().getType();
4650 if (biasSize != 1) {
4651 const size_t outputChannelDim = convShapeAdaptor.getOutputRank() - 1;
4652 outputShape[outputChannelDim] =
4653 ShapedType::isDynamic(outputShape[outputChannelDim])
4655 : outputShape[outputChannelDim];
4662 if (failed(convShapeAdaptor.getSpatialParameters(padValues, strideValues,
4668 for (
int64_t dim = 0; dim < convShapeAdaptor.getNumSpatialDims(); ++dim) {
4669 if (!ShapedType::isStatic(inputSpatial[dim]) ||
4670 !ShapedType::isStatic(weightSpatial[dim]))
4673 inputSpatial[dim] + padValues[2 * dim] + padValues[2 * dim + 1];
4675 (weightSpatial[dim] - 1) * dilationValues[dim] + 1;
4676 const int64_t unstridedResult = inputSize - filterSize + 1;
4677 outputShape[dim + 1] = (unstridedResult - 1) / strideValues[dim] + 1;
4684LogicalResult Conv2DOp::inferReturnTypeComponents(
4685 MLIRContext *context, ::std::optional<Location> location,
4686 Conv2DOp::Adaptor adaptor,
4687 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4691LogicalResult Conv2DOp::verify() {
4698LogicalResult Conv2DBlockScaledOp::inferReturnTypeComponents(
4699 MLIRContext *context, ::std::optional<Location> location,
4700 Conv2DBlockScaledOp::Adaptor adaptor,
4701 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4705LogicalResult Conv2DBlockScaledOp::verify() {
4707 getWeightData().
getType(),
"input_data",
4710 getWeightScale().
getType(),
"input_scale",
4713 getOutput().
getType(),
"bias",
"output")))
4717 int64_t N = ShapedType::kDynamic;
4718 int64_t IH = ShapedType::kDynamic;
4719 int64_t IW = ShapedType::kDynamic;
4720 int64_t IC = ShapedType::kDynamic;
4721 int64_t multiplesOfIC = ShapedType::kDynamic;
4722 int64_t OC = ShapedType::kDynamic;
4723 int64_t KH = ShapedType::kDynamic;
4724 int64_t KW = ShapedType::kDynamic;
4726 const ShapeAdaptor inputDataShape(getInputData().
getType());
4727 if (inputDataShape.hasRank()) {
4728 N = inputDataShape.getDimSize(0);
4729 IH = inputDataShape.getDimSize(1);
4730 IW = inputDataShape.getDimSize(2);
4731 IC = inputDataShape.getDimSize(3);
4734 const ShapeAdaptor inputScaleShape(getInputScale().
getType());
4735 if (inputScaleShape.hasRank()) {
4737 "input_scale",
"batch size")) ||
4739 "input_scale",
"input height")) ||
4741 "input_scale",
"input width")))
4743 multiplesOfIC = inputScaleShape.getDimSize(3);
4746 const ShapeAdaptor weightDataShape(getWeightData().
getType());
4747 if (weightDataShape.hasRank()) {
4748 OC = weightDataShape.getDimSize(0);
4749 KH = weightDataShape.getDimSize(1);
4750 KW = weightDataShape.getDimSize(2);
4752 "weight_data",
"input channels")))
4756 const ShapeAdaptor weightScaleShape(getWeightScale().
getType());
4757 if (weightScaleShape.hasRank()) {
4759 "weight_scale",
"output channels")) ||
4761 "weight_scale",
"kernel height")) ||
4763 "weight_scale",
"kernel width")) ||
4765 weightScaleShape.getDimSize(3),
4766 "weight_scale",
"input channel blocks")))
4770 const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(
getBlockSize());
4771 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
4772 return emitOpError(
"expect block size to be 32, got ") << blockSize;
4774 if (ShapedType::isStatic(IC) && IC % blockSize != 0)
4775 return emitOpError(
"expect IC to be a multiple of block size, got IC=")
4776 << IC <<
", block_size=" << blockSize;
4779 if (ShapedType::isStatic(IC) && ShapedType::isStatic(multiplesOfIC) &&
4780 multiplesOfIC != IC / blockSize)
4782 "expect scale operands dimension 2 to equal IC/block_size (")
4783 << IC <<
"/" << blockSize <<
")"
4784 <<
", got " << multiplesOfIC;
4787 SmallVector<int64_t> padValues;
4789 if (llvm::any_of(padValues, [](int64_t p) {
return p < 0; }))
4790 return emitOpError(
"expect all padding values to be >= 0, got ")
4794 SmallVector<int64_t> strideValues;
4796 if (llvm::any_of(strideValues, [](int64_t s) {
return s < 1; }))
4797 return emitOpError(
"expect all stride values to be >= 1, got ")
4801 SmallVector<int64_t> dilationValues;
4804 if (llvm::any_of(dilationValues, [](int64_t d) {
return d < 1; }))
4805 return emitOpError(
"expect all dilation values to be >= 1, got ")
4810 const ShapeAdaptor outputShape(getOutput().
getType());
4811 if (!padValues.empty() && !strideValues.empty() && !dilationValues.empty() &&
4812 outputShape.hasRank()) {
4814 padValues[0], padValues[1], strideValues[0],
4815 dilationValues[0],
"height",
"y",
"top",
4818 padValues[2], padValues[3], strideValues[1],
4819 dilationValues[1],
"width",
"x",
"left",
4825 const ShapeAdaptor biasShape(getBias().
getType());
4826 if (biasShape.hasRank() && outputShape.hasRank()) {
4827 const int64_t biasChannels = biasShape.getDimSize(0);
4828 const int64_t outputChannels =
4829 outputShape.getDimSize(outputShape.getRank() - 1);
4830 if (biasChannels == ShapedType::kDynamic ||
4831 outputChannels == ShapedType::kDynamic)
4835 if (biasChannels != outputChannels && biasChannels != 1)
4837 "bias channels expected to be equal to output channels (")
4838 << outputChannels <<
") or 1, got " << biasChannels;
4844LogicalResult Conv3DOp::inferReturnTypeComponents(
4845 MLIRContext *context, ::std::optional<Location> location,
4846 Conv3DOp::Adaptor adaptor,
4847 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4851LogicalResult Conv3DOp::verify() {
4858LogicalResult AvgPool2dOp::inferReturnTypeComponents(
4859 MLIRContext *context, ::std::optional<Location> location,
4860 AvgPool2dOp::Adaptor adaptor,
4861 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4862 ShapeAdaptor inputShape(adaptor.getInput().getType());
4863 const Properties &prop = adaptor.getProperties();
4865 inferredReturnShapes);
4868LogicalResult AvgPool2dAdaptiveOp::inferReturnTypeComponents(
4869 MLIRContext *context, ::std::optional<Location> location,
4870 AvgPool2dAdaptiveOp::Adaptor adaptor,
4871 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4872 ShapeAdaptor inputShape(adaptor.getInput().getType());
4874 llvm::SmallVector<int64_t> kernelValues;
4875 llvm::SmallVector<int64_t> strideValues;
4876 llvm::SmallVector<int64_t> padValues;
4883 padValues, inferredReturnShapes);
4886 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4887 if (inputShape.hasRank()) {
4889 outputShape[0] = inputShape.getDimSize(0);
4890 outputShape[3] = inputShape.getDimSize(3);
4893 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4897LogicalResult MaxPool2dOp::inferReturnTypeComponents(
4898 MLIRContext *context, ::std::optional<Location> location,
4899 MaxPool2dOp::Adaptor adaptor,
4900 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4901 ShapeAdaptor inputShape(adaptor.getInput().getType());
4902 const Properties &prop = adaptor.getProperties();
4904 inferredReturnShapes);
4907LogicalResult MaxPool2dAdaptiveOp::inferReturnTypeComponents(
4908 MLIRContext *context, ::std::optional<Location> location,
4909 MaxPool2dAdaptiveOp::Adaptor adaptor,
4910 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4911 ShapeAdaptor inputShape(adaptor.getInput().getType());
4913 llvm::SmallVector<int64_t> kernelValues;
4914 llvm::SmallVector<int64_t> strideValues;
4915 llvm::SmallVector<int64_t> padValues;
4922 padValues, inferredReturnShapes);
4925 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4926 if (inputShape.hasRank()) {
4927 outputShape[0] = inputShape.getDimSize(0);
4928 outputShape[3] = inputShape.getDimSize(3);
4930 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
4934LogicalResult MaxPool2dOp::verify() {
4945LogicalResult MaxPool2dAdaptiveOp::verify() {
4950 AdaptivePoolingConstShapeValues values;
4954 values.pad, getInput(), getOutput())))
4960LogicalResult DepthwiseConv2DOp::inferReturnTypeComponents(
4961 MLIRContext *context, ::std::optional<Location> location,
4962 DepthwiseConv2DOp::Adaptor adaptor,
4963 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
4964 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
4966 int64_t inputWidth = ShapedType::kDynamic;
4967 int64_t inputHeight = ShapedType::kDynamic;
4968 int64_t inputChannels = ShapedType::kDynamic;
4970 int64_t weightWidth = ShapedType::kDynamic;
4971 int64_t weightHeight = ShapedType::kDynamic;
4972 int64_t depthChannels = ShapedType::kDynamic;
4975 ShapeAdaptor inputShape(adaptor.getInput().getType());
4976 if (inputShape.hasRank()) {
4977 outputShape[0] = inputShape.getDimSize(0);
4978 inputHeight = inputShape.getDimSize(1);
4979 inputWidth = inputShape.getDimSize(2);
4980 inputChannels = inputShape.getDimSize(3);
4984 ShapeAdaptor weightShape(adaptor.getWeight().getType());
4985 if (weightShape.hasRank()) {
4986 weightHeight = weightShape.getDimSize(0);
4987 weightWidth = weightShape.getDimSize(1);
4988 inputChannels = ShapedType::isDynamic(inputChannels)
4989 ? weightShape.getDimSize(2)
4991 depthChannels = weightShape.getDimSize(3);
4996 if (ShapedType::isStatic(inputChannels) &&
4997 ShapedType::isStatic(depthChannels)) {
4998 outputShape[3] = inputChannels * depthChannels;
5002 ShapeAdaptor biasShape(adaptor.getBias().getType());
5003 if (biasShape.hasRank() && ShapedType::isDynamic(outputShape[3])) {
5004 int64_t bc = biasShape.getDimSize(0);
5005 if (bc != ShapedType::kDynamic && bc != 1)
5006 outputShape[3] = bc;
5009 llvm::ArrayRef<int64_t> dilation = adaptor.getDilation();
5010 llvm::ArrayRef<int64_t> padding = adaptor.getPad();
5011 llvm::ArrayRef<int64_t> stride = adaptor.getStride();
5013 if (ShapedType::isStatic(inputHeight) && ShapedType::isStatic(weightHeight)) {
5014 int64_t inputSize = inputHeight + padding[0] + padding[1];
5015 int64_t filterSize = (weightHeight - 1) * dilation[0] + 1;
5016 int64_t unstridedResult = inputSize - filterSize + 1;
5017 outputShape[1] = (unstridedResult - 1) / stride[0] + 1;
5020 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(weightWidth)) {
5021 int64_t inputSize = inputWidth + padding[2] + padding[3];
5022 int64_t filterSize = (weightWidth - 1) * dilation[1] + 1;
5023 int64_t unstridedResult = inputSize - filterSize + 1;
5024 outputShape[2] = (unstridedResult - 1) / stride[1] + 1;
5027 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
5031LogicalResult DepthwiseConv2DOp::verify() {
5038LogicalResult TransposeConv2DOp::inferReturnTypeComponents(
5039 MLIRContext *context, ::std::optional<Location> location,
5040 TransposeConv2DOp::Adaptor adaptor,
5041 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5042 llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
5044 int64_t inputWidth = ShapedType::kDynamic;
5045 int64_t inputHeight = ShapedType::kDynamic;
5046 int64_t weightWidth = ShapedType::kDynamic;
5047 int64_t weightHeight = ShapedType::kDynamic;
5050 ShapeAdaptor inputShape(adaptor.getInput().getType());
5051 if (inputShape.hasRank()) {
5052 outputShape[0] = ShapedType::isDynamic(outputShape[0])
5053 ? inputShape.getDimSize(0)
5055 inputHeight = inputShape.getDimSize(1);
5056 inputWidth = inputShape.getDimSize(2);
5060 ShapeAdaptor weightShape(adaptor.getWeight().getType());
5061 if (weightShape.hasRank()) {
5062 outputShape[3] = ShapedType::isDynamic(outputShape[3])
5063 ? weightShape.getDimSize(0)
5065 weightHeight = weightShape.getDimSize(1);
5066 weightWidth = weightShape.getDimSize(2);
5070 ShapeAdaptor biasShape(adaptor.getBias().getType());
5071 if (biasShape.hasRank() && ShapedType::isDynamic(outputShape[3])) {
5072 int64_t bc = biasShape.getDimSize(0);
5073 if (bc != ShapedType::kDynamic && bc != 1)
5074 outputShape[3] = bc;
5077 llvm::ArrayRef<int64_t> padding = adaptor.getOutPad();
5078 llvm::ArrayRef<int64_t> stride = adaptor.getStride();
5080 if (ShapedType::isStatic(inputHeight) && ShapedType::isStatic(weightHeight)) {
5081 int64_t calculateSize =
5082 (inputHeight - 1) * stride[0] + padding[0] + padding[1] + weightHeight;
5084 ShapedType::isDynamic(outputShape[1]) ? calculateSize : outputShape[1];
5087 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(weightWidth)) {
5088 int64_t calculateSize =
5089 (inputWidth - 1) * stride[1] + padding[2] + padding[3] + weightWidth;
5091 ShapedType::isDynamic(outputShape[2]) ? calculateSize : outputShape[2];
5094 inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
5098LogicalResult TransposeConv2DOp::verify() {
5102 const llvm::ArrayRef<int64_t> strides = getStride();
5103 const int64_t strideY = strides[0];
5104 const int64_t strideX = strides[1];
5106 if (strideY < 1 || strideX < 1)
5107 return emitOpError(
"expect all stride values to be >= 1, got [")
5110 const auto checkPadAgainstKernelDim =
5111 [
this](int64_t padValue, int64_t kernelDimSize, llvm::StringRef padName,
5112 llvm::StringRef kernelDimName) -> LogicalResult {
5113 if (padValue <= -kernelDimSize)
5115 << padName <<
" > -" << kernelDimName <<
", but got: " << padName
5116 <<
"=" << padValue <<
" and " << kernelDimName <<
"="
5121 const llvm::ArrayRef<int64_t> padding = getOutPad();
5122 const int64_t outPadTop = padding[0];
5123 const int64_t outPadBottom = padding[1];
5124 const int64_t outPadLeft = padding[2];
5125 const int64_t outPadRight = padding[3];
5127 const auto weightType =
5128 llvm::dyn_cast<RankedTensorType>(getWeight().
getType());
5131 const int64_t kernelHeight = weightType.getDimSize(1);
5132 if (ShapedType::isStatic(kernelHeight)) {
5133 if (
failed(checkPadAgainstKernelDim(outPadTop, kernelHeight,
5134 "out_pad_top",
"KH")))
5137 if (
failed(checkPadAgainstKernelDim(outPadBottom, kernelHeight,
5138 "out_pad_bottom",
"KH")))
5142 const int64_t kernelWidth = weightType.getDimSize(2);
5143 if (ShapedType::isStatic(kernelWidth)) {
5144 if (
failed(checkPadAgainstKernelDim(outPadLeft, kernelWidth,
5145 "out_pad_left",
"KW")))
5148 if (
failed(checkPadAgainstKernelDim(outPadRight, kernelWidth,
5149 "out_pad_right",
"KW")))
5155 const auto outputType =
5156 llvm::dyn_cast<RankedTensorType>(getOutput().
getType());
5160 const auto inputType = llvm::dyn_cast<RankedTensorType>(getInput().
getType());
5161 if (inputType && weightType) {
5162 const int64_t inputHeight = inputType.getDimSize(1);
5163 const int64_t kernelHeight = weightType.getDimSize(1);
5164 const int64_t outputHeight = outputType.getDimSize(1);
5166 if (ShapedType::isStatic(inputHeight) &&
5167 ShapedType::isStatic(outputHeight)) {
5169 (inputHeight - 1) * strideY + outPadTop + outPadBottom + kernelHeight)
5171 "dimension mismatch: expected OH == (IH - 1) * stride_y "
5172 "+ out_pad_top + out_pad_bottom + KH, but got ")
5173 << outputHeight <<
" != (" << inputHeight <<
" - 1) * "
5174 << strideY <<
" + " << outPadTop <<
" + " << outPadBottom
5175 <<
" + " << kernelHeight;
5178 const int64_t inputWidth = inputType.getDimSize(2);
5179 const int64_t kernelWidth = weightType.getDimSize(2);
5180 const int64_t outputWidth = outputType.getDimSize(2);
5182 if (ShapedType::isStatic(inputWidth) && ShapedType::isStatic(outputWidth)) {
5184 (inputWidth - 1) * strideX + outPadLeft + outPadRight + kernelWidth)
5186 "dimension mismatch: expected OW == (IW - 1) * stride_x "
5187 "+ out_pad_left + out_pad_right + KW, but got ")
5188 << outputWidth <<
" != (" << inputWidth <<
" - 1) * " << strideX
5189 <<
" + " << outPadLeft <<
" + " << outPadRight <<
" + "
5194 const auto biasType = llvm::dyn_cast<RankedTensorType>(getBias().
getType());
5199 const int64_t biasChannels = biasType.getDimSize(0);
5202 if (biasChannels == ShapedType::kDynamic)
5205 const int64_t outputChannels = outputType.getDimSize(3);
5206 if (!ShapedType::isDynamic(outputChannels) &&
5207 biasChannels != outputChannels && biasChannels != 1)
5209 "bias channels expected to be equal to output channels (")
5210 << outputChannels <<
") or 1, got " << biasChannels;
5215LogicalResult RescaleOp::verify() {
5216 const auto inputType = llvm::cast<ShapedType>(getInput().
getType());
5217 auto inputElementType =
5219 if (!mlir::isa<IntegerType>(inputElementType)) {
5220 emitOpError(
"expect input to have integer element type, got ")
5221 << inputElementType;
5225 const auto outputType = llvm::cast<ShapedType>(getOutput().
getType());
5226 auto outputElementType =
5228 if (!mlir::isa<IntegerType>(outputElementType)) {
5229 emitOpError(
"expect output to have integer element type, got ")
5230 << outputElementType;
5242 FailureOr<int64_t> maybeIZp = getInputZeroPoint();
5243 if (succeeded(maybeIZp) && verifyInputZeroPoint(*maybeIZp).failed())
5246 FailureOr<int64_t> maybeOZp = getOutputZeroPoint();
5247 if (succeeded(maybeOZp) && verifyOutputZeroPoint(*maybeOZp).failed())
5250 const auto multiplierType = llvm::cast<ShapedType>(getMultiplier().
getType());
5252 if (getScale32() && !multiplierType.getElementType().isInteger(32)) {
5253 emitOpError(
"expect i32 element type for multiplier for scale32=true, got ")
5254 << multiplierType.getElementType();
5259 if (!getScale32() && !multiplierType.getElementType().isInteger(16)) {
5261 "expect i16 element type for multiplier for scale32=false, got ")
5262 << multiplierType.getElementType();
5266 if (!inputType.hasRank())
5272 int64_t numChannels = 1;
5273 if (getPerChannel()) {
5274 if (inputType.getRank() < 1) {
5275 emitOpError(
"requires input to be at least rank 1 when per_channel is "
5276 "true, but got rank ")
5277 << inputType.getRank();
5280 numChannels = inputType.getDimSize(inputType.getRank() - 1);
5283 if (outputType.hasRank()) {
5285 getOperation(), outputType, inputType.getShape())))
5289 if (multiplierType.hasRank()) {
5290 ArrayRef<int64_t> multiplierShape = multiplierType.getShape();
5292 if (multiplierShape[0] != ShapedType::kDynamic &&
5293 multiplierShape[0] != numChannels) {
5295 << numChannels <<
" } for multiplier input, got { "
5296 << multiplierShape[0] <<
" }";
5301 const auto shiftType = llvm::cast<ShapedType>(getShift().
getType());
5302 if (shiftType.hasRank()) {
5303 ArrayRef<int64_t> shiftShape = shiftType.getShape();
5305 if (shiftShape[0] != ShapedType::kDynamic && shiftShape[0] != numChannels) {
5307 << numChannels <<
" } for shift input, got { " << shiftShape[0]
5316LogicalResult RescaleOp::inferReturnTypeComponents(
5317 MLIRContext *context, ::std::optional<Location> location,
5318 RescaleOp::Adaptor adaptor,
5319 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5320 ShapeAdaptor inputShape(adaptor.getInput().getType());
5321 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5325LogicalResult CastOp::verify() {
5326 const ShapedType inputType = llvm::cast<ShapedType>(getInput().
getType());
5327 const ShapedType outputType = llvm::cast<ShapedType>(
getType());
5328 const Type inputElementType = inputType.getElementType();
5329 const Type outputElementType = outputType.getElementType();
5331 const bool inputIsBlockScaled = llvm::isa<BlockScaledType>(inputElementType);
5332 const bool outputIsBlockScaled =
5333 llvm::isa<BlockScaledType>(outputElementType);
5334 if (!inputIsBlockScaled && !outputIsBlockScaled)
5337 if (inputIsBlockScaled && outputIsBlockScaled)
5339 <<
"requires exactly one of input or output to have block scaled "
5342 const Type scalarElementType =
5343 inputIsBlockScaled ? outputElementType : inputElementType;
5344 if (!llvm::isa<FloatType>(scalarElementType))
5346 <<
"requires non-block-scaled element type to be floating-point "
5347 "when casting to or from block scaled element type, got "
5348 << scalarElementType;
5353LogicalResult CastFromBlockScaledOp::inferReturnTypeComponents(
5354 MLIRContext *context, ::std::optional<Location> location,
5355 CastFromBlockScaledOp::Adaptor adaptor,
5356 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5357 const ShapeAdaptor inputShape(adaptor.getInputData().getType());
5358 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5362LogicalResult CastFromBlockScaledOp::verify() {
5363 const Type inputDataType = getInputData().getType();
5364 const Type outputDataType = getResult().getType();
5366 return emitOpError() <<
"require compatible shapes for input_data ("
5367 << inputDataType <<
") and " <<
"output_data ("
5368 << outputDataType <<
")";
5370 const ShapeAdaptor inputDataShape = ShapeAdaptor(inputDataType);
5372 if (inputDataShape.
hasRank()) {
5373 const unsigned int blockSize =
5375 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
5376 return emitOpError(
"expect block size to be 32, got ") << blockSize;
5377 const int64_t inputDataLastDim =
5379 if (inputDataLastDim % blockSize != 0)
5380 return emitOpError() <<
"expect last dimension of input_data ("
5382 <<
") to be divisible by block_size (" << blockSize
5385 const Type inputScaleType = getInputScale().getType();
5386 const ShapeAdaptor inputScaleShape = ShapeAdaptor(inputScaleType);
5388 if (inputScaleShape.
hasRank()) {
5389 SmallVector<int64_t> inputDataDims, inputScaleDims;
5390 inputDataShape.
getDims(inputDataDims);
5391 inputScaleShape.
getDims(inputScaleDims);
5393 if (inputDataDims.size() != inputScaleDims.size() ||
5395 ArrayRef<int64_t>(inputDataDims).drop_back(1),
5396 ArrayRef<int64_t>(inputScaleDims).drop_back(1))))
5398 <<
"require compatible shapes for input_data (" << inputDataType
5399 <<
") and " <<
"input_scale (" << inputScaleType
5400 <<
") except for the last dimension";
5402 const SmallVector<int64_t, 2> dimsToCheck{inputDataLastDim / blockSize,
5403 inputScaleDims.back()};
5404 if (ShapedType::isStatic(inputDataLastDim) &&
5407 <<
"expect last dimension of input_scale ("
5408 << inputScaleDims.back()
5409 <<
") to be equal to last dimension of input_data / block_size ("
5410 << inputDataDims.back() / blockSize <<
")";
5417LogicalResult CastToBlockScaledOp::inferReturnTypeComponents(
5418 MLIRContext *context, ::std::optional<Location> location,
5419 CastToBlockScaledOp::Adaptor adaptor,
5420 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5421 const ShapeAdaptor inputShape(adaptor.getInputData().getType());
5422 inferredReturnShapes.push_back(ShapedTypeComponents(inputShape));
5423 if (!inputShape.hasRank())
5427 SmallVector<int64_t> outputScaleShape;
5428 inputShape.getDims(outputScaleShape);
5429 const int64_t lastDimLoc = inputShape.getRank() - 1;
5430 const int64_t lastDimSize = inputShape.getDimSize(lastDimLoc);
5431 if (ShapedType::isStatic(lastDimSize)) {
5432 const unsigned int blockSize =
5433 BlockSizeAttr::getBlockSizeValue(adaptor.getBlockSize());
5434 outputScaleShape[lastDimLoc] = lastDimSize / blockSize;
5436 inferredReturnShapes.push_back(ShapedTypeComponents(outputScaleShape));
5440LogicalResult CastToBlockScaledOp::verify() {
5441 const Type inputDataType = getInputData().getType();
5442 const Type outputDataType = getResult(0).getType();
5444 return emitOpError() <<
"require compatible shapes for input_data ("
5445 << inputDataType <<
") and " <<
"output_data ("
5446 << outputDataType <<
")";
5448 const unsigned int blockSize =
5450 if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
5451 return emitOpError(
"expect block size to be 32, got ") << blockSize;
5452 const ShapeAdaptor inputDataShape = ShapeAdaptor(inputDataType);
5453 if (inputDataShape.
hasRank()) {
5454 const int64_t inputDataLastDim =
5456 if (ShapedType::isStatic(inputDataLastDim) &&
5457 inputDataLastDim % blockSize != 0)
5458 return emitOpError() <<
"expect last dimension of input_data ("
5460 <<
") to be divisible by block_size (" << blockSize
5464 const ShapeAdaptor outputDataShape = ShapeAdaptor(outputDataType);
5465 const Type outputScaleType = getResult(1).getType();
5466 const ShapeAdaptor outputScaleShape = ShapeAdaptor(outputScaleType);
5468 SmallVector<int64_t> outputDataDims, outputScaleDims;
5469 outputDataShape.
getDims(outputDataDims);
5470 outputScaleShape.
getDims(outputScaleDims);
5472 if (outputDataDims.size() != outputScaleDims.size() ||
5474 ArrayRef<int64_t>(outputDataDims).drop_back(1),
5475 ArrayRef<int64_t>(outputScaleDims).drop_back(1))))
5476 return emitOpError() <<
"require compatible shapes for output_data ("
5477 << outputDataType <<
") and " <<
"output_scale ("
5479 <<
") except for the last dimension";
5481 const int64_t outputDataLastDim = outputDataDims.back();
5482 const SmallVector<int64_t, 2> dimsToCheck{outputDataLastDim / blockSize,
5483 outputScaleDims.back()};
5484 if (ShapedType::isStatic(outputDataLastDim) &&
5487 <<
"expect last dimension of output_scale ("
5488 << outputScaleDims.back()
5489 <<
") to be equal to last dimension of output_data / block_size ("
5490 << outputDataDims.back() / blockSize <<
")";
5496LogicalResult IfOp::inferReturnTypeComponents(
5497 MLIRContext *context, ::std::optional<Location> location,
5498 IfOp::Adaptor adaptor,
5499 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5500 llvm::SmallVector<tosa::YieldOp> yieldOps;
5501 for (Region *region : adaptor.getRegions()) {
5502 for (
auto &block : *region)
5503 if (
auto returnOp = dyn_cast<tosa::YieldOp>(block.getTerminator()))
5504 yieldOps.push_back(returnOp);
5507 if (yieldOps.empty())
5511 llvm::SmallVector<ValueKnowledge> resultKnowledge;
5512 resultKnowledge.reserve(yieldOps.front().getNumOperands());
5513 for (
auto operand : yieldOps.front().getOperands()) {
5514 resultKnowledge.push_back(
5518 for (
auto yieldOp : yieldOps) {
5519 if (resultKnowledge.size() != yieldOp.getNumOperands())
5522 for (
const auto &it : llvm::enumerate(yieldOp.getOperands())) {
5523 int32_t index = it.index();
5525 resultKnowledge[index],
5529 resultKnowledge[index] = meet;
5533 for (
const ValueKnowledge &
result : resultKnowledge) {
5534 inferredReturnShapes.push_back(
result.getShapedTypeComponents());
5540LogicalResult WhileOp::inferReturnTypeComponents(
5541 MLIRContext *context, ::std::optional<Location> location,
5542 WhileOp::Adaptor adaptor,
5543 SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
5544 llvm::SmallVector<tosa::YieldOp> yieldOps;
5545 for (
auto &block : adaptor.getBodyGraph())
5546 if (
auto returnOp = dyn_cast<tosa::YieldOp>(block.getTerminator()))
5547 yieldOps.push_back(returnOp);
5551 if (yieldOps.empty())
5555 llvm::SmallVector<ValueKnowledge> resultKnowledge;
5556 resultKnowledge.reserve(yieldOps.front().getNumOperands());
5557 for (
auto operand : yieldOps.front().getOperands()) {
5558 resultKnowledge.push_back(
5562 for (
auto yieldOp : yieldOps) {
5563 if (resultKnowledge.size() != yieldOp.getNumOperands())
5566 for (
const auto &it : llvm::enumerate(yieldOp.getOperands())) {
5567 int32_t index = it.index();
5569 resultKnowledge[index],
5571 resultKnowledge[index] = meet;
5576 for (
const ValueKnowledge &
result : resultKnowledge) {
5577 inferredReturnShapes.push_back(
result.getShapedTypeComponents());
5583std::optional<SmallVector<int64_t, 4>> ApplyScaleOp::getShapeForUnroll() {
5584 if (
auto vt = llvm::dyn_cast<VectorType>(
getType()))
5585 return llvm::to_vector<4>(vt.getShape());
5586 return std::nullopt;
5592 StringRef prefix =
"") {
5593 assert(blocksArgs.size() == initializers.size() &&
5594 "expected same length of arguments and initializers");
5595 if (initializers.empty())
5598 parser << prefix <<
'(';
5599 llvm::interleaveComma(
5600 llvm::zip(blocksArgs, initializers), parser,
5601 [&](
auto it) { parser << std::get<0>(it) <<
" = " << std::get<1>(it); });
5606ParseResult IfOp::parse(OpAsmParser &parser, OperationState &
result) {
5608 result.regions.reserve(2);
5609 Region *thenRegion =
result.addRegion();
5610 Region *elseRegion =
result.addRegion();
5612 OpAsmParser::UnresolvedOperand cond;
5617 SmallVector<OpAsmParser::Argument, 4> regionArgs;
5618 SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
5621 OptionalParseResult listResult =
5629 "expected type for condition operand");
5635 "expected type for condition operand");
5643 FunctionType functionType;
5647 <<
"expected list of types for block arguments "
5648 <<
"followed by arrow type and list of return types";
5650 result.addTypes(functionType.getResults());
5652 if (functionType.getNumInputs() != operands.size()) {
5654 <<
"expected as many input types as operands " <<
"(expected "
5655 << operands.size() <<
" got " << functionType.getNumInputs()
5686void IfOp::print(OpAsmPrinter &p) {
5687 p <<
" " << getCondition();
5690 getInputList(),
" ");
5692 p << getCondition().getType();
5694 if (!getInputList().empty()) {
5696 llvm::interleaveComma(getInputList().getTypes(), p);
5705 auto &elseRegion = getElseGraph();
5706 if (!elseRegion.
empty()) {
5714LogicalResult IfOp::verify() {
5716 "'then_graph' arguments", getInputList(),
5722 "'else_graph' arguments", getInputList(),
5728 if (getThenGraph().front().mightHaveTerminator()) {
5730 dyn_cast<tosa::YieldOp>(getThenGraph().front().getTerminator());
5732 *
this, thenYield.getInputs(),
"'then_graph' results",
5733 getOutputList(),
"'output_list'")
5739 if (getElseGraph().front().mightHaveTerminator()) {
5741 dyn_cast<tosa::YieldOp>(getElseGraph().front().getTerminator());
5743 *
this, elseYield.getInputs(),
"'else_graph' results",
5744 getOutputList(),
"'output_list'")
5749 auto condType = getCondition().getType();
5751 return emitOpError() <<
"'condition' must be a size 1 tensor, got "
5757LogicalResult WhileOp::verify() {
5759 getOutputList(),
"'output_list'")
5764 "'cond_graph' arguments", getInputList(),
5770 "'body_graph' arguments", getInputList(),
5775 if (getBodyGraph().front().mightHaveTerminator()) {
5777 dyn_cast<tosa::YieldOp>(getBodyGraph().front().getTerminator());
5779 "'body_graph' results",
5780 getInputList(),
"'input_list'")
5787 if (!getCondGraph().front().mightHaveTerminator())
5791 dyn_cast<tosa::YieldOp>(getCondGraph().front().getTerminator());
5795 if (condYield.getInputs().size() != 1)
5796 return emitOpError() <<
"require 'cond_graph' only have one result";
5798 auto condOutType = condYield.getInputs()[0].getType();
5800 return emitOpError() <<
"'cond_graph' result must be a size 1 tensor, got "
5804 return emitOpError() <<
"'cond_graph' result must be a boolean tensor, got "
5810LogicalResult ReverseOp::verify() {
5811 TensorType inputType = getInput1().getType();
5812 int32_t reverseAxis = getAxis();
5814 if (reverseAxis < 0)
5815 return emitOpError(
"expected non-negative reverse axis");
5817 int64_t inputRank = inputType.getRank();
5820 if (reverseAxis >= inputRank && (reverseAxis != 0 || inputRank != 0))
5822 << inputRank <<
") to be larger than reverse axis (" << reverseAxis
5829LogicalResult tosa::SelectOp::verify() {
5840 auto predicateType = llvm::dyn_cast<ShapedType>(getPred().
getType());
5841 if (!predicateType) {
5842 return emitOpError(
"expect shaped tensor for input1, got ")
5843 << getInput1().getType();
5845 auto predicateElementType = predicateType.getElementType();
5846 if (!predicateElementType.isInteger(1)) {
5847 return emitOpError(
"expect element type of bool for input1, got ")
5848 << predicateElementType;
5854LogicalResult tosa::VariableReadOp::verify() {
5862LogicalResult tosa::VariableWriteOp::verify() {
5871ParseResult WhileOp::parse(OpAsmParser &parser, OperationState &
result) {
5872 SmallVector<OpAsmParser::Argument, 4> regionArgs;
5873 SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
5874 Region *cond =
result.addRegion();
5875 Region *body =
result.addRegion();
5877 OptionalParseResult listResult =
5882 FunctionType functionType;
5887 result.addTypes(functionType.getResults());
5889 if (functionType.getNumInputs() != operands.size()) {
5891 <<
"expected as many input types as operands " <<
"(expected "
5892 << operands.size() <<
" got " << functionType.getNumInputs() <<
")";
5902 for (
size_t i = 0, e = regionArgs.size(); i != e; ++i)
5903 regionArgs[i].type = functionType.getInput(i);
5905 return failure(parser.
parseRegion(*cond, regionArgs) ||
5910void WhileOp::print(OpAsmPrinter &parser) {
5912 getInputList(),
" ");
5915 getResults().getTypes());
5929 auto zpType = mlir::RankedTensorType::get({1}, srcElemType);
5930 if (llvm::isa<FloatType>(srcElemType)) {
5932 zpType, builder.
getFloatAttr(srcElemType,
static_cast<double>(zp)));
5933 return tosa::ConstOp::create(builder, loc, zpType, zpAttr);
5935 if (llvm::isa<IntegerType>(srcElemType)) {
5938 return tosa::ConstOp::create(builder, loc, zpType, zpAttr);
5940 llvm::errs() <<
"zero point is not allowed for unsupported data types\n";
5941 return std::nullopt;
5949 return mlir::isa<tosa::shapeType>(t);
5956 return emitError() <<
"invalid rank (must be >= 0): " << rank;
5962 if (mlir::isa<::mlir::tosa::shapeType>(v.getType())) {
5963 Operation *definingOp = v.getDefiningOp();
5965 return op->
emitOpError(
"shape operand is not compile time resolvable");
5978 auto getRank = [](
const Type type) {
5979 return mlir::cast<mlir::tosa::shapeType>(type).getRank();
5985 for (
auto type : operandTypes) {
5986 if (getRank(type) != rank) {
5987 return op->
emitOpError(
"operands don't have matching ranks");
5990 for (
auto type : resultTypes) {
5991 if (getRank(type) != rank) {
5992 return op->
emitOpError(
"result shape has different rank than operands");
6002LogicalResult tosa::ConstShapeOp::verify() {
6004 auto valuesRank = getValues().getType().getRank();
6005 if (valuesRank != 1)
6006 return emitOpError(
"expect elements in attribute values with rank 1");
6008 auto count = getValues().getNumElements();
6009 auto rank = (cast<tosa::shapeType>(getResult().
getType())).getRank();
6010 if (count != rank && (count != 1 || rank != 0)) {
6011 return emitOpError(
"expect number of elements in attribute values (")
6012 << count <<
") to be equal to the rank (" << rank
6013 <<
") for the result shape type";
6018LogicalResult tosa::DimOp::verify() {
6019 const tosa::shapeType outShapeType =
6020 cast<tosa::shapeType>(getResult().
getType());
6021 if (outShapeType.getRank() != 1)
6022 return emitOpError(
"expect output shape type to contain one element, got ")
6027 const int64_t inputRank = inputType.getRank();
6028 const int64_t axis = getAxisAttr().getInt();
6029 if (axis < 0 || axis >= inputRank)
6030 return emitOpError(
"expect axis to be in the range [0, ")
6031 << inputRank <<
"), got " << axis;
6036LogicalResult tosa::ConcatShapeOp::verify() {
6037 const tosa::shapeType outShapeType =
6038 cast<tosa::shapeType>(getResult().
getType());
6039 const int64_t outputRank = outShapeType.getRank();
6042 if (inputList.size() == 0)
6043 return emitOpError(
"requires at least one input shape");
6045 if (llvm::any_of(inputList, [](Value v) {
6046 return cast<tosa::shapeType>(v.
getType()).getRank() == 0;
6048 return emitOpError(
"requires all inputs shapes have a rank greater than 0");
6050 const int64_t inputsRank =
6051 llvm::accumulate(inputList, 0, [](int64_t acc,
const Value &input) {
6052 const tosa::shapeType inShapeType =
6053 cast<tosa::shapeType>(input.
getType());
6054 return acc + inShapeType.getRank();
6056 if (outputRank != inputsRank)
6057 return emitOpError(
"requires output shape rank to be equal to the sum of "
6058 "the input shape ranks (")
6059 << inputsRank <<
"), got " << outputRank;
6064LogicalResult tosa::SliceShapeOp::verify() {
6065 std::optional<int32_t> start;
6066 DenseIntElementsAttr startAttr;
6068 start = startAttr.getValues<int32_t>()[0];
6069 if (start && start.value() < 0)
6070 return emitOpError(
"expected non-negative start index, got ")
6073 std::optional<int32_t> size;
6074 DenseIntElementsAttr sizeAttr;
6076 size = sizeAttr.getValues<int32_t>()[0];
6077 if (size && size.value() <= 0)
6078 return emitOpError(
"expected positive size, got ") << size.value();
6083 const tosa::shapeType outShapeType =
6084 cast<tosa::shapeType>(getResult().
getType());
6085 const int64_t outputRank = outShapeType.getRank();
6086 if (outputRank != size)
6088 "expected output type size to be equal to size attribute, got ")
6089 << outputRank <<
" vs " << size.value();
6094 const tosa::shapeType inShapeType =
6095 cast<tosa::shapeType>(getInput().
getType());
6096 const int64_t inputRank = inShapeType.getRank();
6097 const int64_t sliceSize = start.value() + size.value();
6098 if (sliceSize > inputRank)
6099 return emitOpError(
"expected start + size to be less than or equal to "
6100 "input shape rank (")
6101 << inputRank <<
"), got " << sliceSize;
6110#define GET_ATTRDEF_CLASSES
6111#include "mlir/Dialect/Tosa/IR/TosaAttributes.cpp.inc"
6116#define GET_TYPEDEF_CLASSES
6117#include "mlir/Dialect/Tosa/IR/TosaOpsTypesBase.cpp.inc"
6123#define GET_OP_CLASSES
6124#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)