10#include "mlir/Dialect/Arith/IR/Arith.h"
11#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
12#include "mlir/IR/DialectImplementation.h"
13#include "mlir/IR/OpDefinition.h"
14#include "mlir/IR/TypeUtilities.h"
15#include "mlir/Transforms/FoldUtils.h"
16#include "llvm/ADT/TypeSwitch.h"
29#include "aie/Dialect/AIEVec/IR/AIEVecEnums.cpp.inc"
30#include "aie/Dialect/AIEVec/IR/AIEVecOpsDialect.cpp.inc"
36void AIEVecDialect::initialize() {
39#define GET_ATTRDEF_LIST
40#include "aie/Dialect/AIEVec/IR/AIEVecAttributes.cpp.inc"
44#include "aie/Dialect/AIEVec/IR/AIEVecOps.cpp.inc"
53void UPDOp::print(OpAsmPrinter &p) {
55 p <<
" " << getSource() <<
"[" << getIndices() <<
"]";
58 p <<
", " << getVector();
61 SmallVector<StringRef, 3> elidedAttrs;
62 elidedAttrs.push_back(UPDOp::getOperandSegmentSizeAttr());
63 p.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
66 p <<
" : " << getSource().getType() <<
", " << getResult().getType();
70LogicalResult UPDOp::verify() {
72 MemRefType sourceType = llvm::dyn_cast<MemRefType>(getSource().getType());
73 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
75 return emitError(
"requires memref type");
77 return emitError(
"requires vector type");
78 if (getIndices().empty())
79 return emitError(
"upd source cannot come from scalar value");
84 Type vecType = llvm::dyn_cast<VectorType>(getVector().getType());
85 if (vecType != resultType)
86 return emitError(
"result types of linked UPD ops do not match");
92ParseResult UPDOp::parse(OpAsmParser &parser, OperationState &result) {
93 auto &builder = parser.getBuilder();
95 SmallVector<Type, 2> types;
96 OpAsmParser::UnresolvedOperand source,
vector;
97 SmallVector<OpAsmParser::UnresolvedOperand, 8> indices;
100 if (parser.parseOperand(source) ||
101 parser.parseOperandList(indices, OpAsmParser::Delimiter::Square))
103 ParseResult hasVector = parser.parseOptionalComma();
104 if (hasVector.succeeded() && parser.parseOperand(
vector))
108 if (parser.parseOptionalAttrDict(result.attributes) ||
109 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
112 if (result.attributes.getAttrs().size() != 2)
113 return parser.emitError(typesLoc,
"requires two attributes");
116 if (types.size() != 2)
117 return parser.emitError(typesLoc,
"requires two types");
120 auto memrefType = llvm::dyn_cast<MemRefType>(types[0]);
122 return parser.emitError(typesLoc,
"requires memref type");
123 VectorType vectorType = llvm::dyn_cast<VectorType>(types[1]);
125 return parser.emitError(typesLoc,
"requires vector type");
126 auto indicesType = builder.getIndexType();
129 if (parser.resolveOperand(source, memrefType, result.operands) ||
130 parser.resolveOperands(indices, indicesType, result.operands))
133 if (hasVector.succeeded())
134 if (parser.resolveOperand(
vector, vectorType, result.operands))
138 result.addAttribute(UPDOp::getOperandSegmentSizeAttr(),
139 builder.getDenseI32ArrayAttr(
140 {1, static_cast<int32_t>(indices.size()),
141 static_cast<int32_t>(hasVector.succeeded())}));
143 return parser.addTypeToList(vectorType, result.types);
151void CastOp::print(OpAsmPrinter &p) {
153 p <<
" " << getSource();
156 p.printOptionalAttrDict((*this)->getAttrs());
159 p <<
" : " << getSource().getType() <<
", " << getResult().getType();
163LogicalResult CastOp::verify() {
165 VectorType sourceType = llvm::dyn_cast<VectorType>(getSource().getType());
166 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
168 return emitError(
"requires source vector type");
170 return emitError(
"requires result vector type");
172 if (sourceType.getElementType().getIntOrFloatBitWidth() !=
173 resultType.getElementType().getIntOrFloatBitWidth()) {
174 return emitError(
"the bitwidth of resource and result should be equal");
181ParseResult CastOp::parse(OpAsmParser &parser, OperationState &result) {
182 llvm::SMLoc typesLoc;
183 SmallVector<Type, 2> types;
184 OpAsmParser::UnresolvedOperand source;
187 if (parser.parseOperand(source))
191 if (parser.parseOptionalAttrDict(result.attributes) ||
192 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
195 if (result.attributes.getAttrs().size() != 1)
196 return parser.emitError(typesLoc,
"requires one attribute");
199 if (types.size() != 2)
200 return parser.emitError(typesLoc,
"requires two types");
203 VectorType sourceType = llvm::dyn_cast<VectorType>(types[0]);
205 return parser.emitError(typesLoc,
"requires vector type");
206 VectorType vectorType = llvm::dyn_cast<VectorType>(types[1]);
208 return parser.emitError(typesLoc,
"requires vector type");
211 if (parser.resolveOperand(source, sourceType, result.operands))
214 return parser.addTypeToList(vectorType, result.types);
218OpFoldResult CastOp::fold(FoldAdaptor adaptor) {
219 auto srcCastOp = getSource().getDefiningOp<aievec::CastOp>();
223 if (srcCastOp.getIsResAcc() == getIsResAcc())
224 return srcCastOp.getResult();
226 return srcCastOp.getSource();
234OpFoldResult SRSOp::fold(FoldAdaptor adaptor) {
235 auto *srcDefOp = getSource().getDefiningOp();
239 auto upsOp = dyn_cast<UPSOp>(srcDefOp);
243 auto *shiftDefOp = getShift().getDefiningOp();
247 auto constOp = dyn_cast<arith::ConstantOp>(shiftDefOp);
253 auto intAttr = dyn_cast<IntegerAttr>(constOp.getValue());
254 if (!intAttr || intAttr.getInt() != 0)
257 if (upsOp.getSource().getType() != getResult().getType())
260 return upsOp.getSource();
264void SRSOp::print(OpAsmPrinter &p) {
266 p <<
" " << getSource() <<
", ";
273 if (getSign() == 1) {
274 p.printOptionalAttrDict((*this)->getAttrs(), {
"sign"});
276 p.printOptionalAttrDict((*this)->getAttrs());
280 p <<
" : " << getSource().getType() <<
", " << getShift().getType() <<
", "
281 << getResult().getType();
285LogicalResult SRSOp::verify() {
287 VectorType sourceType = llvm::dyn_cast<VectorType>(getSource().getType());
288 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
290 return emitError(
"requires accumulator type");
292 return emitError(
"requires vector type");
297 if (accLanes != vecLanes)
298 return emitError(
"The number of lanes in result vector "
299 "and source accumulator must match");
302 Type stype = resultType.getElementType();
303 Type atype = sourceType.getElementType();
304 unsigned stypeWidth = stype.getIntOrFloatBitWidth();
305 unsigned atypeWidth = atype.getIntOrFloatBitWidth();
307 if (isa<IntegerType>(atype) && stypeWidth >= atypeWidth)
308 return emitError(
"the element type of source accumulator must be "
309 "wider than that of the result vector");
310 if (isa<FloatType>(atype) && stypeWidth != 16 && stypeWidth != atypeWidth)
311 return emitError(
"the element type of source accumulator must be "
312 "same as the result vector");
318ParseResult SRSOp::parse(OpAsmParser &parser, OperationState &result) {
319 llvm::SMLoc typesLoc;
320 SmallVector<Type, 3> types;
321 OpAsmParser::UnresolvedOperand source, shift;
324 if (parser.parseOperand(source) || parser.parseComma() ||
325 parser.parseOperand(shift))
329 if (parser.parseOptionalAttrDict(result.attributes))
333 if (parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
337 if (types.size() != 3)
338 return parser.emitError(typesLoc,
"requires three types");
341 VectorType accType = llvm::dyn_cast<VectorType>(types[0]);
343 return parser.emitError(typesLoc,
"requires vector type");
345 IntegerType shiftType = llvm::dyn_cast<IntegerType>(types[1]);
347 return parser.emitError(typesLoc,
"requires integer type");
349 VectorType vectorType = llvm::dyn_cast<VectorType>(types[2]);
351 return parser.emitError(typesLoc,
"requires vector type");
354 if (parser.resolveOperand(source, accType, result.operands) ||
355 parser.resolveOperand(shift, shiftType, result.operands))
358 return parser.addTypeToList(vectorType, result.types);
366OpFoldResult UPSOp::fold(FoldAdaptor adaptor) {
371 auto *srcDefOp = getSource().getDefiningOp();
374 auto srsOp = llvm::dyn_cast<SRSOp>(srcDefOp);
377 return srsOp.getSource();
381void UPSOp::print(OpAsmPrinter &p) {
383 p <<
" " << getSource();
386 p.printOptionalAttrDict((*this)->getAttrs());
389 p <<
" : " << getSource().getType() <<
", " << getResult().getType();
393LogicalResult UPSOp::verify() {
395 VectorType sourceType = llvm::dyn_cast<VectorType>(getSource().getType());
396 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
398 return emitError(
"requires vector type");
400 return emitError(
"requires vector type");
405 if (vecLanes != accLanes)
406 return emitError(
"The number of lanes in source vector "
407 "and result accumulator must match");
410 Type stype = sourceType.getElementType();
411 Type atype = resultType.getElementType();
412 unsigned stypeWidth = stype.getIntOrFloatBitWidth();
413 unsigned atypeWidth = atype.getIntOrFloatBitWidth();
415 if (stypeWidth >= atypeWidth)
416 return emitError(
"the element type of result accumulator "
417 "must be wider than that of the source vector");
423ParseResult UPSOp::parse(OpAsmParser &parser, OperationState &result) {
424 llvm::SMLoc typesLoc;
425 SmallVector<Type, 2> types;
426 OpAsmParser::UnresolvedOperand source;
429 if (parser.parseOperand(source))
433 if (parser.parseOptionalAttrDict(result.attributes) ||
434 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
437 if (result.attributes.getAttrs().size() != 1)
438 return parser.emitError(typesLoc,
"requires one attribute");
441 if (types.size() != 2)
442 return parser.emitError(typesLoc,
"requires two types");
445 VectorType vectorType = llvm::dyn_cast<VectorType>(types[0]);
447 return parser.emitError(typesLoc,
"requires vector type");
448 VectorType accType = llvm::dyn_cast<VectorType>(types[1]);
450 return parser.emitError(typesLoc,
"requires vector type");
453 if (parser.resolveOperand(source, vectorType, result.operands))
456 return parser.addTypeToList(accType, result.types);
464void BroadcastOp::print(OpAsmPrinter &p) {
466 p <<
" " << getSource();
469 p.printOptionalAttrDict((*this)->getAttrs());
472 p <<
" : " << getSource().getType() <<
", " << getResult().getType();
476LogicalResult BroadcastOp::verify() {
478 VectorType sourceType = llvm::dyn_cast<VectorType>(getSource().getType());
479 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
482 return emitError(
"requires vector type");
484 return emitError(
"requires vector type");
486 if (sourceType != resultType) {
487 return emitError(
"The vector type of source vector "
488 "and result vector must match");
493 if (sourceLanes != resultLanes)
494 return emitError(
"The number of lanes in source vector "
495 "and result vector must match");
498 Type stype = sourceType.getElementType();
499 Type rtype = resultType.getElementType();
501 if (stype != rtype) {
502 return emitError(
"the element type of result vector "
503 "must be the same as source vector");
510ParseResult BroadcastOp::parse(OpAsmParser &parser, OperationState &result) {
511 llvm::SMLoc typesLoc;
512 SmallVector<Type, 2> types;
513 OpAsmParser::UnresolvedOperand source;
516 if (parser.parseOperand(source))
520 if (parser.parseOptionalAttrDict(result.attributes) ||
521 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
524 if (result.attributes.getAttrs().size() != 1)
525 return parser.emitError(typesLoc,
"requires one attribute");
528 if (types.size() != 2)
529 return parser.emitError(typesLoc,
"requires two types");
532 VectorType vecType = llvm::dyn_cast<VectorType>(types[0]);
534 return parser.emitError(typesLoc,
"requires vector type");
536 VectorType resType = llvm::dyn_cast<VectorType>(types[1]);
538 return parser.emitError(typesLoc,
"requires vector type");
541 if (parser.resolveOperand(source, vecType, result.operands))
544 return parser.addTypeToList(resType, result.types);
552void BroadcastScalarOp::print(OpAsmPrinter &p) {
554 p <<
" " << getSource();
557 p <<
" : " << getSource().getType() <<
", " << getResult().getType();
561LogicalResult BroadcastScalarOp::verify() {
563 Type sourceType = getSource().getType();
564 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
567 return emitError(
"requires vector type");
569 if (!isa<IntegerType, FloatType>(sourceType))
570 return emitError(
"requires source type to be integer or float");
572 Type resultElemType = resultType.getElementType();
573 if (sourceType != resultElemType) {
574 return emitError(
"the element type of result vector must be the same as "
582ParseResult BroadcastScalarOp::parse(OpAsmParser &parser,
583 OperationState &result) {
584 llvm::SMLoc typesLoc;
585 SmallVector<Type, 2> types;
586 OpAsmParser::UnresolvedOperand source;
589 if (parser.parseOperand(source))
593 if (parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
596 if (!result.attributes.getAttrs().empty())
597 return parser.emitError(typesLoc,
"do not require attributes");
600 if (types.size() != 2)
601 return parser.emitError(typesLoc,
"requires two types");
604 VectorType resType = llvm::dyn_cast<VectorType>(types[1]);
606 return parser.emitError(typesLoc,
"requires vector type");
608 if (parser.resolveOperand(source, types[0], result.operands))
611 return parser.addTypeToList(resType, result.types);
628 p <<
", " << op.getAcc();
638 SmallVector<StringRef, 4> &elidedAttrs) {
640 elidedAttrs.push_back(op.getSubAttrName());
645 SmallVector<StringRef, 4> &elidedAttrs) {}
649static void printMulFMAElemOp(OpAsmPrinter &p, T op) {
651 p <<
" " << op.getLhs();
653 p <<
", " << op.getRhs();
658 SmallVector<StringRef, 4> elidedAttrs;
659 for (
int idx = 0; idx < 2; ++idx) {
662 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
665 p <<
" : " << op.getLhs().getType() <<
", " << op.getRhs().getType();
666 p <<
", " << op.getResult().getType();
669void MulElemOp::print(OpAsmPrinter &p) {
670 printMulFMAElemOp<aievec::MulElemOp>(p, *
this);
673void aievec::FMAElemOp::print(OpAsmPrinter &p) {
674 printMulFMAElemOp<aievec::FMAElemOp>(p, *
this);
679static LogicalResult verifyMulFMAElemOp(T op) {
681 auto lhsType = llvm::dyn_cast<VectorType>(op.getLhs().getType());
682 auto rhsType = llvm::dyn_cast<VectorType>(op.getRhs().getType());
684 if (!lhsType || !rhsType)
685 return op.emitError(
"requires vector type");
687 auto resultType = llvm::dyn_cast<VectorType>(op.getResult().getType());
690 return op.emitError(
"requires vector type");
694 Type ltype = lhsType.getElementType();
695 Type rtype = rhsType.getElementType();
696 Type atype = resultType.getElementType();
697 unsigned ltypeWidth = ltype.getIntOrFloatBitWidth();
698 unsigned rtypeWidth = rtype.getIntOrFloatBitWidth();
699 unsigned atypeWidth = atype.getIntOrFloatBitWidth();
706 if (lhsLanes != rhsLanes) {
707 return op.emitError(
"The number of lanes in lhs operand "
708 "must be the same as rhs operand");
713 return op.emitError(
"The element type of lhs and rhs "
714 "operand vectors must match");
717 if (isa<IntegerType>(atype)) {
718 if (!isa<IntegerType>(ltype))
719 return op.emitError(
"Integer result must have integer operands");
721 if (ltypeWidth >= atypeWidth || rtypeWidth >= atypeWidth)
722 return op.emitError(
"the element type of accumulator must have "
723 "wider width than that of the operand vectors");
724 }
else if (isa<FloatType>(atype)) {
725 if (!isa<FloatType>(ltype))
726 return op.emitError(
"Floating point result must have "
727 "floating point operands");
733LogicalResult aievec::MulElemOp::verify() {
735 (!getElementTypeOrSelf(getLhs().getType()).isBF16() ||
736 !getElementTypeOrSelf(getResult().getType()).isF32()))
737 return emitError(
"64 lanes are supported only for bf16 operands with an "
739 return verifyMulFMAElemOp<aievec::MulElemOp>(*
this);
742LogicalResult aievec::FMAElemOp::verify() {
743 return verifyMulFMAElemOp<aievec::FMAElemOp>(*
this);
747static ParseResult parseMulFMAElemOp(OpAsmParser &parser,
748 OperationState &result,
749 bool isFMAElemOp =
true) {
750 llvm::SMLoc typesLoc;
751 SmallVector<Type, 3> types;
752 OpAsmParser::UnresolvedOperand lhs, rhs, acc;
755 if (parser.parseOperand(lhs) || parser.parseComma() ||
756 parser.parseOperand(rhs))
761 if (parser.parseComma() || parser.parseOperand(acc))
766 if (parser.parseOptionalAttrDict(result.attributes) ||
767 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
771 if (types.size() != 3)
772 return parser.emitError(typesLoc,
"requires three types");
775 VectorType lhsType = llvm::dyn_cast<VectorType>(types[0]);
777 return parser.emitError(typesLoc,
"requires vector type");
778 VectorType rhsType = llvm::dyn_cast<VectorType>(types[1]);
780 return parser.emitError(typesLoc,
"requires vector type");
783 VectorType accType = llvm::dyn_cast<VectorType>(types[2]);
785 return parser.emitError(typesLoc,
"requires vector type");
788 if (parser.resolveOperand(lhs, lhsType, result.operands) ||
789 parser.resolveOperand(rhs, rhsType, result.operands))
794 if (parser.resolveOperand(acc, accType, result.operands))
798 return parser.addTypeToList(accType, result.types);
801ParseResult MulElemOp::parse(OpAsmParser &parser, OperationState &result) {
802 return parseMulFMAElemOp(parser, result,
false);
805ParseResult FMAElemOp::parse(OpAsmParser &parser, OperationState &result) {
806 return parseMulFMAElemOp(parser, result,
true);
814void ConcatOp::print(OpAsmPrinter &p) {
816 assert(!getSources().empty() &&
"concat source empty");
817 p <<
" " << getSources();
820 p.printOptionalAttrDict((*this)->getAttrs());
823 p <<
" : " << getSources().getTypes().front() <<
", "
824 << getResult().getType();
828LogicalResult ConcatOp::verify() {
830 if (getSources().size() < 2)
831 return emitError(
"Must concatenate at least two vectors");
834 VectorType sourceType =
835 llvm::dyn_cast<VectorType>(getSources().getTypes().front());
836 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
837 if (!sourceType || !resultType)
838 return emitError(
"requires vector type");
840 SmallVector<Value, 8> srcs(getSources().begin(), getSources().end());
842 for (
auto source : srcs) {
843 VectorType type = llvm::dyn_cast<VectorType>(source.getType());
845 return emitError(
"requires vector type");
846 if (type != sourceType)
847 return emitError(
"All sources must have same type");
851 unsigned totalLanes = 0;
852 for (
auto source : srcs) {
853 VectorType type = llvm::dyn_cast<VectorType>(source.getType());
858 return emitError(
"mismatch between vector lanes "
859 "and sum of source lanes");
865ParseResult ConcatOp::parse(OpAsmParser &parser, OperationState &result) {
866 llvm::SMLoc typesLoc;
867 SmallVector<Type, 2> types;
868 SmallVector<OpAsmParser::UnresolvedOperand, 8> sources;
871 if (parser.parseOperandList(sources))
875 if (parser.parseOptionalAttrDict(result.attributes) ||
876 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
880 if (!result.attributes.getAttrs().empty())
881 return parser.emitError(typesLoc,
"expects no attribute");
884 if (types.size() != 2)
885 return parser.emitError(typesLoc,
"requires two types");
888 VectorType sourceType = llvm::dyn_cast<VectorType>(types[0]);
889 VectorType resultType = llvm::dyn_cast<VectorType>(types[1]);
890 if (!sourceType || !resultType)
891 return parser.emitError(typesLoc,
"requires vector type");
894 if (parser.resolveOperands(sources, sourceType, result.operands))
897 return parser.addTypeToList(resultType, result.types);
901ConcatOp::inferReturnTypes(MLIRContext *, std::optional<Location>,
902 ConcatOp::Adaptor adaptor,
903 SmallVectorImpl<Type> &inferredReturnTypes) {
904 SmallVector<Value, 8> srcs(adaptor.getSources().begin(),
905 adaptor.getSources().end());
906 unsigned totalLength = 0;
907 for (
auto source : srcs) {
908 VectorType type = llvm::cast<VectorType>(source.getType());
909 assert(type.getRank() == 1 &&
910 "only rank 1 vectors currently supported by concat");
911 totalLength += type.getDimSize(0);
913 inferredReturnTypes.push_back(VectorType::get(
915 llvm::cast<VectorType>(srcs[0].getType()).getElementType()));
924void ExtOp::print(OpAsmPrinter &p) {
926 p <<
" " << getSource();
929 p.printOptionalAttrDict((*this)->getAttrs());
932 p <<
" : " << getSource().getType() <<
", " << getResult().getType();
936LogicalResult ExtOp::verify() {
938 VectorType sourceType = llvm::dyn_cast<VectorType>(getSource().getType());
939 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
940 if (!sourceType || !resultType)
941 return emitError(
"requires vector type");
947 if (sourceLanes / resultLanes <= 1)
948 return emitError(
"lanes in source vector must be at least "
949 "twice that of result vector");
951 if (sourceLanes % resultLanes != 0)
952 return emitError(
"lanes in result vector must be a multiple "
953 "of source vector lanes");
956 unsigned factor = sourceLanes / resultLanes;
957 if (
static_cast<unsigned>(getIndex()) >= factor)
958 return emitError(
"index out of bounds");
961 Type stype = sourceType.getElementType();
962 Type rtype = resultType.getElementType();
964 return emitError(
"source and result element type must be same");
970ParseResult ExtOp::parse(OpAsmParser &parser, OperationState &result) {
971 llvm::SMLoc typesLoc;
972 SmallVector<Type, 2> types;
973 OpAsmParser::UnresolvedOperand source;
976 if (parser.parseOperand(source))
980 if (parser.parseOptionalAttrDict(result.attributes) ||
981 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
984 if (result.attributes.getAttrs().size() != 1)
985 return parser.emitError(typesLoc,
"requires one attribute");
988 if (types.size() != 2)
989 return parser.emitError(typesLoc,
"requires two types");
992 VectorType sourceType = llvm::dyn_cast<VectorType>(types[0]);
993 VectorType resultType = llvm::dyn_cast<VectorType>(types[1]);
994 if (!sourceType || !resultType)
995 return parser.emitError(typesLoc,
"requires vector type");
998 if (parser.resolveOperand(source, sourceType, result.operands))
1001 return parser.addTypeToList(resultType, result.types);
1009template <
typename T>
1010static void printPackUnpackOp(OpAsmPrinter &p, T op) {
1012 p <<
" " << op.getSource();
1015 p.printOptionalAttrDict(op->getAttrs());
1018 p <<
" : " << op.getSource().getType() <<
", " << op.getResult().getType();
1021void PackOp::print(OpAsmPrinter &p) { printPackUnpackOp<PackOp>(p, *
this); }
1023void UnpackOp::print(OpAsmPrinter &p) { printPackUnpackOp<UnpackOp>(p, *
this); }
1026template <
typename T>
1027static LogicalResult verifyPackUnpackOp(T op) {
1029 auto sourceType = llvm::dyn_cast<VectorType>(op.getSource().getType());
1030 auto resultType = llvm::dyn_cast<VectorType>(op.getResult().getType());
1031 if (!sourceType || !resultType)
1032 return op.emitError(
"requires vector type");
1037 Type stype = sourceType.getElementType();
1038 Type rtype = resultType.getElementType();
1041 if (!isa<IntegerType>(stype) || !isa<IntegerType>(rtype))
1042 return op.emitError(
"requires integer element types");
1043 unsigned stypeWidth = stype.getIntOrFloatBitWidth();
1044 unsigned rtypeWidth = rtype.getIntOrFloatBitWidth();
1046 if (isa<PackOp>(op)) {
1051 stypeWidth == 16 && rtypeWidth == 8 && sourceLanes == resultLanes;
1052 bool legalI8I4Packed =
1053 stypeWidth == 8 && rtypeWidth == 8 && sourceLanes == 2 * resultLanes;
1054 if (!legalI16I8 && !legalI8I4Packed)
1055 return op.emitError(
1056 "pack must narrow i16->i8 (same lanes) or i8->i8 (input lanes = "
1057 "2 * output lanes, int4-packed)");
1064 stypeWidth == 8 && rtypeWidth == 16 && sourceLanes == resultLanes;
1065 bool legalI4PackedI8 =
1066 stypeWidth == 8 && rtypeWidth == 8 && resultLanes == 2 * sourceLanes;
1067 if (!legalI8I16 && !legalI4PackedI8)
1068 return op.emitError(
1069 "unpack must widen i8->i16 (same lanes) or i8->i8 (output lanes = "
1070 "2 * input lanes, int4-packed)");
1076LogicalResult PackOp::verify() {
return verifyPackUnpackOp<PackOp>(*
this); }
1078LogicalResult UnpackOp::verify() {
return verifyPackUnpackOp<UnpackOp>(*
this); }
1081static ParseResult parsePackUnpackOp(OpAsmParser &parser,
1082 OperationState &result) {
1083 llvm::SMLoc typesLoc;
1084 SmallVector<Type, 2> types;
1085 OpAsmParser::UnresolvedOperand source;
1088 if (parser.parseOperand(source))
1092 if (parser.parseOptionalAttrDict(result.attributes) ||
1093 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
1097 if (!result.attributes.getAttrs().empty())
1098 return parser.emitError(typesLoc,
"expects no attributes");
1101 if (types.size() != 2)
1102 return parser.emitError(typesLoc,
"requires two types");
1105 VectorType sourceType = llvm::dyn_cast<VectorType>(types[0]);
1106 VectorType resultType = llvm::dyn_cast<VectorType>(types[1]);
1107 if (!sourceType || !resultType)
1108 return parser.emitError(typesLoc,
"requires vector type");
1111 if (parser.resolveOperand(source, sourceType, result.operands))
1114 return parser.addTypeToList(resultType, result.types);
1117ParseResult PackOp::parse(OpAsmParser &parser, OperationState &result) {
1118 return parsePackUnpackOp(parser, result);
1121ParseResult UnpackOp::parse(OpAsmParser &parser, OperationState &result) {
1122 return parsePackUnpackOp(parser, result);
1130LogicalResult ExtElemOp::verify() {
1132 VectorType sourceType = llvm::dyn_cast<VectorType>(getSource().getType());
1135 return emitError(
"source requires vector type");
1138 Type stype = sourceType.getElementType();
1139 Type rtype = getResult().getType();
1141 if (stype != rtype) {
1142 return emitError(
"the type of result must be the same as the element "
1143 "type of source vector");
1154void ShiftOp::print(OpAsmPrinter &p) {
1156 p <<
" " << getLhs() <<
", " << getRhs();
1159 p <<
", " << getShift();
1162 p.printOptionalAttrDict((*this)->getAttrs());
1165 p <<
" : " << getLhs().getType() <<
", " << getLhs().getType() <<
", "
1166 << getShift().getType() <<
", " << getResult().getType();
1170LogicalResult ShiftOp::verify() {
1172 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
1174 return emitError(
"requires vector type");
1177 VectorType lhsType = llvm::dyn_cast<VectorType>(getLhs().getType());
1178 VectorType rhsType = llvm::dyn_cast<VectorType>(getRhs().getType());
1180 if (!lhsType || !rhsType)
1181 return emitError(
"requires vector type");
1182 if (lhsType != resultType || rhsType != resultType)
1183 return emitError(
"All vectors must have same type");
1185 if (!isa<IntegerType>(getShift().getType()))
1186 return emitError(
"requires integer type");
1192ParseResult ShiftOp::parse(OpAsmParser &parser, OperationState &result) {
1193 llvm::SMLoc typesLoc;
1194 SmallVector<Type, 4> types;
1195 OpAsmParser::UnresolvedOperand lhs, rhs, shift;
1198 if (parser.parseOperand(lhs) || parser.parseComma() ||
1199 parser.parseOperand(rhs) || parser.parseComma() ||
1200 parser.parseOperand(shift))
1204 if (parser.parseOptionalAttrDict(result.attributes) ||
1205 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
1208 if (result.attributes.getAttrs().size() != 1)
1209 return parser.emitError(typesLoc,
"expects one attribute");
1212 if (types.size() != 4)
1213 return parser.emitError(typesLoc,
"requires four types");
1216 VectorType lhsType = llvm::dyn_cast<VectorType>(types[0]);
1217 VectorType rhsType = llvm::dyn_cast<VectorType>(types[1]);
1218 IntegerType shiftType = llvm::dyn_cast<IntegerType>(types[2]);
1219 VectorType resultType = llvm::dyn_cast<VectorType>(types[3]);
1220 if (!lhsType || !rhsType || !resultType)
1221 return parser.emitError(typesLoc,
"requires vector type");
1224 return parser.emitError(typesLoc,
"requires integer type");
1227 if (parser.resolveOperand(lhs, lhsType, result.operands) ||
1228 parser.resolveOperand(rhs, rhsType, result.operands) ||
1229 parser.resolveOperand(shift, shiftType, result.operands))
1232 return parser.addTypeToList(resultType, result.types);
1242struct MatMulRecipeEntry {
1244 unsigned lhsWidth, rhsWidth, accWidth;
1246 MatMulRecipe recipe;
1256static ArrayRef<MatMulRecipeEntry> getMatMulRecipeTable() {
1259 static const MatMulRecipeEntry table[] = {
1261 {
false, 8, 4, 32, 4, 16, 8, {K::AIE2_I8xI4_4x16x8,
false,
false}},
1262 {
false, 8, 8, 32, 4, 8, 8, {K::AIE2_I8xI8_4x8x8,
false,
false}},
1263 {
false, 16, 8, 32, 4, 4, 8, {K::AIE2_I16xI8_4x4x8,
false,
false}},
1264 {
false, 16, 16, 32, 4, 2, 8, {K::AIE2_I16xI16_4x2x8,
false,
false}},
1265 {
false, 16, 8, 64, 2, 8, 8, {K::AIE2_I16xI8_2x8x8_Acc64,
false,
false}},
1266 {
false, 16, 8, 64, 4, 8, 4, {K::AIE2_I16xI8_4x8x4_Acc64,
false,
false}},
1267 {
false, 16, 16, 64, 2, 4, 8, {K::AIE2_I16xI16_2x4x8_Acc64,
false,
false}},
1268 {
false, 16, 16, 64, 4, 4, 4, {K::AIE2_I16xI16_4x4x4_Acc64,
false,
false}},
1269 {
false, 32, 16, 64, 4, 2, 4, {K::AIE2_I32xI16_4x2x4_Acc64,
false,
false}},
1270 {
false, 0, 0, 0, 4, 8, 4, {K::AIE2_BF16_4x8x4,
false,
false}},
1271 {
true, 8, 8, 32, 8, 8, 8, {K::AIE2P_I8_8x8x8,
false,
false}},
1272 {
true, 16, 16, 32, 8, 2, 8, {K::AIE2P_I16_8x2x8,
false,
false}},
1273 {
true, 0, 0, 0, 8, 8, 8, {K::AIE2P_BFP16_8x8x8,
false,
true}},
1274 {
true, 0, 0, 0, 4, 8, 8, {K::AIE2P_BFP16_4x8x8,
false,
true}},
1275 {
true, 0, 0, 0, 8, 8, 4, {K::AIE2P_BF16Elem_8x8x4,
true,
false}},
1276 {
true, 0, 0, 0, 4, 8, 4, {K::AIE2P_BF16Elem_4x8x4,
false,
false}},
1277 {
true, 0, 0, 0, 8, 1, 8, {K::AIE2P_BF16Outer_8x1x8,
false,
false}},
1285static std::optional<unsigned> getRecipeOperandWidth(Type t) {
1286 if (
auto intTy = dyn_cast<IntegerType>(t))
1287 return intTy.getWidth();
1290 return std::nullopt;
1293static std::optional<unsigned> getRecipeAccWidth(Type t) {
1294 if (
auto intTy = dyn_cast<IntegerType>(t))
1295 return intTy.getWidth();
1298 return std::nullopt;
1301std::optional<MatMulRecipe>
1303 Type accElemTy, int64_t m, int64_t k,
1305 auto lhsWidth = getRecipeOperandWidth(lhsElemTy);
1306 auto rhsWidth = getRecipeOperandWidth(rhsElemTy);
1307 auto accWidth = getRecipeAccWidth(accElemTy);
1308 if (!lhsWidth || !rhsWidth || !accWidth)
1309 return std::nullopt;
1311 if ((*lhsWidth == 0 || *rhsWidth == 0 || *accWidth == 0) &&
1312 (*lhsWidth | *rhsWidth | *accWidth) != 0)
1313 return std::nullopt;
1314 for (
const MatMulRecipeEntry &e : getMatMulRecipeTable())
1315 if (e.aie2p == aie2p && e.lhsWidth == *lhsWidth &&
1316 e.rhsWidth == *rhsWidth && e.accWidth == *accWidth && e.m == m &&
1317 e.k == k && e.n == n)
1319 return std::nullopt;
1322std::optional<SmallVector<ShuffleMode, 2>>
1325 if (rows == 1 || cols == 1)
1326 return SmallVector<ShuffleMode, 2>{};
1327 if (!elemTy.isIntOrFloat())
1328 return std::nullopt;
1329 unsigned width = elemTy.getIntOrFloatBitWidth();
1330 int64_t bits = rows * cols * width;
1333 static const struct {
1338 {8, 4, 16, ShuffleMode::T8_4X16}, {8, 8, 8, ShuffleMode::T8_8X8},
1339 {8, 16, 4, ShuffleMode::T8_16X4}, {16, 2, 16, ShuffleMode::T16_2X16},
1340 {16, 4, 8, ShuffleMode::T16_4X8}, {16, 8, 4, ShuffleMode::T16_8X4},
1341 {16, 16, 2, ShuffleMode::T16_16X2}, {32, 4, 4, ShuffleMode::T32_4X4},
1344 static const struct {
1349 {8, 4, 8, ShuffleMode::T8_4X8}, {8, 8, 4, ShuffleMode::T8_8X4},
1350 {16, 2, 8, ShuffleMode::T16_2X8}, {16, 4, 4, ShuffleMode::T16_4X4},
1351 {16, 8, 2, ShuffleMode::T16_8X2},
1354 for (
const auto &e : modes512)
1355 if (e.width == width && e.rows == rows && e.cols == cols)
1356 return SmallVector<ShuffleMode, 2>{e.mode};
1357 return std::nullopt;
1360 return std::nullopt;
1362 for (
const auto &e : modes256)
1363 if (e.width == width && e.rows == rows && e.cols == cols)
1364 return SmallVector<ShuffleMode, 2>{e.mode};
1365 return std::nullopt;
1367 if (width == 16 && rows == 8 && cols == 8)
1368 return SmallVector<ShuffleMode, 2>{ShuffleMode::T16_8X8_LO,
1369 ShuffleMode::T16_8X8_HI};
1370 return std::nullopt;
1374static std::optional<MatMulRecipe>
1375checkMatMulTileImpl(
bool aie2p, VectorType lhsTy, VectorType rhsTy,
1376 VectorType accTy,
bool lhsTransposed,
bool rhsTransposed,
1377 llvm::raw_ostream &os) {
1378 if (lhsTy.getRank() != 2 || rhsTy.getRank() != 2 || accTy.getRank() != 2) {
1379 os <<
"expects rank-2 operands";
1380 return std::nullopt;
1382 ArrayRef<int64_t> lhsShape = lhsTy.getShape(), rhsShape = rhsTy.getShape(),
1383 accShape = accTy.getShape();
1384 int64_t m = lhsShape[lhsTransposed ? 1 : 0];
1385 int64_t k = lhsShape[lhsTransposed ? 0 : 1];
1386 int64_t rhsK = rhsShape[rhsTransposed ? 1 : 0];
1387 int64_t n = rhsShape[rhsTransposed ? 0 : 1];
1388 if (k != rhsK || accShape[0] != m || accShape[1] != n) {
1389 os <<
"lhs " << lhsTy << (lhsTransposed ?
" [k, m]" :
" [m, k]")
1390 <<
" times rhs " << rhsTy << (rhsTransposed ?
" [n, k]" :
" [k, n]")
1391 <<
" is not a contraction into " << accTy;
1392 return std::nullopt;
1394 StringRef target = aie2p ?
"AIE2P" :
"AIE2";
1395 std::optional<MatMulRecipe> recipe =
1396 getMatMulRecipe(aie2p, lhsTy.getElementType(), rhsTy.getElementType(),
1397 accTy.getElementType(), m, k, n);
1399 os <<
"no " << target <<
" matrix multiply takes " << m <<
"x" << k <<
" "
1400 << lhsTy.getElementType() <<
" times " << k <<
"x" << n <<
" "
1401 << rhsTy.getElementType() <<
" into " << accTy.getElementType();
1402 return std::nullopt;
1404 auto layoutReachable = [&](VectorType ty,
bool stored,
bool native) {
1405 return stored == native ||
1409 if (!layoutReachable(lhsTy, lhsTransposed, recipe->lhsKM)) {
1410 os <<
"the " << target <<
" " << m <<
"x" << k <<
"x" << n
1411 <<
" multiply reads lhs as " << (recipe->lhsKM ?
"[k, m]" :
"[m, k]")
1412 <<
", and no shuffle transposes " << lhsTy;
1413 return std::nullopt;
1415 if (!layoutReachable(rhsTy, rhsTransposed, recipe->rhsNK)) {
1416 os <<
"the " << target <<
" " << m <<
"x" << k <<
"x" << n
1417 <<
" multiply reads rhs as " << (recipe->rhsNK ?
"[n, k]" :
"[k, n]")
1418 <<
", and no shuffle transposes " << rhsTy;
1419 return std::nullopt;
1425 bool aie2p, VectorType lhsTy, VectorType rhsTy, VectorType accTy,
1426 bool lhsTransposed,
bool rhsTransposed,
1427 llvm::function_ref<InFlightDiagnostic()> emitError) {
1428 std::string message;
1429 llvm::raw_string_ostream os(message);
1430 std::optional<MatMulRecipe> recipe = checkMatMulTileImpl(
1431 aie2p, lhsTy, rhsTy, accTy, lhsTransposed, rhsTransposed, os);
1432 if (!recipe && emitError)
1433 emitError() << message;
1437template <
typename OpTy>
1438static LogicalResult verifyMatMulOp(OpTy op,
bool aie2p) {
1439 auto lhsTy = cast<VectorType>(op.getLhs().getType());
1440 auto rhsTy = cast<VectorType>(op.getRhs().getType());
1441 auto accTy = cast<VectorType>(op.getAcc().getType());
1442 if (!
checkMatMulTile(aie2p, lhsTy, rhsTy, accTy, op.getLhsTransposed(),
1443 op.getRhsTransposed(),
1444 [&]() { return op.emitOpError(); }))
1449LogicalResult MatMulOp::verify() {
return verifyMatMulOp(*
this,
false); }
1451LogicalResult MatMulOp_AIE2P::verify() {
return verifyMatMulOp(*
this,
true); }
1459 StringRef name = stringifyShuffleMode(mode);
1462 name.consume_front(
"t") && !name.consumeInteger(10, shape.
elemBits) &&
1463 name.consume_front(
"_") && !name.consumeInteger(10, shape.
rows) &&
1464 name.consume_front(
"x") && !name.consumeInteger(10, shape.
cols);
1465 shape.
flip = name ==
"_flip";
1466 shape.
hi = name ==
"_hi";
1467 assert(parsed && (name.empty() || name ==
"_lo" || shape.
hi || shape.
flip) &&
1468 "unexpected shuffle mode name");
1474 return static_cast<uint32_t
>(mode) >= 48;
1477std::array<uint8_t, 64>
1480 unsigned elemBytes = shape.
elemBits / 8;
1481 unsigned blockBytes = shape.
blockBits() / 8;
1482 unsigned blockElems = shape.
rows * shape.
cols;
1483 std::array<uint8_t, 64> perm;
1484 for (
unsigned out = 0; out < 64; ++out) {
1487 unsigned pos = shape.
isTwoInput() && shape.
hi ? out + 64 : out;
1488 unsigned block = pos / blockBytes;
1489 unsigned elem = pos % blockBytes / elemBytes;
1492 src = blockElems - 1 - elem;
1495 unsigned i = elem % shape.
rows, j = elem / shape.
rows;
1496 src = i * shape.
cols + j;
1498 perm[out] = block * blockBytes + src * elemBytes + pos % elemBytes;
1504LogicalResult ShuffleOp::verify() {
1505 ShuffleMode mode = getMode();
1509 if (requireRhs && !getRhs())
1510 return emitError() <<
"shuffle mode '" << stringifyEnum(mode)
1511 <<
"' requires a second operand";
1513 if (!requireRhs && getRhs())
1514 return emitError() <<
"shuffle mode '" << stringifyEnum(mode)
1515 <<
"' does not admit a second operand";
1518 cast<VectorType>(getLhs().getType()).getElementTypeBitWidth();
1519 if (shape.
elemBits != elemBitWidth)
1520 return emitError() <<
"shuffle mode '" << stringifyEnum(mode)
1521 <<
"' requires vectors of " << shape.
elemBits
1526 if (
auto target = (*this)->getParentOfType<AIE::AIETarget>())
1527 if (target.getTargetModel().getTargetArch() != AIE::AIEArch::AIE2p)
1528 return emitError() <<
"shuffle mode '" << stringifyEnum(mode)
1529 <<
"' is only available on AIE2P";
1535void LegacyShuffleOp::print(OpAsmPrinter &p) {
1537 p <<
" " << getSource();
1540 p.printOptionalAttrDict((*this)->getAttrs());
1543 p <<
" : " << getSource().getType() <<
", " << getResult().getType();
1547LogicalResult LegacyShuffleOp::verify() {
1549 VectorType sourceType = llvm::dyn_cast<VectorType>(getSource().getType());
1550 VectorType resultType = llvm::dyn_cast<VectorType>(getResult().getType());
1551 if (!sourceType || !resultType)
1552 return emitError(
"requires vector type");
1557 if (sourceLanes != resultLanes)
1558 return emitError(
"The number of lanes in input and "
1559 "output vector must match");
1561 Type stype = sourceType.getElementType();
1562 unsigned stypeWidth = stype.getIntOrFloatBitWidth();
1563 Type rtype = resultType.getElementType();
1564 unsigned rtypeWidth = rtype.getIntOrFloatBitWidth();
1566 if (stypeWidth != rtypeWidth)
1567 return emitError(
"The type width in input and "
1568 "output must match");
1574ParseResult LegacyShuffleOp::parse(OpAsmParser &parser,
1575 OperationState &result) {
1576 llvm::SMLoc typesLoc;
1577 SmallVector<Type, 2> types;
1578 OpAsmParser::UnresolvedOperand source;
1581 if (parser.parseOperand(source))
1585 if (parser.parseOptionalAttrDict(result.attributes) ||
1586 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
1590 if (result.attributes.getAttrs().size() != 1)
1591 return parser.emitError(typesLoc,
"expects one attribute");
1594 VectorType sourceType = llvm::dyn_cast<VectorType>(types[0]);
1595 VectorType resultType = llvm::dyn_cast<VectorType>(types[1]);
1596 if (!sourceType || !resultType)
1597 return parser.emitError(typesLoc,
"requires vector type");
1600 if (parser.resolveOperand(source, sourceType, result.operands))
1603 return parser.addTypeToList(resultType, result.types);
1616template <
typename T>
1620 p <<
", " << op.getAcc();
1626template <
typename T>
1627void elideFMSubAttr(T op, SmallVector<StringRef, 4> &elidedAttrs);
1630 SmallVector<StringRef, 4> &elidedAttrs) {
1632 elidedAttrs.push_back(op.getSubAttrName());
1637 SmallVector<StringRef, 4> &elidedAttrs) {}
1640template <
typename T>
1641static void printMulFMAConvOp(OpAsmPrinter &p, T op) {
1643 p <<
" " << op.getLhs();
1645 p <<
", " << op.getRhs();
1650 SmallVector<StringRef, 4> elidedAttrs;
1651 for (
int idx = 0; idx < 2; ++idx) {
1654 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
1657 p <<
" : " << op.getLhs().getType() <<
", " << op.getRhs().getType();
1658 p <<
", " << op.getResult().getType();
1661void MulConvOp::print(OpAsmPrinter &p) {
1662 printMulFMAConvOp<aievec::MulConvOp>(p, *
this);
1665void aievec::FMAConvOp::print(OpAsmPrinter &p) {
1666 printMulFMAConvOp<aievec::FMAConvOp>(p, *
this);
1670template <
typename T>
1671static LogicalResult verifyMulFMAConvOp(T op) {
1673 auto lhsType = llvm::dyn_cast<VectorType>(op.getLhs().getType());
1674 auto rhsType = llvm::dyn_cast<VectorType>(op.getRhs().getType());
1676 if (!lhsType || !rhsType)
1677 return op.emitError(
"requires vector type");
1679 unsigned M = op.getM();
1680 unsigned N = op.getN();
1682 if (M <= 0 || N <= 0 || 2 * M < M + N - 1)
1683 return op.emitError(
1684 "M and N should be larger than 0 and 2*M should be no less than M+N-1");
1686 auto resultType = llvm::dyn_cast<VectorType>(op.getResult().getType());
1689 return op.emitError(
"requires vector type");
1693 Type ltype = lhsType.getElementType();
1694 Type rtype = rhsType.getElementType();
1695 Type atype = resultType.getElementType();
1699 return op.emitError(
"The element type of lhs and rhs "
1700 "operand vectors must match");
1702 if (!isa<IntegerType>(ltype) || !isa<IntegerType>(rtype) ||
1703 !isa<IntegerType>(atype)) {
1704 return op.emitError(
"requires integer type");
1707 unsigned ltypeWidth = ltype.getIntOrFloatBitWidth();
1708 unsigned rtypeWidth = rtype.getIntOrFloatBitWidth();
1709 unsigned atypeWidth = atype.getIntOrFloatBitWidth();
1717 if (accLanes != M || accLanes != (rhsLanes / 2) || lhsLanes != rhsLanes) {
1718 return op.emitError(
1719 "The number of lanes in accumulator "
1720 "must be the same as M and the half as lhs and rhs operand");
1724 if (ltypeWidth >= atypeWidth || rtypeWidth >= atypeWidth)
1725 return op.emitError(
"the element type of accumulator must have "
1726 "wider width than that of the operand vectors");
1731LogicalResult aievec::MulConvOp::verify() {
1732 return verifyMulFMAConvOp<aievec::MulConvOp>(*
this);
1735LogicalResult aievec::FMAConvOp::verify() {
1736 return verifyMulFMAConvOp<aievec::FMAConvOp>(*
this);
1740static ParseResult parseMulFMAConvOp(OpAsmParser &parser,
1741 OperationState &result,
1742 bool isFMAConvOp =
true) {
1743 llvm::SMLoc typesLoc;
1744 SmallVector<Type, 3> types;
1745 OpAsmParser::UnresolvedOperand lhs, rhs, acc;
1748 if (parser.parseOperand(lhs) || parser.parseComma() ||
1749 parser.parseOperand(rhs))
1754 if (parser.parseComma() || parser.parseOperand(acc))
1759 if (parser.parseOptionalAttrDict(result.attributes) ||
1760 parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
1764 if (types.size() != 3)
1765 return parser.emitError(typesLoc,
"requires three types");
1768 VectorType lhsType = llvm::dyn_cast<VectorType>(types[0]);
1770 return parser.emitError(typesLoc,
"requires vector type");
1771 VectorType rhsType = llvm::dyn_cast<VectorType>(types[1]);
1773 return parser.emitError(typesLoc,
"requires vector type");
1776 VectorType accType = llvm::dyn_cast<VectorType>(types[2]);
1778 return parser.emitError(typesLoc,
"requires vector type");
1781 if (parser.resolveOperand(lhs, lhsType, result.operands) ||
1782 parser.resolveOperand(rhs, rhsType, result.operands))
1787 if (parser.resolveOperand(acc, accType, result.operands))
1791 return parser.addTypeToList(accType, result.types);
1794ParseResult MulConvOp::parse(OpAsmParser &parser, OperationState &result) {
1795 return parseMulFMAConvOp(parser, result,
false);
1798ParseResult FMAConvOp::parse(OpAsmParser &parser, OperationState &result) {
1799 return parseMulFMAConvOp(parser, result,
true);
1802#define GET_ATTRDEF_CLASSES
1803#include "aie/Dialect/AIEVec/IR/AIEVecAttributes.cpp.inc"
1805#define GET_OP_CLASSES
1806#include "aie/Dialect/AIEVec/IR/AIEVecOps.cpp.inc"
void printAccumulator(OpAsmPrinter &p, T op)
void elideFMSubAttr(T op, SmallVector< StringRef, 4 > &elidedAttrs)
std::optional< MatMulRecipe > checkMatMulTile(bool aie2p, mlir::VectorType lhsTy, mlir::VectorType rhsTy, mlir::VectorType accTy, bool lhsTransposed, bool rhsTransposed, llvm::function_ref< mlir::InFlightDiagnostic()> emitError=nullptr)
unsigned getVectorLaneSize(mlir::VectorType type)
bool isAIE2POnlyShuffleMode(ShuffleMode mode)
std::optional< llvm::SmallVector< ShuffleMode, 2 > > getTileTransposeModes(bool aie2p, mlir::Type elemTy, int64_t rows, int64_t cols)
ShuffleModeShape getShuffleModeShape(ShuffleMode mode)
std::optional< MatMulRecipe > getMatMulRecipe(bool aie2p, mlir::Type lhsElemTy, mlir::Type rhsElemTy, mlir::Type accElemTy, int64_t m, int64_t k, int64_t n)
std::array< uint8_t, 64 > getShuffleModeBytePermutation(ShuffleMode mode)
unsigned blockBits() const