22#include "mlir/Dialect/Affine/IR/AffineOps.h"
23#include "mlir/Dialect/EmitC/IR/EmitC.h"
24#include "mlir/Dialect/Func/IR/FuncOps.h"
25#include "mlir/Dialect/Math/IR/Math.h"
26#include "mlir/Dialect/MemRef/IR/MemRef.h"
27#include "mlir/Dialect/SCF/IR/SCF.h"
28#include "mlir/Dialect/UB/IR/UBOps.h"
29#include "mlir/IR/PatternMatch.h"
30#include "mlir/IR/SymbolTable.h"
31#include "mlir/IR/TypeUtilities.h"
32#include "mlir/Pass/PassManager.h"
33#include "mlir/Transforms/DialectConversion.h"
34#include "mlir/Transforms/Passes.h"
35#include "llvm/ADT/SmallSet.h"
40#define DEBUG_TYPE "lower-vector-to-aievec"
61static bool isSRSCompoundCandidate(arith::TruncIOp trunciOp) {
62 Value source = trunciOp.getIn();
65 if (source.getDefiningOp<arith::ShRSIOp>())
69 if (
auto minsiOp = source.getDefiningOp<arith::MinSIOp>()) {
70 if (
auto maxsiOp = minsiOp.getLhs().getDefiningOp<arith::MaxSIOp>()) {
71 if (maxsiOp.getLhs().getDefiningOp<arith::ShRSIOp>())
77 if (
auto maxsiOp = source.getDefiningOp<arith::MaxSIOp>()) {
78 if (
auto minsiOp = maxsiOp.getLhs().getDefiningOp<arith::MinSIOp>()) {
79 if (minsiOp.getLhs().getDefiningOp<arith::ShRSIOp>())
86 if (
auto minsiOp = source.getDefiningOp<arith::MinSIOp>()) {
87 if (minsiOp.getLhs().getDefiningOp<arith::MaxSIOp>())
92 if (
auto maxsiOp = source.getDefiningOp<arith::MaxSIOp>()) {
93 if (maxsiOp.getLhs().getDefiningOp<arith::MinSIOp>())
102static bool shrsiUsedByCompoundSRS(arith::ShRSIOp rsOp) {
103 for (Operation *user : rsOp->getUsers()) {
105 if (
auto truncOp = dyn_cast<arith::TruncIOp>(user))
106 if (isSRSCompoundCandidate(truncOp))
110 if (isa<arith::MaxSIOp, arith::MinSIOp>(user)) {
111 for (Operation *user2 : user->getUsers()) {
112 if (
auto truncOp2 = dyn_cast<arith::TruncIOp>(user2))
113 if (isSRSCompoundCandidate(truncOp2))
115 if (isa<arith::MaxSIOp, arith::MinSIOp>(user2)) {
116 for (Operation *user3 : user2->getUsers()) {
117 if (
auto truncOp3 = dyn_cast<arith::TruncIOp>(user3))
118 if (isSRSCompoundCandidate(truncOp3))
131static bool scalarClampInCompoundSRS(Operation *op) {
132 if (!isa<arith::MaxSIOp, arith::MinSIOp>(op))
135 if (isa<VectorType>(op->getResult(0).getType()))
137 for (Operation *user : op->getUsers()) {
138 if (
auto truncOp = dyn_cast<arith::TruncIOp>(user)) {
139 if (isSRSCompoundCandidate(truncOp))
142 if (isa<arith::MaxSIOp, arith::MinSIOp>(user)) {
143 for (Operation *user2 : user->getUsers()) {
144 if (
auto truncOp2 = dyn_cast<arith::TruncIOp>(user2)) {
145 if (isSRSCompoundCandidate(truncOp2))
157static Value skipShapeCastRoundTrip(Value v) {
159 while (
auto castOp = src.getDefiningOp<vector::ShapeCastOp>())
160 src = castOp.getSource();
161 return src.getType() == v.getType() ? src : v;
167static std::optional<Value> getSourceOfWideningOp(Value src) {
168 src = skipShapeCastRoundTrip(src);
169 if (
auto extSIOp = src.getDefiningOp<arith::ExtSIOp>())
170 return extSIOp.getIn();
171 if (
auto extUIOp = src.getDefiningOp<arith::ExtUIOp>())
172 return extUIOp.getIn();
173 if (
auto extFOp = src.getDefiningOp<arith::ExtFOp>())
174 return extFOp.getIn();
175 if (
auto srsOp = src.getDefiningOp<aievec::SRSOp>()) {
179 auto srsSource = srsOp.getSource();
181 if (
auto upsOp = srsSource.getDefiningOp<aievec::UPSOp>())
182 return upsOp.getSource();
184 if (
auto castOp = src.getDefiningOp<aievec::CastOp>()) {
188 auto castSource = castOp.getSource();
190 if (
auto upsOp = castSource.getDefiningOp<aievec::UPSOp>())
191 return upsOp.getSource();
193 return std::optional<Value>();
198static bool holdsBF16(Value src) {
199 if (
auto wideSrc = getSourceOfWideningOp(src))
200 return getElementTypeOrSelf(wideSrc->getType()).isBF16();
201 DenseFPElementsAttr dense;
202 if (!matchPattern(src, m_Constant(&dense)) || !dense.getElementType().isF32())
204 return llvm::all_of(dense.getValues<APFloat>(), [](APFloat v) {
205 bool losesInfo = false;
206 v.convert(APFloat::BFloat(), APFloat::rmNearestTiesToEven, &losesInfo);
214static Value getBF16Source(OpBuilder &builder, Location loc, Value src) {
215 if (
auto wideSrc = getSourceOfWideningOp(src))
217 auto bf16Type = VectorType::get(cast<VectorType>(src.getType()).getShape(),
218 builder.getBF16Type());
220 arith::ConstantOp::create(builder, loc, builder.getI32IntegerAttr(0));
221 return aievec::SRSOp::create(builder, loc, bf16Type, src, shift);
232static std::optional<bool> getSignednessOfWideningOp(Value src) {
235 while (
auto castOp = src.getDefiningOp<vector::ShapeCastOp>())
236 src = castOp.getSource();
237 if (src.getDefiningOp<arith::ExtSIOp>())
239 if (src.getDefiningOp<arith::ExtUIOp>())
244 if (
auto srsOp = src.getDefiningOp<aievec::SRSOp>())
245 return srsOp.getSign() != 0;
251static std::optional<Value> getSourceOfNarrowingOp(Value src) {
252 if (
auto truncFOp = src.getDefiningOp<arith::TruncFOp>())
253 return truncFOp.getIn();
254 if (
auto truncIOp = src.getDefiningOp<arith::TruncIOp>())
255 return truncIOp.getIn();
256 return std::optional<Value>();
265static Value widenValueWithNarrowingCheck(Value val, Type targetType,
267 ConversionPatternRewriter &rewriter) {
269 if (
auto narrowedSrc = getSourceOfNarrowingOp(val)) {
270 if (narrowedSrc->getType() == targetType)
275 if (val.getType() == targetType)
278 return arith::ExtFOp::create(rewriter, loc, targetType, val,
292narrowValueWithWideningCheck(Operation *srcOp, Value val, Type targetType,
294 ConversionPatternRewriter &rewriter) {
301 if (srcOp->hasOneUse()) {
302 Operation *user = *srcOp->getUsers().begin();
303 if (
auto extfOp = dyn_cast<arith::ExtFOp>(user)) {
313 arith::TruncFOp::create(rewriter, loc, targetType, val);
323performBF16BinaryOpInF32(Value lhs, Value rhs, Operation *srcOp, Location loc,
324 ConversionPatternRewriter &rewriter,
325 const std::function<Value(Value, Value)> &opBuilder) {
326 Type f32Type = rewriter.getF32Type();
329 Value lhsF32 = widenValueWithNarrowingCheck(lhs, f32Type, loc, rewriter);
330 Value rhsF32 = widenValueWithNarrowingCheck(rhs, f32Type, loc, rewriter);
333 Value resultF32 = opBuilder(lhsF32, rhsF32);
336 auto narrowResult = narrowValueWithWideningCheck(
337 srcOp, resultF32, lhs.getType(), loc, rewriter);
339 if (narrowResult.skipNarrowing) {
341 rewriter.replaceOp(narrowResult.wideningUser, resultF32);
342 rewriter.eraseOp(srcOp);
344 rewriter.replaceOp(srcOp, narrowResult.narrowedValue);
351static std::optional<std::tuple<Value, Value, Value>>
352extractMACOperandsFromAddOperands(Value addLhs, Value addRhs) {
353 auto *lhsDefOp = addLhs.getDefiningOp();
354 auto *rhsDefOp = addRhs.getDefiningOp();
355 arith::MulIOp mulOp =
nullptr;
358 mulOp = dyn_cast<arith::MulIOp>(lhsDefOp);
361 if (!mulOp && rhsDefOp) {
362 mulOp = dyn_cast<arith::MulIOp>(rhsDefOp);
366 return std::make_tuple(mulOp.getLhs(), mulOp.getRhs(), acc);
369 auto lhsSrsOp = addLhs.getDefiningOp<aievec::SRSOp>();
370 auto rhsSrsOp = addRhs.getDefiningOp<aievec::SRSOp>();
371 aievec::aie1::MulOp aieMulOp =
nullptr;
373 aieMulOp = lhsSrsOp.getSource().getDefiningOp<aievec::aie1::MulOp>();
376 if (!aieMulOp && rhsSrsOp) {
377 aieMulOp = rhsSrsOp.getSource().getDefiningOp<aievec::aie1::MulOp>();
381 return std::make_tuple(aieMulOp.getLhs(), aieMulOp.getRhs(), acc);
388static std::optional<std::tuple<Value, Value, Value>>
389extractFMACOperandsFromAddOperands(Value addLhs, Value addRhs) {
390 auto *lhsDefOp = addLhs.getDefiningOp();
391 auto *rhsDefOp = addRhs.getDefiningOp();
392 arith::MulFOp mulOp =
nullptr;
395 mulOp = dyn_cast<arith::MulFOp>(lhsDefOp);
398 if (!mulOp && rhsDefOp) {
399 mulOp = dyn_cast<arith::MulFOp>(rhsDefOp);
403 return std::make_tuple(mulOp.getLhs(), mulOp.getRhs(), acc);
410static std::optional<Value>
411convertValueToTargetTypeAIE2(ConversionPatternRewriter &rewriter, Location loc,
412 Value inputVal, VectorType tgtType) {
413 auto srcType = cast<VectorType>(inputVal.getType());
414 auto srcElemType = srcType.getElementType();
415 unsigned srcBitWidth = srcElemType.getIntOrFloatBitWidth();
418 auto tgtElemType = tgtType.getElementType();
419 unsigned tgtBitWidth = tgtElemType.getIntOrFloatBitWidth();
422 if (srcType == tgtType)
425 if ((srcElemType == tgtElemType) && (srcLaneSize != tgtLaneSize)) {
427 if ((srcLaneSize == 16 && tgtLaneSize == 32 &&
428 isa<FloatType>(srcElemType)) ||
429 (srcLaneSize == 32 && tgtLaneSize == 64 &&
430 isa<IntegerType>(srcElemType))) {
431 auto zeroConstOp = arith::ConstantOp::create(
432 rewriter, loc, srcType.getElementType(),
433 rewriter.getZeroAttr(srcType.getElementType()));
434 auto broadcastZeroOp = aievec::BroadcastScalarOp::create(
435 rewriter, loc, tgtType, zeroConstOp->getResult(0));
436 auto extOp = aievec::ExtOp::create(rewriter, loc, srcType,
437 broadcastZeroOp->getResult(0), 0);
439 SmallVector<Value> inputSources = {inputVal, extOp->getResult(0)};
441 aievec::ConcatOp::create(rewriter, loc, tgtType, inputSources);
443 return concatOp.getResult();
445 }
else if ((srcElemType != tgtElemType) && (srcLaneSize == tgtLaneSize) &&
446 isa<IntegerType>(srcElemType) && isa<IntegerType>(tgtElemType)) {
447 if (srcBitWidth == 16 && tgtBitWidth == 32 && srcLaneSize == 16) {
451 auto upsOp = aievec::UPSOp::create(rewriter, loc, accType, inputVal);
452 auto castOp = aievec::CastOp::create(
453 rewriter, loc, tgtType, upsOp.getResult(),
false);
454 return castOp.getResult();
457 if (srcBitWidth == 8 && tgtBitWidth == 32 && srcLaneSize == 16) {
462 aievec::ConcatOp::create(rewriter, loc, concatOutType,
463 SmallVector<Value>({inputVal, inputVal}));
466 aievec::UPSOp::create(rewriter, loc, accType, concatOp.getResult());
468 auto castOp = aievec::CastOp::create(
469 rewriter, loc, castType, upsOp.getResult(),
false);
471 aievec::ExtOp::create(rewriter, loc, tgtType, castOp.getResult(), 0);
472 return extOp.getResult();
475 if (srcBitWidth == 8 && tgtBitWidth == 16 && srcLaneSize == 32) {
478 aievec::UnpackOp::create(rewriter, loc, tgtType, inputVal);
479 return unpackOp.getResult();
489static SmallVector<NamedAttribute>
490buildAttributeListForRotationSelectOp(PatternRewriter &rewriter, VectorType vTy,
493 auto elemTy = vTy.getElementType();
494 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
495 width = intTy.getWidth();
496 StringAttr attr0 = rewriter.getStringAttr(
"0");
497 StringAttr attr0x06040200 = rewriter.getStringAttr(
"0x06040200");
498 StringAttr attr0x0e0c0a08 = rewriter.getStringAttr(
"0x0e0c0a08");
499 StringAttr attr0x2103 = rewriter.getStringAttr(
"0x2103");
500 StringAttr attr0x3210 = rewriter.getStringAttr(
"0x3210");
501 StringAttr selectAttrName = rewriter.getStringAttr(
"select");
502 StringAttr xoffsetsAttrName = rewriter.getStringAttr(
"xoffsets");
503 StringAttr xoffsetsHiAttrName = rewriter.getStringAttr(
"xoffsets_hi");
504 StringAttr xsquareAttrName = rewriter.getStringAttr(
"xsquare");
505 StringAttr xstartAttrName = rewriter.getStringAttr(
"xstart");
506 StringAttr yoffsetsAttrName = rewriter.getStringAttr(
"yoffsets");
507 StringAttr yoffsetsHiAttrName = rewriter.getStringAttr(
"yoffsets_hi");
508 StringAttr ysquareAttrName = rewriter.getStringAttr(
"ysquare");
509 StringAttr ystartAttrName = rewriter.getStringAttr(
"ystart");
514 int64_t xstart = rotation + 1;
515 int64_t ystart = rotation - 1;
516 return SmallVector<NamedAttribute, 9>(
517 {{selectAttrName, rewriter.getStringAttr(
"0x11111111")},
518 {xoffsetsAttrName, attr0x06040200},
519 {xoffsetsHiAttrName, attr0x0e0c0a08},
520 {xsquareAttrName, attr0x2103},
521 {xstartAttrName, rewriter.getStringAttr(std::to_string(xstart))},
522 {yoffsetsAttrName, rewriter.getStringAttr(
"0x0503010f")},
523 {yoffsetsHiAttrName, rewriter.getStringAttr(
"0x0d0b0907")},
524 {ysquareAttrName, attr0x2103},
525 {ystartAttrName, rewriter.getStringAttr(std::to_string(ystart))}});
527 return SmallVector<NamedAttribute, 9>(
528 {{selectAttrName, attr0},
529 {xoffsetsAttrName, attr0x06040200},
530 {xoffsetsHiAttrName, attr0x0e0c0a08},
531 {xsquareAttrName, attr0x3210},
532 {xstartAttrName, rewriter.getStringAttr(std::to_string(rotation))},
533 {yoffsetsAttrName, attr0},
534 {yoffsetsHiAttrName, attr0},
535 {ysquareAttrName, attr0},
536 {ystartAttrName, attr0}});
539 return SmallVector<NamedAttribute, 7>(
540 {{selectAttrName, attr0},
541 {xoffsetsAttrName, rewriter.getStringAttr(
"0x76543210")},
542 {xsquareAttrName, attr0x3210},
543 {xstartAttrName, rewriter.getStringAttr(std::to_string(rotation))},
544 {yoffsetsAttrName, attr0},
545 {ysquareAttrName, attr0},
546 {ystartAttrName, attr0}});
548 llvm::report_fatal_error(
"Unexpected width!");
558SmallVector<NamedAttribute>
563 auto elemTy = fmaOp.getLhs().getType().getElementType();
564 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
565 width = intTy.getWidth();
566 auto *ctx = fmaOp.getContext();
586 return SmallVector<NamedAttribute, 11>(
587 {{fmaOp.getXstartAttrName(), StringAttr::get(ctx,
"0")},
588 {fmaOp.getXoffsetsAttrName(), StringAttr::get(ctx,
"0x73727170")},
589 {fmaOp.getXoffsetsHiAttrName(), StringAttr::get(ctx,
"0x77767574")},
590 {fmaOp.getXstepAttrName(), fmaOp.getXstepAttr()},
591 {fmaOp.getXsquareAttrName(), StringAttr::get(ctx,
"0x3120")},
592 {fmaOp.getZstartAttrName(),
593 StringAttr::get(ctx, std::to_string(bcastPos))},
594 {fmaOp.getZoffsetsAttrName(), StringAttr::get(ctx,
"0")},
595 {fmaOp.getZoffsetsHiAttrName(), StringAttr::get(ctx,
"0")},
596 {fmaOp.getZstepAttrName(), StringAttr::get(ctx, std::to_string(step))},
597 {fmaOp.getZsquareAttrName(), fmaOp.getZsquareAttr()},
598 {fmaOp.getFmsubAttrName(), fmaOp.getFmsubAttr()}});
600 return SmallVector<NamedAttribute, 11>(
601 {{fmaOp.getXstartAttrName(), StringAttr::get(ctx,
"0")},
602 {fmaOp.getXoffsetsAttrName(), StringAttr::get(ctx,
"0x76543210")},
603 {fmaOp.getXoffsetsHiAttrName(), fmaOp.getXoffsetsHiAttr()},
604 {fmaOp.getXstepAttrName(), fmaOp.getXstepAttr()},
605 {fmaOp.getXsquareAttrName(), fmaOp.getXsquareAttr()},
606 {fmaOp.getZstartAttrName(),
607 StringAttr::get(ctx, std::to_string(bcastPos))},
608 {fmaOp.getZoffsetsAttrName(), StringAttr::get(ctx,
"0x00000000")},
609 {fmaOp.getZoffsetsHiAttrName(), fmaOp.getZoffsetsHiAttr()},
610 {fmaOp.getZstepAttrName(), fmaOp.getZstepAttr()},
611 {fmaOp.getZsquareAttrName(), fmaOp.getZsquareAttr()},
612 {fmaOp.getFmsubAttrName(), fmaOp.getFmsubAttr()}});
614 llvm::report_fatal_error(
"Unexpected width!");
622template <
typename SrcOpTy,
typename AIEv2ElemOp>
623static LogicalResult genAddElemAIE2(ConversionPatternRewriter &rewriter,
624 Value lval, Value rval, VectorType srcType,
626 auto lCastOp = aievec::CastOp::create(rewriter, srcOp.getLoc(), srcType, lval,
628 auto rCastOp = aievec::CastOp::create(rewriter, srcOp.getLoc(), srcType, rval,
630 auto elemOp = AIEv2ElemOp::create(
631 rewriter, srcOp.getLoc(), lCastOp->getResult(0).getType(),
632 lCastOp->getResult(0), rCastOp->getResult(0));
633 rewriter.replaceOpWithNewOp<aievec::CastOp>(
634 srcOp, srcOp.getType(), elemOp.getResult(),
false);
638static arith::CmpIPredicate
639convertToIntegerPredicate(arith::CmpFPredicate pred) {
641 case CmpFPredicate::UEQ:
642 case CmpFPredicate::OEQ:
643 return CmpIPredicate::eq;
644 case CmpFPredicate::UGT:
645 return CmpIPredicate::ugt;
646 case CmpFPredicate::OGT:
647 return CmpIPredicate::sgt;
648 case CmpFPredicate::UGE:
649 return CmpIPredicate::uge;
650 case CmpFPredicate::OGE:
651 return CmpIPredicate::sge;
652 case CmpFPredicate::ULT:
653 return CmpIPredicate::ult;
654 case CmpFPredicate::OLT:
655 return CmpIPredicate::slt;
656 case CmpFPredicate::ULE:
657 return CmpIPredicate::ule;
658 case CmpFPredicate::OLE:
659 return CmpIPredicate::sle;
660 case CmpFPredicate::UNE:
661 case CmpFPredicate::ONE:
662 return CmpIPredicate::ne;
664 llvm::report_fatal_error(
"Unexpected predicate!");
668static arith::CmpIPredicate
669convertToIntegerPredicate(arith::CmpIPredicate pred) {
673static aievec::CmpOp createCmpOpAIE2(ConversionPatternRewriter &rewriter,
674 CmpIPredicate pred, Location loc,
675 Type type, Value lhs, Value rhs) {
677 case CmpIPredicate::eq:
678 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"eq");
679 case CmpIPredicate::ne:
680 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"ne");
681 case CmpIPredicate::slt:
682 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"slt");
683 case CmpIPredicate::ult:
684 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"ult");
685 case CmpIPredicate::sle:
686 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"sle");
687 case CmpIPredicate::ule:
688 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"ule");
689 case CmpIPredicate::sgt:
690 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"sgt");
691 case CmpIPredicate::ugt:
692 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"ugt");
693 case CmpIPredicate::sge:
694 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"sge");
695 case CmpIPredicate::uge:
696 return aievec::CmpOp::create(rewriter, loc, type, lhs, rhs,
"uge");
701template <
typename DstOpTy>
702static aievec::ExtElemOp
703generateAIEVecOpsForReductionOp(ConversionPatternRewriter &rewriter,
704 vector::ReductionOp srcOp,
int shiftIndex,
706 assert(shiftIndex > 0 && (shiftIndex & (shiftIndex - 1)) == 0 &&
707 "shiftIndex must be power of 2");
709 Location loc = srcOp.getLoc();
710 auto vType = cast<VectorType>(curValue.getType());
711 Type scalarType = vType.getElementType();
712 Type vecType = curValue.getType();
713 DstOpTy curOp =
nullptr;
714 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
716 for (
int id = shiftIndex;
id > 0;
id /= 2) {
717 auto constOp = arith::ConstantOp::create(
718 rewriter, loc, rewriter.getI32IntegerAttr(
id * elWidth / 8));
720 auto shiftBytesOp = aievec::ShiftOp::create(
721 rewriter, loc, vecType, curValue, curValue, constOp.getResult());
723 curOp = DstOpTy::create(rewriter, loc, vecType, curValue,
724 shiftBytesOp.getResult());
726 curValue = curOp.getResult();
730 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
731 return aievec::ExtElemOp::create(rewriter, loc, scalarType, curOp,
732 zeroConstOp.getResult());
738static std::pair<Value, unsigned>
739padV16ToV32WithInfinity(ConversionPatternRewriter &rewriter, Location loc,
740 Value inputVec, Type scalarType,
bool negativeInf) {
745 auto infAttr = rewriter.getFloatAttr(
747 APFloat::getInf(cast<FloatType>(scalarType).getFloatSemantics(),
749 auto splatInf = arith::ConstantOp::create(rewriter, loc, infAttr).getResult();
753 aievec::BroadcastScalarOp::create(rewriter, loc, v32bf16Type, splatInf);
755 aievec::ExtOp::create(rewriter, loc, v16bf16Type, infVec, 1);
759 aievec::ConcatOp::create(rewriter, loc, v32bf16Type,
760 ValueRange{inputVec, infUpperHalf.getResult()});
762 return {paddedVec, 32};
767static Value padV16ToV32WithZeros(ConversionPatternRewriter &rewriter,
768 Location loc, Value inputVec,
772 auto zeroAttr = rewriter.getZeroAttr(v16Type);
773 auto zeroVec = arith::ConstantOp::create(rewriter, loc, zeroAttr);
774 return aievec::ConcatOp::create(rewriter, loc, v32Type,
775 ValueRange{inputVec, zeroVec.getResult()});
778static func::FuncOp getOrInsertFuncDecl(ConversionPatternRewriter &rewriter,
779 Operation *parentSymbolTableOp,
780 StringRef funcName, TypeRange inTypes,
781 TypeRange outTypes) {
783 mlir::OpBuilder::InsertionGuard insertGuard(rewriter);
784 rewriter.setInsertionPointToStart(
785 &parentSymbolTableOp->getRegions().front().getBlocks().front());
786 SymbolTable st = SymbolTable(parentSymbolTableOp);
787 func::FuncOp fnOpLookup = st.lookup<func::FuncOp>(funcName);
791 if (fnOpLookup !=
nullptr) {
794 StringAttr t1 = rewriter.getStringAttr(
"sym_visibility");
795 StringAttr t2 = rewriter.getStringAttr(
"private");
796 NamedAttribute funcAccess = NamedAttribute(t1, t2);
797 FunctionType fnType =
798 mlir::FunctionType::get(rewriter.getContext(), inTypes, outTypes);
799 fnOp = func::FuncOp::create(rewriter, parentSymbolTableOp->getLoc(),
800 funcName, fnType, funcAccess);
830template <
typename SrcOpTy,
typename Func>
831static void splitWideVectorOp(SrcOpTy srcOp, ArrayRef<Value> wideInputs,
832 VectorType halfType, VectorType wideType,
833 ConversionPatternRewriter &rewriter,
834 Func &&processHalves) {
836 Location loc = srcOp.getLoc();
839 SmallVector<std::pair<Value, Value>> halfInputs;
840 halfInputs.reserve(wideInputs.size());
841 for (Value wideInput : wideInputs) {
843 aievec::ExtOp::create(rewriter, loc, halfType, wideInput, 0);
845 aievec::ExtOp::create(rewriter, loc, halfType, wideInput, 1);
846 halfInputs.emplace_back(lowerHalf.getResult(), upperHalf.getResult());
850 auto [lowResult, highResult] = processHalves(halfInputs, loc, rewriter);
853 SmallVector<Value> concatSources = {lowResult, highResult};
854 rewriter.replaceOpWithNewOp<aievec::ConcatOp>(srcOp, wideType, concatSources);
858template <
typename SrcOpTy>
859static void splitWideUnaryVectorOp(
860 SrcOpTy srcOp, Value wideInput, VectorType halfType, VectorType wideType,
861 ConversionPatternRewriter &rewriter,
862 std::function<Value(Value, Location, ConversionPatternRewriter &)>
865 splitWideVectorOp<SrcOpTy>(
866 srcOp, {wideInput}, halfType, wideType, rewriter,
867 [&processHalf](ArrayRef<std::pair<Value, Value>> halfInputs, Location loc,
868 ConversionPatternRewriter &rewriter) {
869 auto [lowerHalf, upperHalf] = halfInputs[0];
870 Value lowResult = processHalf(lowerHalf, loc, rewriter);
871 Value highResult = processHalf(upperHalf, loc, rewriter);
872 return std::make_pair(lowResult, highResult);
877template <
typename SrcOpTy>
878static void splitWideBinaryVectorOp(
879 SrcOpTy srcOp, Value lhs, Value rhs, VectorType halfType,
880 VectorType wideType, ConversionPatternRewriter &rewriter,
881 std::function<Value(Value, Value, Location, ConversionPatternRewriter &)>
884 splitWideVectorOp<SrcOpTy>(
885 srcOp, {lhs, rhs}, halfType, wideType, rewriter,
886 [&processHalf](ArrayRef<std::pair<Value, Value>> halfInputs, Location loc,
887 ConversionPatternRewriter &rewriter) {
888 auto [lhsLow, lhsHigh] = halfInputs[0];
889 auto [rhsLow, rhsHigh] = halfInputs[1];
890 Value lowResult = processHalf(lhsLow, rhsLow, loc, rewriter);
891 Value highResult = processHalf(lhsHigh, rhsHigh, loc, rewriter);
892 return std::make_pair(lowResult, highResult);
901static bool matchExpOpForAIE2LUT(math::ExpOp::Adaptor adaptor) {
902 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
907 Type scalarType = srcType.getElementType();
908 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
911 return isa<FloatType>(scalarType) && (laneSize == 16 || laneSize == 32) &&
916static bool matchExpOpForAIE2P(math::ExpOp::Adaptor adaptor) {
917 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
922 Type scalarType = srcType.getElementType();
923 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
926 return scalarType.isBF16() && (laneSize == 16 || laneSize == 32) &&
933static bool isAIE2PAccFloatUnaryType(VectorType type) {
934 if (type.isScalable())
936 Type elemType = type.getElementType();
938 return (elemType.isBF16() || elemType.isF32()) &&
939 (laneSize == 16 || laneSize == 32);
945static bool isAIE2PAccFloatUnaryOrScalarType(Type type) {
946 auto vecType = dyn_cast<VectorType>(type);
948 return type.isBF16() || type.isF32();
949 if (!vecType.isScalable() && vecType.getRank() == 1 &&
950 vecType.getNumElements() == 1) {
951 Type elemType = vecType.getElementType();
952 return elemType.isBF16() || elemType.isF32();
954 return isAIE2PAccFloatUnaryType(vecType);
964 : OpConversionPattern<vector::BroadcastOp> {
965 using OpConversionPattern::OpConversionPattern;
969 ConversionPatternRewriter &rewriter)
const override {
971 auto extOp = adaptor.getSource().getDefiningOp<vector::ExtractOp>();
976 auto src = extOp.getSource();
977 auto pos = extOp.getStaticPosition();
978 int64_t posVal = pos[0];
979 auto srcVecType = cast<VectorType>(src.getType());
980 auto resultType = cast<VectorType>(bcastOp.getResult().getType());
981 if (srcVecType != resultType) {
982 if (srcVecType.getNumElements() != 2 * resultType.getNumElements())
984 auto half =
static_cast<int8_t
>(posVal / resultType.getNumElements());
985 posVal -= half * resultType.getNumElements();
986 src = aievec::ExtOp::create(rewriter, extOp.getLoc(), resultType, src,
987 rewriter.getI8IntegerAttr(half))
991 unsigned elWidth = resultType.getElementType().getIntOrFloatBitWidth();
994 laneSize * elWidth == 512) {
996 rewriter.replaceOpWithNewOp<aievec::BroadcastOp>(bcastOp, resultType, src,
998 }
else if (laneSize * elWidth == 256) {
1000 VectorType aievecBcastType =
1003 aievec::ConcatOp::create(rewriter, bcastOp.getLoc(), aievecBcastType,
1004 SmallVector<Value>({src, src}));
1005 auto aieBcastOp = aievec::BroadcastOp::create(
1006 rewriter, bcastOp.getLoc(), aievecBcastType, concatOp.getResult(),
1008 rewriter.replaceOpWithNewOp<aievec::ExtOp>(bcastOp, resultType,
1009 aieBcastOp.getResult(), 0);
1010 }
else if (laneSize * elWidth == 1024) {
1012 VectorType aievecBcastType =
1014 auto half =
static_cast<int8_t
>(posVal / resultType.getNumElements());
1015 posVal -= half * resultType.getNumElements();
1017 aievec::ExtOp::create(rewriter, bcastOp.getLoc(), aievecBcastType,
1018 src, rewriter.getI8IntegerAttr(half));
1019 auto aieBcastOp = aievec::BroadcastOp::create(rewriter, bcastOp.getLoc(),
1021 extOp.getResult(), posVal);
1022 rewriter.replaceOpWithNewOp<aievec::ConcatOp>(
1023 bcastOp, resultType,
1024 SmallVector<Value>({aieBcastOp.getResult(), aieBcastOp.getResult()}));
1034 using OpConversionPattern::OpConversionPattern;
1038 ConversionPatternRewriter &rewriter)
const override {
1040 if (adaptor.getSource().getDefiningOp<vector::ExtractOp>())
1043 auto resultType = cast<VectorType>(bcastOp.getResult().getType());
1045 Type scalarType = resultType.getElementType();
1046 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
1048 auto src = bcastOp.getSource();
1050 if (laneSize * elWidth == 512) {
1051 Value newOp = aievec::BroadcastScalarOp::create(
1052 rewriter, bcastOp.getLoc(), flatResultType, src);
1053 if (resultType != flatResultType)
1054 newOp = vector::ShapeCastOp::create(rewriter, bcastOp.getLoc(),
1056 rewriter.replaceOp(bcastOp, newOp);
1060 if (laneSize * elWidth == 256) {
1062 auto aieBcastOp = aievec::BroadcastScalarOp::create(
1063 rewriter, bcastOp.getLoc(), vecType, src);
1065 aievec::ExtOp::create(rewriter, bcastOp.getLoc(), flatResultType,
1066 aieBcastOp.getResult(), 0);
1067 if (resultType != flatResultType)
1068 newOp = vector::ShapeCastOp::create(rewriter, bcastOp.getLoc(),
1070 rewriter.replaceOp(bcastOp, newOp);
1074 if (laneSize * elWidth == 1024) {
1076 auto aieBcastOp = aievec::BroadcastScalarOp::create(
1077 rewriter, bcastOp.getLoc(), vecType, src);
1078 Value newOp = aievec::ConcatOp::create(
1079 rewriter, bcastOp.getLoc(), flatResultType,
1080 SmallVector<Value>({aieBcastOp.getResult(), aieBcastOp.getResult()}));
1081 if (resultType != flatResultType)
1082 newOp = vector::ShapeCastOp::create(rewriter, bcastOp.getLoc(),
1084 rewriter.replaceOp(bcastOp, newOp);
1095 : OpConversionPattern<arith::AddIOp> {
1096 using OpConversionPattern::OpConversionPattern;
1104 ConversionPatternRewriter &rewriter)
const override {
1106 auto resultType = dyn_cast<VectorType>(addOp.getType());
1112 extractMACOperandsFromAddOperands(adaptor.getLhs(), adaptor.getRhs());
1115 auto [lhs, rhs, acc] = *res;
1118 unsigned resultElWidth =
1119 resultType.getElementType().getIntOrFloatBitWidth();
1122 if ((laneSize != 32 || resultElWidth != 16) &&
1123 (laneSize != 16 || resultElWidth != 32))
1128 auto upsOp = aievec::UPSOp::create(rewriter, addOp.getLoc(), accType, acc,
1130 auto fmaElemOp = aievec::FMAElemOp::create(
1131 rewriter, addOp.getLoc(), accType, lhs, rhs, upsOp.getResult(),
1134 auto shiftParamOp = arith::ConstantOp::create(
1135 rewriter, addOp.getLoc(), rewriter.getI32IntegerAttr(
shiftParam));
1136 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
1137 addOp, resultType, fmaElemOp.getResult(), shiftParamOp.getResult());
1146static Value lowerBF16FMAHalf(Value lhs, Value rhs, Value acc,
1147 unsigned shiftParam, Location loc,
1148 ConversionPatternRewriter &rewriter) {
1149 auto f32AccType = VectorType::get({16}, rewriter.getF32Type());
1151 aievec::UPSOp::create(rewriter, loc, f32AccType, acc, shiftParam);
1152 auto fmaElemOp = aievec::FMAElemOp::create(rewriter, loc, f32AccType, lhs,
1153 rhs, upsOp.getResult(),
1155 auto shiftParamOp = arith::ConstantOp::create(
1156 rewriter, loc, rewriter.getI32IntegerAttr(shiftParam));
1158 aievec::SRSOp::create(rewriter, loc, cast<VectorType>(lhs.getType()),
1159 fmaElemOp.getResult(), shiftParamOp.getResult());
1160 return srsOp.getResult();
1171 : OpConversionPattern<vector::FMAOp> {
1172 using OpConversionPattern::OpConversionPattern;
1180 ConversionPatternRewriter &rewriter)
const override {
1182 auto resVecTy = cast<VectorType>(fmaOp.getType());
1183 auto resElemTy = resVecTy.getElementType();
1187 if ((!resElemTy.isF32() && !resElemTy.isBF16()) ||
1188 (numElems != 16 && numElems != 32))
1189 return rewriter.notifyMatchFailure(
1190 fmaOp,
"Unsupported operand types in vector.fma lowering.");
1192 Value lhs = adaptor.getLhs();
1193 Value rhs = adaptor.getRhs();
1194 Value acc = adaptor.getAcc();
1196 if (resElemTy.isF32()) {
1197 if (!holdsBF16(lhs) || !holdsBF16(rhs))
1198 return rewriter.notifyMatchFailure(
1199 fmaOp,
"vector.fma operands are f32 and do not hold bf16 values; "
1200 "can't lower to aievec.");
1201 Location loc = fmaOp.getLoc();
1202 lhs = getBF16Source(rewriter, loc, lhs);
1203 rhs = getBF16Source(rewriter, loc, rhs);
1204 if (numElems == 16) {
1205 rewriter.replaceOpWithNewOp<aievec::FMAElemOp>(
1206 fmaOp, acc.getType(), lhs, rhs, acc,
false);
1212 SmallVector<Value> halves;
1213 for (
int idx : {0, 1}) {
1215 aievec::ExtOp::create(rewriter, loc, bf16HalfTy, lhs, idx);
1217 aievec::ExtOp::create(rewriter, loc, bf16HalfTy, rhs, idx);
1219 aievec::ExtOp::create(rewriter, loc, f32HalfTy, acc, idx);
1220 halves.push_back(aievec::FMAElemOp::create(rewriter, loc, f32HalfTy,
1221 lhsHalf, rhsHalf, accHalf,
1224 rewriter.replaceOpWithNewOp<aievec::ConcatOp>(fmaOp, resVecTy, halves);
1229 if (numElems == 32 && resElemTy.isBF16()) {
1233 splitWideVectorOp<vector::FMAOp>(
1234 fmaOp, {lhs, rhs, acc}, halfType, resVecTy, rewriter,
1235 [localShiftParam](ArrayRef<std::pair<Value, Value>> halfInputs,
1236 Location loc, ConversionPatternRewriter &rewriter) {
1237 auto [lhsLow, lhsHigh] = halfInputs[0];
1238 auto [rhsLow, rhsHigh] = halfInputs[1];
1239 auto [accLow, accHigh] = halfInputs[2];
1241 Value lowResult = lowerBF16FMAHalf(lhsLow, rhsLow, accLow,
1242 localShiftParam, loc, rewriter);
1243 Value highResult = lowerBF16FMAHalf(lhsHigh, rhsHigh, accHigh,
1244 localShiftParam, loc, rewriter);
1245 return std::make_pair(lowResult, highResult);
1250 acc = aievec::UPSOp::create(rewriter, fmaOp.getLoc(),
1251 VectorType::get({16}, rewriter.getF32Type()),
1254 aievec::FMAElemOp::create(rewriter, fmaOp.getLoc(), acc.getType(), lhs,
1256 auto shiftParamOp = arith::ConstantOp::create(
1257 rewriter, fmaOp.getLoc(), rewriter.getI32IntegerAttr(
shiftParam));
1258 newOp = aievec::SRSOp::create(rewriter, fmaOp.getLoc(), resVecTy, newOp,
1261 rewriter.replaceOp(fmaOp, newOp);
1272 : OpConversionPattern<vector::FMAOp> {
1273 using OpConversionPattern::OpConversionPattern;
1277 ConversionPatternRewriter &rewriter)
const override {
1278 auto resVecTy = cast<VectorType>(fmaOp.getType());
1279 if (!resVecTy.getElementType().isF32() || resVecTy.getRank() != 1 ||
1280 resVecTy.getNumElements() != 32 || !holdsBF16(adaptor.getLhs()) ||
1281 !holdsBF16(adaptor.getRhs()))
1283 Location loc = fmaOp.getLoc();
1284 Value lhs = getBF16Source(rewriter, loc, adaptor.getLhs());
1285 Value rhs = getBF16Source(rewriter, loc, adaptor.getRhs());
1286 rewriter.replaceOpWithNewOp<aievec::FMAElemOp>(
1287 fmaOp, resVecTy, lhs, rhs, adaptor.getAcc(),
false);
1294 : OpConversionPattern<arith::MulFOp> {
1295 using OpConversionPattern::OpConversionPattern;
1299 ConversionPatternRewriter &rewriter)
const override {
1300 auto resVecTy = dyn_cast<VectorType>(mulOp.getType());
1301 if (!resVecTy || !resVecTy.getElementType().isF32() ||
1302 resVecTy.getRank() != 1 ||
1303 (resVecTy.getNumElements() != 32 && resVecTy.getNumElements() != 64) ||
1304 !holdsBF16(adaptor.getLhs()) || !holdsBF16(adaptor.getRhs()))
1306 Location loc = mulOp.getLoc();
1307 Value lhs = getBF16Source(rewriter, loc, adaptor.getLhs());
1308 Value rhs = getBF16Source(rewriter, loc, adaptor.getRhs());
1310 aievec::MulElemOp::create(rewriter, loc, resVecTy, lhs, rhs);
1311 rewriter.replaceOpWithNewOp<aievec::CastOp>(mulOp, resVecTy, mulElemOp,
1320 : OpConversionPattern<arith::AddFOp> {
1321 using OpConversionPattern::OpConversionPattern;
1329 ConversionPatternRewriter &rewriter)
const override {
1331 auto resultType = dyn_cast<VectorType>(addOp.getType());
1336 auto elemType = resultType.getElementType();
1337 if (!elemType.isBF16())
1342 extractFMACOperandsFromAddOperands(adaptor.getLhs(), adaptor.getRhs());
1345 auto [lhs, rhs, acc] = *res;
1350 if (laneSize == 32) {
1354 splitWideVectorOp<arith::AddFOp>(
1355 addOp, {lhs, rhs, acc}, halfType, resultType, rewriter,
1356 [localShiftParam](ArrayRef<std::pair<Value, Value>> halfInputs,
1357 Location loc, ConversionPatternRewriter &rewriter) {
1358 auto [lhsLow, lhsHigh] = halfInputs[0];
1359 auto [rhsLow, rhsHigh] = halfInputs[1];
1360 auto [accLow, accHigh] = halfInputs[2];
1362 Value lowResult = lowerBF16FMAHalf(lhsLow, rhsLow, accLow,
1363 localShiftParam, loc, rewriter);
1364 Value highResult = lowerBF16FMAHalf(lhsHigh, rhsHigh, accHigh,
1365 localShiftParam, loc, rewriter);
1366 return std::make_pair(lowResult, highResult);
1375 auto f32AccType = VectorType::get({16}, rewriter.getF32Type());
1376 auto upsOp = aievec::UPSOp::create(rewriter, addOp.getLoc(), f32AccType,
1378 auto fmaElemOp = aievec::FMAElemOp::create(
1379 rewriter, addOp.getLoc(), f32AccType, lhs, rhs, upsOp.getResult(),
1382 auto shiftParamOp = arith::ConstantOp::create(
1383 rewriter, addOp.getLoc(), rewriter.getI32IntegerAttr(
shiftParam));
1384 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
1385 addOp, resultType, fmaElemOp.getResult(), shiftParamOp.getResult());
1396 : OpConversionPattern<arith::MulFOp> {
1397 using OpConversionPattern::OpConversionPattern;
1405 ConversionPatternRewriter &rewriter)
const override {
1407 auto resultType = dyn_cast<VectorType>(mulOp.getType());
1415 auto isAddOp = [&](Operation *op) {
return isa<arith::AddFOp>(op); };
1416 if (resultType.getElementType().isBF16() && mulOp->hasOneUse() &&
1417 llvm::any_of(mulOp->getUsers(), isAddOp))
1420 unsigned resultElWidth =
1421 resultType.getElementType().getIntOrFloatBitWidth();
1426 if (resultType.getElementType().isF32() &&
1427 (laneSize == 16 || laneSize == 32) && holdsBF16(adaptor.getLhs()) &&
1428 holdsBF16(adaptor.getRhs())) {
1429 Location loc = mulOp.getLoc();
1430 Value lhs = getBF16Source(rewriter, loc, adaptor.getLhs());
1431 Value rhs = getBF16Source(rewriter, loc, adaptor.getRhs());
1434 auto mul16 = [&](Value l, Value r) -> Value {
1436 aievec::MulElemOp::create(rewriter, loc, f32HalfTy, l, r);
1437 return aievec::CastOp::create(rewriter, loc, f32HalfTy, mulElemOp,
1440 if (laneSize == 16) {
1441 rewriter.replaceOp(mulOp, mul16(lhs, rhs));
1444 SmallVector<Value> halves;
1445 for (
int idx : {0, 1})
1447 mul16(aievec::ExtOp::create(rewriter, loc, bf16HalfTy, lhs, idx),
1448 aievec::ExtOp::create(rewriter, loc, bf16HalfTy, rhs, idx)));
1449 rewriter.replaceOpWithNewOp<aievec::ConcatOp>(mulOp, resultType, halves);
1454 if (laneSize == 32 && resultElWidth == 16) {
1458 splitWideBinaryVectorOp<arith::MulFOp>(
1459 mulOp, adaptor.getLhs(), adaptor.getRhs(), halfType, resultType,
1461 [localShiftParam](Value lhsHalf, Value rhsHalf, Location loc,
1462 ConversionPatternRewriter &rewriter) -> Value {
1463 Type accType = getVectorOpDestType(
1464 cast<VectorType>(lhsHalf.getType()), true);
1465 auto mulElemOp = aievec::MulElemOp::create(rewriter, loc, accType,
1467 auto shiftParamOp = arith::ConstantOp::create(
1468 rewriter, loc, rewriter.getI32IntegerAttr(localShiftParam));
1469 auto srsOp = aievec::SRSOp::create(
1470 rewriter, loc, cast<VectorType>(lhsHalf.getType()),
1471 mulElemOp.getResult(), shiftParamOp.getResult());
1472 return srsOp.getResult();
1478 if (laneSize != 16 || (resultElWidth != 16 && resultElWidth != 32))
1482 auto lval = adaptor.getLhs();
1483 auto rval = adaptor.getRhs();
1484 lval = getSourceOfWideningOp(lval).value_or(lval);
1485 rval = getSourceOfWideningOp(rval).value_or(rval);
1486 auto lSrcType = cast<VectorType>(lval.getType());
1487 auto rSrcType = cast<VectorType>(rval.getType());
1488 unsigned lBitWidth = lSrcType.getElementType().getIntOrFloatBitWidth();
1489 unsigned rBitWidth = rSrcType.getElementType().getIntOrFloatBitWidth();
1491 if (rBitWidth > lBitWidth) {
1495 if (lSrcType != rSrcType) {
1500 unsigned bitWidth = (rBitWidth > lBitWidth) ? rBitWidth : lBitWidth;
1501 Type srcElemType = (rBitWidth > lBitWidth) ? rSrcType.getElementType()
1502 : lSrcType.getElementType();
1503 unsigned numLanes = 0;
1506 if (isa<FloatType>(srcElemType) &&
1507 (bitWidth == 16 || bitWidth == 32)) {
1509 }
else if (isa<IntegerType>(srcElemType) &&
1510 (bitWidth == 8 || bitWidth == 16)) {
1512 }
else if (isa<IntegerType>(srcElemType) && (bitWidth == 32)) {
1518 if (targetInputType != lSrcType) {
1519 auto converted = convertValueToTargetTypeAIE2(rewriter, mulOp.getLoc(),
1520 lval, targetInputType);
1525 if (targetInputType != rSrcType) {
1526 auto converted = convertValueToTargetTypeAIE2(rewriter, mulOp.getLoc(),
1527 rval, targetInputType);
1536 auto mulElemOp = aievec::MulElemOp::create(rewriter, mulOp.getLoc(),
1537 accType, lval, rval);
1540 auto mulElemResultType = mulElemOp.getType();
1541 auto mulElemResultElWidth =
1542 mulElemResultType.getElementType().getIntOrFloatBitWidth();
1544 if (mulElemResultElWidth == resultElWidth) {
1545 rewriter.replaceOpWithNewOp<aievec::CastOp>(
1546 mulOp, resultType, mulElemOp.getResult(),
false);
1547 }
else if (mulElemResultElWidth > resultElWidth) {
1548 auto shiftParamOp = arith::ConstantOp::create(
1549 rewriter, mulOp.getLoc(), rewriter.getI32IntegerAttr(
shiftParam));
1550 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
1551 mulOp, resultType, mulElemOp.getResult(), shiftParamOp.getResult());
1565 : OpConversionPattern<arith::MulIOp> {
1566 using OpConversionPattern::OpConversionPattern;
1574 ConversionPatternRewriter &rewriter)
const override {
1576 auto resultType = dyn_cast<VectorType>(mulOp.getType());
1581 auto isAddOp = [&](Operation *op) {
return isa<arith::AddIOp>(op); };
1582 if (mulOp->hasOneUse() && llvm::any_of(mulOp->getUsers(), isAddOp))
1586 unsigned resultElWidth =
1587 resultType.getElementType().getIntOrFloatBitWidth();
1590 if ((laneSize != 32 || (resultElWidth != 16 && resultElWidth != 8)) &&
1591 ((laneSize != 16 && laneSize != 32) || resultElWidth != 32))
1595 auto lval = adaptor.getLhs();
1596 auto rval = adaptor.getRhs();
1598 lval = getSourceOfWideningOp(lval).value_or(lval);
1599 rval = getSourceOfWideningOp(rval).value_or(rval);
1601 auto lSrcType = cast<VectorType>(lval.getType());
1602 auto rSrcType = cast<VectorType>(rval.getType());
1603 unsigned lBitWidth = lSrcType.getElementType().getIntOrFloatBitWidth();
1604 unsigned rBitWidth = rSrcType.getElementType().getIntOrFloatBitWidth();
1606 if (rBitWidth > lBitWidth) {
1611 unsigned bitWidth = (rBitWidth > lBitWidth) ? rBitWidth : lBitWidth;
1612 Type srcElemType = (rBitWidth > lBitWidth) ? rSrcType.getElementType()
1613 : lSrcType.getElementType();
1614 unsigned numLanes = 0;
1617 if (isa<FloatType>(srcElemType) &&
1618 (bitWidth == 16 || bitWidth == 32)) {
1620 }
else if (isa<IntegerType>(srcElemType) &&
1621 (bitWidth == 8 || bitWidth == 16)) {
1623 }
else if (isa<IntegerType>(srcElemType) && (bitWidth == 32)) {
1629 if (targetInputType != lSrcType) {
1630 auto converted = convertValueToTargetTypeAIE2(rewriter, mulOp.getLoc(),
1631 lval, targetInputType);
1636 if (targetInputType != rSrcType) {
1637 auto converted = convertValueToTargetTypeAIE2(rewriter, mulOp.getLoc(),
1638 rval, targetInputType);
1647 auto mulElemOp = aievec::MulElemOp::create(rewriter, mulOp.getLoc(),
1648 accType, lval, rval);
1651 auto mulElemResultType = mulElemOp.getType();
1652 auto mulElemResultElWidth =
1653 mulElemResultType.getElementType().getIntOrFloatBitWidth();
1655 if (mulElemResultElWidth == resultElWidth) {
1656 rewriter.replaceOpWithNewOp<aievec::CastOp>(
1657 mulOp, resultType, mulElemOp.getResult(),
false);
1658 }
else if (mulElemResultElWidth > resultElWidth) {
1659 auto shiftParamOp = arith::ConstantOp::create(
1660 rewriter, mulOp.getLoc(), rewriter.getI32IntegerAttr(
shiftParam));
1661 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
1662 mulOp, resultType, mulElemOp.getResult(), shiftParamOp.getResult());
1676 using OpConversionPattern::OpConversionPattern;
1680 ConversionPatternRewriter &rewriter)
const override {
1682 dyn_cast<aievec::ConcatOp>(adaptor.getLhs().getDefiningOp());
1685 vector::BroadcastOp bcastOp =
nullptr;
1686 auto *concatDefOp = concatOp.getSources()[0].getDefiningOp();
1688 bcastOp = dyn_cast<vector::BroadcastOp>(concatDefOp);
1689 Value lhs = adaptor.getRhs();
1691 bcastOp = dyn_cast<vector::BroadcastOp>(adaptor.getRhs().getDefiningOp());
1694 lhs = concatOp.getSources()[0];
1697 dyn_cast<vector::ExtractOp>(bcastOp.getSource().getDefiningOp());
1701 auto rhs = extOp.getSource();
1702 auto concatVecType = cast<VectorType>(concatOp.getResult().getType());
1704 arith::ConstantOp::create(rewriter, concatOp.getLoc(), lhs.getType(),
1705 rewriter.getZeroAttr(lhs.getType()));
1707 aievec::ConcatOp::create(rewriter, concatOp.getLoc(), concatVecType,
1708 SmallVector<Value, 2>({lhs, zvec}))
1711 auto pos = extOp.getStaticPosition();
1712 int64_t zstart = pos[0];
1714 aievec::aie1::FMAOp::Properties fmaProps;
1715 if (failed(aievec::aie1::FMAOp::setPropertiesFromAttr(
1716 fmaProps, rewriter.getDictionaryAttr(fmaOpAttr),
1717 [&]() { return fmaOp.emitError(); })))
1719 rewriter.replaceOpWithNewOp<aievec::aie1::FMAOp>(
1720 fmaOp, TypeRange({fmaOp.getResult().getType()}),
1721 ValueRange({lhsX2, rhs, adaptor.getAcc()}), fmaProps);
1728 : OpConversionPattern<aievec::aie1::AddOp> {
1729 using OpConversionPattern::OpConversionPattern;
1733 ConversionPatternRewriter &rewriter)
const override {
1734 auto vecType = cast<VectorType>(addOp.getType());
1737 extractMACOperandsFromAddOperands(adaptor.getLhs(), adaptor.getRhs());
1740 auto [lhs, rhs, acc] = *res;
1742 SmallVector<int64_t, 4> concatVecShape(vecType.getShape().begin(),
1743 vecType.getShape().end());
1744 concatVecShape[vecType.getRank() - 1] *= 2;
1745 auto concatVecType =
1746 VectorType::get(concatVecShape, vecType.getElementType());
1750 aievec::ConcatOp::create(rewriter, addOp.getLoc(), concatVecType,
1751 SmallVector<Value, 2>(2, lhs))
1753 auto upsOp = aievec::UPSOp::create(rewriter, addOp.getLoc(), accType, acc);
1754 auto fmaOp = aievec::aie1::FMAOp::create(
1755 rewriter, addOp.getLoc(), accType, lhsX2, rhs, upsOp.getResult(),
1759 auto shiftParamOp = arith::ConstantOp::create(
1760 rewriter, addOp.getLoc(), rewriter.getI32IntegerAttr(0));
1761 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
1762 addOp, vecType, fmaOp.getResult(), shiftParamOp.getResult());
1771 : OpConversionPattern<vector::TransferReadOp> {
1772 using OpConversionPattern::OpConversionPattern;
1783 ConversionPatternRewriter &rewriter)
const override {
1785 if (readOp.getMask())
1786 return readOp.emitError() <<
"AIE doesn't support masked loads.";
1789 AffineMap map = readOp.getPermutationMap();
1790 if (!map.isMinorIdentity())
1794 if (map.isConstant())
1798 auto vType = readOp.getVectorType();
1808 int64_t vSize = vType.getNumElements() * vType.getElementTypeBitWidth();
1817 if ((vSize >
minVectorSize) && std::bitset<8>(multiplicity).count() != 1)
1820 auto updOp = xilinx::aievec::UPDOp::create(
1821 rewriter, readOp.getLoc(), vType, adaptor.getBase(),
1822 adaptor.getIndices(), 0, 0, TypedValue<VectorType>(
nullptr));
1824 updOp = xilinx::aievec::UPDOp::create(
1825 rewriter, readOp.getLoc(), vType, adaptor.getBase(),
1826 adaptor.getIndices(),
maxLoadSize, 1, updOp.getResult());
1828 rewriter.replaceOp(readOp, updOp.getResult());
1838template <
typename SrcOpTy,
typename DstOpTy>
1840 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
1845 ConversionPatternRewriter &rewriter)
const override {
1846 rewriter.replaceOpWithNewOp<DstOpTy>(
1847 srcOp, srcOp.getResult().getType(), adaptor.getLhs(), adaptor.getRhs(),
1855 using OpConversionPattern::OpConversionPattern;
1859 ConversionPatternRewriter &rewriter)
const override {
1860 auto resType = addOp.getType();
1861 if (!isa<VectorType>(resType))
1864 auto lhs = adaptor.getLhs();
1865 auto rhs = adaptor.getRhs();
1866 auto *lhsDefOp = lhs.getDefiningOp();
1867 auto *rhsDefOp = rhs.getDefiningOp();
1868 if ((isa_and_nonnull<arith::MulIOp>(lhsDefOp)) ||
1869 (isa_and_nonnull<arith::MulIOp>(rhsDefOp)))
1872 rewriter.replaceOpWithNewOp<aievec::aie1::AddOp>(
1873 addOp, resType, lhs, rhs,
1890 using OpConversionPattern::OpConversionPattern;
1893 ConversionPatternRewriter &rewriter)
const override {
1894 auto resTy = dyn_cast<VectorType>(mulOp.getType());
1898 auto newMulOp = aievec::aie1::MulOp::create(
1899 rewriter, mulOp.getLoc(), accTy, adaptor.getLhs(), adaptor.getRhs());
1900 auto shiftParamOp = arith::ConstantOp::create(
1901 rewriter, mulOp.getLoc(), rewriter.getI32IntegerAttr(0));
1902 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
1903 mulOp, resTy, newMulOp.getResult(), shiftParamOp.getResult());
1908template <
typename SrcOpTy,
typename DstOpTy>
1910 : OpConversionPattern<SrcOpTy> {
1911 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
1916 ConversionPatternRewriter &rewriter)
const override {
1917 VectorType resultType = dyn_cast<VectorType>(srcOp.getType());
1923 llvm::SmallSet<std::pair<unsigned, signed>, 16> laneSizeElWidthPairSet;
1924 laneSizeElWidthPairSet.insert({64, 8});
1925 laneSizeElWidthPairSet.insert({32, 16});
1926 laneSizeElWidthPairSet.insert({16, 32});
1927 laneSizeElWidthPairSet.insert({32, 32});
1929 auto lhs = adaptor.getLhs();
1930 auto rhs = adaptor.getRhs();
1931 auto lhsDefOp = lhs.getDefiningOp();
1932 auto rhsDefOp = rhs.getDefiningOp();
1937 bool lhsIsMul = lhsDefOp && (isa<arith::MulIOp>(lhsDefOp) ||
1938 isa<arith::MulFOp>(lhsDefOp));
1939 bool rhsIsMul = rhsDefOp && (isa<arith::MulIOp>(rhsDefOp) ||
1940 isa<arith::MulFOp>(rhsDefOp));
1941 bool lhsIsConst = isa_and_nonnull<arith::ConstantOp>(lhsDefOp);
1942 bool rhsIsConst = isa_and_nonnull<arith::ConstantOp>(rhsDefOp);
1947 if (!resultType.getElementType().isF32() &&
1948 ((lhsIsMul && !rhsIsConst) || (rhsIsMul && !lhsIsConst)))
1951 Type scalarType = resultType.getElementType();
1952 unsigned resultElWidth = scalarType.getIntOrFloatBitWidth();
1956 if (isa<IntegerType>(scalarType)) {
1957 if (!laneSizeElWidthPairSet.count(
1958 std::make_pair(laneSize, resultElWidth)))
1964 if (!lhsDefOp && !rhsDefOp) {
1965 if (laneSize * resultElWidth == 512) {
1966 rewriter.replaceOpWithNewOp<DstOpTy>(srcOp, srcOp.getType(), lhs,
1970 return genAddElemAIE2<SrcOpTy, DstOpTy>(rewriter, lhs, rhs, resultType,
1975 if (resultElWidth == 32) {
1976 auto lhsExt = getSourceOfWideningOp(lhs).value_or(
nullptr);
1977 auto rhsExt = getSourceOfWideningOp(rhs).value_or(
nullptr);
1979 if (!lhsExt && !rhsExt) {
1980 if (laneSize * resultElWidth == 512) {
1981 rewriter.replaceOpWithNewOp<DstOpTy>(srcOp, srcOp.getType(), lhs,
1985 return genAddElemAIE2<SrcOpTy, DstOpTy>(rewriter, lhs, rhs,
1989 if (lhsExt && rhsExt) {
1992 VectorType lSrcType = cast<VectorType>(lval.getType());
1996 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, lval);
1998 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, rval);
1999 auto elemOp = DstOpTy::create(
2000 rewriter, srcOp.getLoc(), lUpsOp->getResult(0).getType(),
2001 lUpsOp->getResult(0), rUpsOp->getResult(0));
2002 rewriter.replaceOpWithNewOp<aievec::CastOp>(
2003 srcOp, srcOp.getType(), elemOp.getResult(),
false);
2007 if (!lhsExt || !rhsExt) {
2008 auto lval = lhsExt ? lhsExt : lhs;
2009 auto rval = rhsExt ? rhsExt : rhs;
2010 auto extVal = lhsExt ? lval : rval;
2011 VectorType vType = cast<VectorType>(extVal.getType());
2012 unsigned bitWidth = vType.getElementType().getIntOrFloatBitWidth();
2014 if (bitWidth != 8 && bitWidth != 16) {
2015 return genAddElemAIE2<SrcOpTy, DstOpTy>(rewriter, lhs, rhs,
2019 if (bitWidth * laneSize != 256) {
2020 return genAddElemAIE2<SrcOpTy, DstOpTy>(rewriter, lhs, rhs,
2024 Type accType =
nullptr;
2026 if (bitWidth == 8) {
2028 Value valToUps = lhsExt ? lval : rval;
2029 Value valToCast = lhsExt ? rval : lval;
2030 auto upsOp = aievec::UPSOp::create(rewriter, srcOp.getLoc(),
2033 aievec::CastOp::create(rewriter, srcOp.getLoc(), resultType,
2036 lhsExt ? upsOp->getResult(0) : castOp->getResult(0);
2038 lhsExt ? castOp->getResult(0) : upsOp->getResult(0);
2039 auto elemOp = DstOpTy::create(rewriter, srcOp.getLoc(),
2040 upsOp->getResult(0).getType(),
2041 lhsToElemOp, rhsToElemOp);
2042 rewriter.replaceOpWithNewOp<aievec::CastOp>(
2043 srcOp, srcOp.getType(), elemOp.getResult(),
false);
2047 if (bitWidth == 16) {
2050 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, lval);
2052 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, rval);
2054 auto elemOp = DstOpTy::create(
2055 rewriter, srcOp.getLoc(), lUpsOp->getResult(0).getType(),
2056 lUpsOp->getResult(0), rUpsOp->getResult(0));
2058 auto shiftParamOp = arith::ConstantOp::create(
2059 rewriter, srcOp.getLoc(), rewriter.getI32IntegerAttr(0));
2060 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
2061 srcOp, srcOp.getType(), elemOp.getResult(),
2062 shiftParamOp.getResult());
2067 rewriter.replaceOpWithNewOp<DstOpTy>(srcOp, srcOp.getType(), lhs, rhs);
2074 if (laneSize == 64 && scalarType.isF32())
2075 return genAddElemAIE2<SrcOpTy, DstOpTy>(rewriter, lhs, rhs, resultType,
2077 if (laneSize != 16 && laneSize != 32)
2081 if (laneSize == 32 && resultElWidth == 32) {
2084 splitWideBinaryVectorOp<SrcOpTy>(
2085 srcOp, lhs, rhs, halfType, resultType, rewriter,
2086 [](Value lhsHalf, Value rhsHalf, Location loc,
2087 ConversionPatternRewriter &rewriter) -> Value {
2088 VectorType halfVecType = cast<VectorType>(lhsHalf.getType());
2090 auto lCastOp = aievec::CastOp::create(rewriter, loc, halfVecType,
2092 auto rCastOp = aievec::CastOp::create(rewriter, loc, halfVecType,
2094 auto elemOp = DstOpTy::create(
2095 rewriter, loc, lCastOp->getResult(0).getType(),
2096 lCastOp->getResult(0), rCastOp->getResult(0));
2097 auto resCastOp = aievec::CastOp::create(
2098 rewriter, loc, halfVecType, elemOp.getResult(),
2100 return resCastOp.getResult();
2106 if (laneSize == 32 && resultElWidth == 16) {
2109 splitWideBinaryVectorOp<SrcOpTy>(
2110 srcOp, lhs, rhs, halfType, resultType, rewriter,
2111 [](Value lhsHalf, Value rhsHalf, Location loc,
2112 ConversionPatternRewriter &rewriter) -> Value {
2113 VectorType halfVecType = cast<VectorType>(lhsHalf.getType());
2116 aievec::UPSOp::create(rewriter, loc, accType, lhsHalf);
2118 aievec::UPSOp::create(rewriter, loc, accType, rhsHalf);
2120 DstOpTy::create(rewriter, loc, lUpsOp->getResult(0).getType(),
2121 lUpsOp->getResult(0), rUpsOp->getResult(0));
2122 auto shiftParamOp = arith::ConstantOp::create(
2123 rewriter, loc, rewriter.getI32IntegerAttr(0));
2124 auto srsOp = aievec::SRSOp::create(rewriter, loc, halfVecType,
2126 shiftParamOp.getResult());
2127 return srsOp.getResult();
2134 if (resultElWidth == 32) {
2135 if (!lhsDefOp && !rhsDefOp) {
2136 return genAddElemAIE2<SrcOpTy, DstOpTy>(rewriter, lhs, rhs,
2140 auto lhsExt = getSourceOfWideningOp(lhs).value_or(
nullptr);
2141 auto rhsExt = getSourceOfWideningOp(rhs).value_or(
nullptr);
2143 if (!lhsExt && !rhsExt) {
2144 return genAddElemAIE2<SrcOpTy, DstOpTy>(rewriter, lhs, rhs,
2149 if (lhsExt && rhsExt) {
2152 VectorType vType = cast<VectorType>(lval.getType());
2156 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, lval);
2158 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, rval);
2159 auto elemOp = DstOpTy::create(
2160 rewriter, srcOp.getLoc(), lUpsOp->getResult(0).getType(),
2161 lUpsOp->getResult(0), rUpsOp->getResult(0));
2162 rewriter.replaceOpWithNewOp<aievec::CastOp>(srcOp, srcOp.getType(),
2163 elemOp.getResult());
2168 if (!lhsExt || !rhsExt) {
2169 auto lval = lhsExt ? lhsExt : lhs;
2170 auto rval = rhsExt ? rhsExt : rhs;
2171 auto extVal = lhsExt ? lval : rval;
2172 VectorType vType = cast<VectorType>(extVal.getType());
2175 aievec::UPSOp upsOp;
2176 aievec::CastOp castOp;
2179 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, lval);
2180 castOp = aievec::CastOp::create(rewriter, srcOp.getLoc(),
2185 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, rval);
2186 castOp = aievec::CastOp::create(rewriter, srcOp.getLoc(),
2191 auto elemOp = DstOpTy::create(
2192 rewriter, srcOp.getLoc(), upsOp->getResult(0).getType(),
2193 upsOp->getResult(0), castOp->getResult(0));
2195 rewriter.replaceOpWithNewOp<aievec::CastOp>(
2196 srcOp, srcOp.getType(), elemOp.getResult(),
false);
2205 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, lhs);
2207 aievec::UPSOp::create(rewriter, srcOp.getLoc(), accType, rhs);
2208 auto elemOp = DstOpTy::create(rewriter, srcOp.getLoc(),
2209 lUpsOp->getResult(0).getType(),
2210 lUpsOp->getResult(0), rUpsOp->getResult(0));
2211 auto shiftParamOp = arith::ConstantOp::create(
2212 rewriter, srcOp.getLoc(), rewriter.getI32IntegerAttr(0));
2213 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
2214 srcOp, srcOp.getType(), elemOp.getResult(), shiftParamOp.getResult());
2236template <
typename SrcOpTy,
typename DstOpTy>
2238 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
2243 ConversionPatternRewriter &rewriter)
const override {
2244 VectorType resultType = dyn_cast<VectorType>(srcOp.getType());
2249 llvm::SmallSet<unsigned, 16> elWidthSet;
2250 elWidthSet.insert(8);
2251 elWidthSet.insert(16);
2252 elWidthSet.insert(32);
2254 Type scalarType = resultType.getElementType();
2255 unsigned resultElWidth = scalarType.getIntOrFloatBitWidth();
2258 unsigned totalBits = laneSize * resultElWidth;
2259 if (!elWidthSet.count(resultElWidth) ||
2260 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16)))
2263 if (totalBits == 256 && resultElWidth == 16) {
2265 Location loc = srcOp.getLoc();
2268 padV16ToV32WithZeros(rewriter, loc, adaptor.getLhs(), scalarType);
2270 padV16ToV32WithZeros(rewriter, loc, adaptor.getRhs(), scalarType);
2271 auto wideOp = DstOpTy::create(rewriter, loc, wideType, lhsPad, rhsPad);
2272 rewriter.replaceOpWithNewOp<aievec::ExtOp>(srcOp, resultType,
2273 wideOp.getResult(), 0);
2277 rewriter.replaceOpWithNewOp<DstOpTy>(srcOp, srcOp.getType(),
2278 adaptor.getLhs(), adaptor.getRhs());
2291template <
typename SrcOpTy, arith::CmpIPredicate Pred>
2293 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
2298 ConversionPatternRewriter &rewriter)
const override {
2299 if (!isa<VectorType>(srcOp.getType()))
2301 Value lhs = adaptor.getLhs();
2302 Value rhs = adaptor.getRhs();
2304 arith::CmpIOp::create(rewriter, srcOp.getLoc(), Pred, lhs, rhs);
2305 rewriter.replaceOpWithNewOp<arith::SelectOp>(srcOp, cmpOp, lhs, rhs);
2317template <
typename SrcOpTy,
typename DstOpTy>
2319 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
2324 ConversionPatternRewriter &rewriter)
const override {
2326 Type resultType = srcOp.getType();
2327 if (isa<VectorType>(resultType))
2330 auto intType = dyn_cast<IntegerType>(resultType);
2334 unsigned elWidth = intType.getWidth();
2335 if (elWidth != 8 && elWidth != 16 && elWidth != 32)
2338 unsigned numLanes = 512 / elWidth;
2340 Location loc = srcOp.getLoc();
2343 auto lhsBcast = aievec::BroadcastScalarOp::create(rewriter, loc, vecType,
2345 auto rhsBcast = aievec::BroadcastScalarOp::create(rewriter, loc, vecType,
2349 auto vecOp = DstOpTy::create(rewriter, loc, vecType, lhsBcast.getResult(),
2350 rhsBcast.getResult());
2354 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
2355 rewriter.replaceOpWithNewOp<aievec::ExtElemOp>(
2356 srcOp, intType, vecOp.getResult(), zeroIdx.getResult());
2373template <
typename SrcOpTy,
typename CmpTy>
2375 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
2380 ConversionPatternRewriter &rewriter)
const override {
2381 VectorType lhsType = dyn_cast<VectorType>(srcOp.getLhs().getType());
2385 llvm::SmallSet<unsigned, 16> elWidthSet;
2386 elWidthSet.insert(8);
2387 elWidthSet.insert(16);
2388 elWidthSet.insert(32);
2390 Type scalarType = lhsType.getElementType();
2391 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
2394 unsigned totalBits = laneSize * elWidth;
2395 if (!elWidthSet.count(elWidth) ||
2396 (totalBits != 512 && (totalBits != 256 || elWidth != 16)))
2399 Location loc = srcOp.getLoc();
2400 Value lhs = srcOp.getLhs();
2401 Value rhs = srcOp.getRhs();
2402 unsigned effectiveLaneSize = laneSize;
2404 if (totalBits == 256 && elWidth == 16) {
2405 lhs = padV16ToV32WithZeros(rewriter, loc, lhs, scalarType);
2406 rhs = padV16ToV32WithZeros(rewriter, loc, rhs, scalarType);
2407 effectiveLaneSize = 32;
2411 Type type = mlir::IntegerType::get(srcOp.getContext(),
2412 effectiveLaneSize <= 32 ? 32 : 64,
2413 mlir::IntegerType::Unsigned);
2415 CmpTy pred = srcOp.getPredicate();
2417 arith::CmpIPredicate ipred = convertToIntegerPredicate(pred);
2419 aievec::CmpOp aieCmpOp =
2420 createCmpOpAIE2(rewriter, ipred, loc, type, lhs, rhs);
2425 VectorType resultType = cast<VectorType>(srcOp.getResult().getType());
2428 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
2429 srcOp, resultType, aieCmpOp.getResult());
2441 using OpConversionPattern::OpConversionPattern;
2445 ConversionPatternRewriter &rewriter)
const override {
2446 auto resultType = dyn_cast<VectorType>(srcOp.getType());
2450 llvm::SmallSet<unsigned, 16> elWidthSet;
2451 elWidthSet.insert(8);
2452 elWidthSet.insert(16);
2453 elWidthSet.insert(32);
2455 Type scalarType = resultType.getElementType();
2456 unsigned resultElWidth = scalarType.getIntOrFloatBitWidth();
2459 unsigned totalBits = laneSize * resultElWidth;
2460 if (!elWidthSet.count(resultElWidth) ||
2461 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16)))
2464 if (totalBits == 256 && resultElWidth == 16) {
2466 Location loc = srcOp.getLoc();
2473 Value falsePad = padV16ToV32WithZeros(rewriter, loc,
2474 srcOp.getFalseValue(), scalarType);
2476 padV16ToV32WithZeros(rewriter, loc, srcOp.getTrueValue(), scalarType);
2480 Type type = mlir::IntegerType::get(srcOp.getContext(), 32,
2481 mlir::IntegerType::Unsigned);
2482 auto convertOp = UnrealizedConversionCastOp::create(
2483 rewriter, loc, type, adaptor.getCondition());
2485 auto wideSelOp = aievec::SelOp::create(rewriter, loc, wideType, falsePad,
2486 truePad, convertOp.getResult(0));
2488 rewriter.replaceOpWithNewOp<aievec::ExtOp>(srcOp, resultType,
2489 wideSelOp.getResult(), 0);
2494 mlir::IntegerType::get(srcOp.getContext(), laneSize <= 32 ? 32 : 64,
2495 mlir::IntegerType::Unsigned);
2497 auto convertOp = UnrealizedConversionCastOp::create(
2498 rewriter, srcOp.getLoc(), type, adaptor.getCondition());
2504 rewriter.replaceOpWithNewOp<aievec::SelOp>(
2505 srcOp, srcOp.getResult().getType(), srcOp.getFalseValue(),
2506 srcOp.getTrueValue(), convertOp.getResult(0));
2513 using OpConversionPattern::OpConversionPattern;
2517 ConversionPatternRewriter &rewriter)
const override {
2518 if (
auto kind = srcOp.getKind(); kind != vector::CombiningKind::MINSI &&
2519 kind != vector::CombiningKind::MINUI &&
2520 kind != vector::CombiningKind::MINIMUMF &&
2521 kind != vector::CombiningKind::MINNUMF)
2524 auto vType = cast<VectorType>(srcOp.getVector().getType());
2525 Type scalarType = vType.getElementType();
2526 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
2528 unsigned vectorSize = laneSize * elWidth;
2531 if (vectorSize != 512 && (vectorSize != 256 || !scalarType.isBF16()))
2534 Location loc = srcOp.getLoc();
2535 Value inputVec = srcOp.getVector();
2538 if (vectorSize == 256) {
2539 std::tie(inputVec, laneSize) = padV16ToV32WithInfinity(
2540 rewriter, loc, srcOp.getVector(), scalarType,
false);
2543 int shiftIndex = laneSize / 2;
2544 auto reduceResultOp = generateAIEVecOpsForReductionOp<aievec::MinOp>(
2545 rewriter, srcOp, shiftIndex, inputVec);
2547 if (srcOp.getAcc()) {
2548 Value reduceResult = reduceResultOp.getResult();
2549 Value acc = srcOp.getAcc();
2552 if (acc.getType().isBF16()) {
2554 auto minOpBuilder = [&](Value lhs, Value rhs) -> Value {
2555 auto cmpOp = arith::CmpFOp::create(
2556 rewriter, srcOp.getLoc(), arith::CmpFPredicate::OLT, lhs, rhs);
2557 return arith::SelectOp::create(rewriter, srcOp.getLoc(), cmpOp, lhs,
2563 performBF16BinaryOpInF32(reduceResult, acc, srcOp, srcOp.getLoc(),
2564 rewriter, minOpBuilder);
2568 arith::CmpFOp::create(rewriter, srcOp.getLoc(),
2569 arith::CmpFPredicate::OLT, reduceResult, acc);
2570 rewriter.replaceOpWithNewOp<arith::SelectOp>(srcOp, cmpOp, reduceResult,
2574 rewriter.replaceOp(srcOp, reduceResultOp);
2581 using OpConversionPattern::OpConversionPattern;
2585 ConversionPatternRewriter &rewriter)
const override {
2586 if (
auto kind = srcOp.getKind(); kind != vector::CombiningKind::MAXSI &&
2587 kind != vector::CombiningKind::MAXUI &&
2588 kind != vector::CombiningKind::MAXIMUMF &&
2589 kind != vector::CombiningKind::MAXNUMF)
2592 auto vType = cast<VectorType>(srcOp.getVector().getType());
2593 Type scalarType = vType.getElementType();
2594 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
2596 unsigned vectorSize = laneSize * elWidth;
2600 if (vectorSize != 512 && (vectorSize != 256 || !scalarType.isBF16()))
2603 Location loc = srcOp.getLoc();
2604 Value inputVec = srcOp.getVector();
2607 if (vectorSize == 256) {
2608 std::tie(inputVec, laneSize) = padV16ToV32WithInfinity(
2609 rewriter, loc, srcOp.getVector(), scalarType,
true);
2612 int shiftIndex = laneSize / 2;
2613 auto reduceResultOp = generateAIEVecOpsForReductionOp<aievec::MaxOp>(
2614 rewriter, srcOp, shiftIndex, inputVec);
2616 if (srcOp.getAcc()) {
2617 Value reduceResult = reduceResultOp.getResult();
2618 Value acc = srcOp.getAcc();
2621 if (acc.getType().isBF16()) {
2623 auto maxOpBuilder = [&](Value lhs, Value rhs) -> Value {
2624 auto cmpOp = arith::CmpFOp::create(
2625 rewriter, srcOp.getLoc(), arith::CmpFPredicate::OGT, lhs, rhs);
2626 return arith::SelectOp::create(rewriter, srcOp.getLoc(), cmpOp, lhs,
2632 performBF16BinaryOpInF32(reduceResult, acc, srcOp, srcOp.getLoc(),
2633 rewriter, maxOpBuilder);
2637 arith::CmpFOp::create(rewriter, srcOp.getLoc(),
2638 arith::CmpFPredicate::OGT, reduceResult, acc);
2639 rewriter.replaceOpWithNewOp<arith::SelectOp>(srcOp, cmpOp, reduceResult,
2643 rewriter.replaceOp(srcOp, reduceResultOp);
2650 using OpConversionPattern::OpConversionPattern;
2654 ConversionPatternRewriter &rewriter)
const override {
2655 if (
auto kind = srcOp.getKind(); kind != vector::CombiningKind::ADD)
2658 auto vType = cast<VectorType>(srcOp.getVector().getType());
2659 Type scalarType = vType.getElementType();
2660 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
2662 llvm::SmallSet<std::pair<unsigned, signed>, 16> laneSizeElWidthPairSet;
2663 laneSizeElWidthPairSet.insert({64, 8});
2664 laneSizeElWidthPairSet.insert({32, 16});
2665 laneSizeElWidthPairSet.insert({32, 32});
2666 laneSizeElWidthPairSet.insert({16, 32});
2668 if (!isa<IntegerType>(scalarType) ||
2669 !laneSizeElWidthPairSet.count(std::make_pair(laneSize, elWidth)))
2672 int shiftIndex = laneSize / 2;
2673 if (laneSize == 32 && elWidth == 32) {
2674 Location loc = srcOp.getLoc();
2678 aievec::ExtOp::create(rewriter, loc, vecType, srcOp.getVector(), 0);
2680 aievec::ExtOp::create(rewriter, loc, vecType, srcOp.getVector(), 1);
2682 aievec::AddElemOp::create(rewriter, loc, lExtOp.getResult().getType(),
2683 lExtOp.getResult(), rExtOp.getResult());
2685 auto reduceResultOp = generateAIEVecOpsForReductionOp<aievec::AddElemOp>(
2686 rewriter, srcOp, shiftIndex, addElemOp.getResult());
2688 rewriter.replaceOpWithNewOp<arith::AddIOp>(
2689 srcOp, reduceResultOp.getResult(), srcOp.getAcc());
2691 rewriter.replaceOp(srcOp, reduceResultOp);
2693 auto reduceResultOp = generateAIEVecOpsForReductionOp<aievec::AddElemOp>(
2694 rewriter, srcOp, shiftIndex, srcOp.getVector());
2696 rewriter.replaceOpWithNewOp<arith::AddIOp>(
2697 srcOp, reduceResultOp.getResult(), srcOp.getAcc());
2699 rewriter.replaceOp(srcOp, reduceResultOp);
2707 : OpConversionPattern<vector::ReductionOp> {
2708 using OpConversionPattern::OpConversionPattern;
2712 ConversionPatternRewriter &rewriter)
const override {
2713 if (
auto kind = srcOp.getKind(); kind != vector::CombiningKind::ADD)
2716 auto vType = cast<VectorType>(srcOp.getVector().getType());
2717 Type scalarType = vType.getElementType();
2718 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
2721 if (!isa<FloatType>(scalarType) || laneSize != 16 || elWidth != 32)
2724 int shiftIndex = laneSize / 2;
2725 assert(shiftIndex > 0 && (shiftIndex & (shiftIndex - 1)) == 0 &&
2726 "shiftIndex must be power of 2");
2728 Location loc = srcOp.getLoc();
2729 Value curValue = srcOp.getVector();
2730 aievec::CastOp curOp =
nullptr;
2732 for (
int id = shiftIndex;
id > 0;
id /= 2) {
2733 auto constOp = arith::ConstantOp::create(
2734 rewriter, loc, rewriter.getI32IntegerAttr(
id * elWidth / 8));
2736 auto shiftBytesOp = aievec::ShiftOp::create(
2737 rewriter, loc, vType, curValue, curValue, constOp.getResult());
2739 auto lCastOp = aievec::CastOp::create(rewriter, loc, vType, curValue,
2742 aievec::CastOp::create(rewriter, loc, vType, shiftBytesOp.getResult(),
2744 auto elemOp = aievec::AddElemOp::create(
2745 rewriter, loc, lCastOp.getResult().getType(), lCastOp.getResult(),
2746 rCastOp.getResult());
2747 curOp = aievec::CastOp::create(rewriter, loc, vType, elemOp.getResult(),
2749 curValue = curOp.getResult();
2753 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
2754 auto reduceResultOp = aievec::ExtElemOp::create(
2755 rewriter, srcOp.getLoc(), scalarType, curOp, zeroConstOp.getResult());
2758 rewriter.replaceOpWithNewOp<arith::AddFOp>(
2759 srcOp, reduceResultOp.getResult(), srcOp.getAcc());
2761 rewriter.replaceOp(srcOp, reduceResultOp);
2769 : OpConversionPattern<vector::ReductionOp> {
2770 using OpConversionPattern::OpConversionPattern;
2774 ConversionPatternRewriter &rewriter)
const override {
2776 if (
auto kind = srcOp.getKind(); kind != vector::CombiningKind::ADD) {
2780 auto vType = cast<VectorType>(srcOp.getVector().getType());
2781 Type scalarType = vType.getElementType();
2782 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
2786 if (!isa<FloatType>(scalarType) || (laneSize != 16 && laneSize != 32) ||
2791 Location loc = srcOp.getLoc();
2792 Value curValue = srcOp.getVector();
2793 VectorType currentVType = vType;
2796 if (laneSize == 32) {
2799 aievec::ExtOp::create(rewriter, loc, halfType, srcOp.getVector(), 0);
2801 aievec::ExtOp::create(rewriter, loc, halfType, srcOp.getVector(), 1);
2805 aievec::UPSOp::create(rewriter, loc, accType, lowerHalf.getResult());
2807 aievec::UPSOp::create(rewriter, loc, accType, upperHalf.getResult());
2808 auto addElemOp = aievec::AddElemOp::create(
2809 rewriter, loc, accType, lUpsOp.getResult(), rUpsOp.getResult());
2810 auto shiftParamOp = arith::ConstantOp::create(
2811 rewriter, loc, rewriter.getI32IntegerAttr(0));
2813 aievec::SRSOp::create(rewriter, loc, halfType, addElemOp.getResult(),
2814 shiftParamOp.getResult());
2815 curValue = srsOp.getResult();
2816 currentVType = halfType;
2823 cast<VectorType>(accType).getElementType().getIntOrFloatBitWidth();
2825 auto upsOp = aievec::UPSOp::create(rewriter, loc, accType, curValue);
2826 curValue = upsOp.getResult();
2828 aievec::AddElemOp curOp =
nullptr;
2830 for (
int id = shiftIndex;
id > 0;
id /= 2) {
2831 auto constOp = arith::ConstantOp::create(
2832 rewriter, loc, rewriter.getI32IntegerAttr(
id * accWidth / 8));
2833 auto shiftBytesOp = aievec::ShiftOp::create(
2834 rewriter, loc, accType, curValue, curValue, constOp,
true);
2835 curOp = aievec::AddElemOp::create(rewriter, loc, accType, curValue,
2836 shiftBytesOp.getResult());
2837 curValue = curOp.getResult();
2840 auto shiftParamOp = arith::ConstantOp::create(
2841 rewriter, srcOp.getLoc(), rewriter.getI32IntegerAttr(0));
2844 aievec::SRSOp::create(rewriter, loc, currentVType, curOp.getResult(),
2845 shiftParamOp.getResult());
2849 SmallVector<Value> concatSources = {srsOp.getResult(), srsOp.getResult()};
2851 aievec::ConcatOp::create(rewriter, loc, vecType, concatSources);
2854 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
2855 auto reduceResultOp =
2856 aievec::ExtElemOp::create(rewriter, srcOp.getLoc(), scalarType,
2857 concatOp, zeroConstOp.getResult());
2860 rewriter.replaceOpWithNewOp<arith::AddFOp>(
2861 srcOp, reduceResultOp.getResult(), srcOp.getAcc());
2863 rewriter.replaceOp(srcOp, reduceResultOp);
2870 : OpConversionPattern<vector::ReductionOp> {
2871 using OpConversionPattern::OpConversionPattern;
2875 ConversionPatternRewriter &rewriter)
const override {
2876 if (
auto kind = srcOp.getKind(); kind != vector::CombiningKind::ADD)
2879 auto vType = cast<VectorType>(srcOp.getVector().getType());
2880 Type scalarType = vType.getElementType();
2881 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
2885 if (!isa<FloatType>(scalarType) || (laneSize != 16 && laneSize != 32) ||
2889 Location loc = srcOp.getLoc();
2890 int shiftIndex = laneSize / 2;
2891 Value inputToReduce = srcOp.getVector();
2894 if (laneSize == 32) {
2899 aievec::ExtOp::create(rewriter, loc, halfType, srcOp.getVector(), 0);
2901 aievec::ExtOp::create(rewriter, loc, halfType, srcOp.getVector(), 1);
2906 aievec::UPSOp::create(rewriter, loc, accType, lowerHalf.getResult());
2908 aievec::UPSOp::create(rewriter, loc, accType, upperHalf.getResult());
2909 auto addElemOp = aievec::AddElemOp::create(
2910 rewriter, loc, accType, lUpsOp.getResult(), rUpsOp.getResult());
2911 auto shiftParamOp = arith::ConstantOp::create(
2912 rewriter, loc, rewriter.getI32IntegerAttr(0));
2914 aievec::SRSOp::create(rewriter, loc, halfType, addElemOp.getResult(),
2915 shiftParamOp.getResult());
2917 inputToReduce = srsOp.getResult();
2923 cast<VectorType>(inputToReduce.getType()),
true);
2925 cast<VectorType>(accType).getElementType().getIntOrFloatBitWidth();
2927 auto upsOp = aievec::UPSOp::create(rewriter, loc, accType, inputToReduce);
2928 Value curValue = upsOp.getResult();
2930 aievec::AddElemOp curOp =
nullptr;
2931 for (
int id = shiftIndex;
id > 0;
id /= 2) {
2932 auto constOp = arith::ConstantOp::create(
2933 rewriter, loc, rewriter.getI32IntegerAttr(
id * accWidth / 8));
2934 auto shiftBytesOp = aievec::ShiftOp::create(
2935 rewriter, loc, accType, curValue, curValue, constOp,
true);
2936 curOp = aievec::AddElemOp::create(rewriter, loc, accType, curValue,
2937 shiftBytesOp.getResult());
2938 curValue = curOp.getResult();
2945 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
2946 auto extractedF32 = aievec::ExtElemOp::create(
2947 rewriter, srcOp.getLoc(), rewriter.getF32Type(), curOp.getResult(),
2948 zeroConstOp.getResult());
2951 auto reduceResultBF16 = arith::TruncFOp::create(
2952 rewriter, srcOp.getLoc(), scalarType, extractedF32.getResult());
2955 rewriter.replaceOpWithNewOp<arith::AddFOp>(srcOp, reduceResultBF16,
2958 rewriter.replaceOp(srcOp, reduceResultBF16);
2966 : OpConversionPattern<vector::ExtractStridedSliceOp> {
2967 using OpConversionPattern::OpConversionPattern;
2971 ConversionPatternRewriter &rewriter)
const override {
2972 auto vType = extractOp.getSourceVectorType();
2973 if (vType.getRank() != 1)
2976 int64_t stride = cast<IntegerAttr>(adaptor.getStrides()[0]).getInt();
2982 return extractOp.emitError()
2983 <<
"AIEv1 doesn't support select ops on int8 types";
2987 int64_t size = cast<IntegerAttr>(adaptor.getSizes()[0]).getInt();
2988 if (vType.getNumElements() != 2 * size)
2991 int64_t offset = cast<IntegerAttr>(adaptor.getOffsets()[0]).getInt();
2992 aievec::aie1::SelectOp::Properties selectProps;
2993 if (failed(aievec::aie1::SelectOp::setPropertiesFromAttr(
2995 rewriter.getDictionaryAttr(
2996 buildAttributeListForRotationSelectOp(rewriter, vType, offset)),
2997 [&]() {
return extractOp.emitError(); })))
2999 auto selectOp = aievec::aie1::SelectOp::create(
3000 rewriter, extractOp.getLoc(), TypeRange({vType}),
3001 ValueRange({adaptor.getSource()}), selectProps);
3002 rewriter.replaceOpWithNewOp<aievec::aie1::ExtOp>(
3003 extractOp, extractOp.getType(), selectOp.getResult(),
3004 rewriter.getI8IntegerAttr(0));
3012 : OpConversionPattern<vector::ExtractStridedSliceOp> {
3013 using OpConversionPattern::OpConversionPattern;
3017 ConversionPatternRewriter &rewriter)
const override {
3018 auto vType = cast<VectorType>(adaptor.getSource().getType());
3019 if (vType.getRank() != 1)
3022 int64_t stride = cast<IntegerAttr>(adaptor.getStrides()[0]).getInt();
3028 int64_t size = cast<IntegerAttr>(adaptor.getSizes()[0]).getInt();
3029 if (vType.getNumElements() != 2 * size)
3032 auto shortVecType = cast<VectorType>(extractOp.getResult().getType());
3034 aievec::ExtOp::create(rewriter, extractOp.getLoc(), shortVecType,
3035 adaptor.getSource(), rewriter.getI8IntegerAttr(0))
3038 aievec::ExtOp::create(rewriter, extractOp.getLoc(), shortVecType,
3039 adaptor.getSource(), rewriter.getI8IntegerAttr(1))
3041 int64_t offset = cast<IntegerAttr>(adaptor.getOffsets()[0]).getInt();
3043 auto shiftBytesConstOp = arith::ConstantOp::create(
3044 rewriter, extractOp.getLoc(), rewriter.getIntegerType(32),
3045 rewriter.getI32IntegerAttr(shiftBytes));
3046 rewriter.replaceOpWithNewOp<aievec::ShiftOp>(
3047 extractOp, shortVecType, bottomHalf, topHalf, shiftBytesConstOp);
3056 using OpConversionPattern::OpConversionPattern;
3059 : OpConversionPattern(context) {}
3063 ConversionPatternRewriter &rewriter)
const override {
3065 if (updOp->hasOneUse() && isa<aievec::ExtOp>(*updOp->getUsers().begin()))
3068 auto vecType = cast<VectorType>(updOp.getType());
3069 SmallVector<int64_t, 4> vecShape(vecType.getShape().begin(),
3070 vecType.getShape().end());
3071 vecShape[vecType.getRank() - 1] *= 2;
3072 auto longVecType = VectorType::get(vecShape, vecType.getElementType());
3073 auto newUpdOp = aievec::UPDOp::create(
3074 rewriter, updOp.getLoc(), longVecType, adaptor.getSource(),
3075 adaptor.getIndices(), adaptor.getOffset(), adaptor.getIndex(),
3076 adaptor.getVector());
3077 rewriter.replaceOpWithNewOp<aievec::ExtOp>(
3078 updOp, vecType, newUpdOp.getResult(), rewriter.getI8IntegerAttr(0));
3087 using OpConversionPattern::OpConversionPattern;
3093 ConversionPatternRewriter &rewriter)
const override {
3095 if (extOp.getIndex() != 0)
3098 auto updOp = dyn_cast<aievec::UPDOp>(extOp.getSource().getDefiningOp());
3103 if (!updOp->hasOneUse())
3106 rewriter.replaceOpWithNewOp<aievec::UPDOp>(
3107 extOp, extOp.getType(), updOp.getSource(), updOp.getIndices(),
3108 updOp.getOffset(), updOp.getIndex(), updOp.getVector());
3117 using OpConversionPattern::OpConversionPattern;
3121 ConversionPatternRewriter &rewriter)
const override {
3122 if (matchExpOpForAIE2P(adaptor)) {
3123 auto srcType = cast<VectorType>(adaptor.getOperand().getType());
3124 rewriter.replaceOpWithNewOp<aievec::ExpOp>(expOp, srcType,
3125 adaptor.getOperand());
3130 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
3131 if (!srcType || srcType.isScalable() || srcType.getRank() != 1 ||
3132 !srcType.getElementType().isF32() ||
3133 (srcType.getNumElements() != 16 && srcType.getNumElements() != 32))
3136 Location loc = expOp.getLoc();
3137 auto bf16Type = VectorType::get(srcType.getShape(), rewriter.getBF16Type());
3139 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
3140 Value input = aievec::SRSOp::create(rewriter, loc, bf16Type,
3141 adaptor.getOperand(), shift);
3142 Value exp = aievec::ExpOp::create(rewriter, loc, bf16Type, input);
3143 rewriter.replaceOpWithNewOp<aievec::UPSOp>(expOp, srcType, exp,
3151template <
typename MathOpTy,
typename AIEVecOpTy>
3153 : OpConversionPattern<MathOpTy> {
3154 using OpConversionPattern<MathOpTy>::OpConversionPattern;
3159 ConversionPatternRewriter &rewriter)
const override {
3160 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
3161 if (!srcType || !isAIE2PAccFloatUnaryType(srcType))
3164 rewriter.replaceOpWithNewOp<AIEVecOpTy>(op, srcType, adaptor.getOperand());
3177 using OpConversionPattern::OpConversionPattern;
3181 ConversionPatternRewriter &rewriter)
const override {
3182 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
3183 if (!srcType || srcType.getRank() != 1 ||
3184 !isAIE2PAccFloatUnaryType(srcType))
3187 constexpr double a = 1.1283791670955126;
3188 constexpr double b = 0.10091092485409293;
3190 Location loc = erfOp.getLoc();
3191 auto bf16Type = VectorType::get(srcType.getShape(), rewriter.getBF16Type());
3192 auto f32Type = VectorType::get(srcType.getShape(), rewriter.getF32Type());
3194 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
3195 auto toBF16 = [&](Value v) -> Value {
3196 return aievec::SRSOp::create(rewriter, loc, bf16Type, v, shift);
3199 auto splatBF16 = [&](
double value) -> std::pair<Value, double> {
3200 auto attr = rewriter.getFloatAttr(rewriter.getBF16Type(), value);
3201 Value splat = arith::ConstantOp::create(
3202 rewriter, loc, DenseElementsAttr::get(bf16Type, attr));
3203 return {splat, attr.getValueAsDouble()};
3206 Value x = adaptor.getOperand();
3207 if (srcType.getElementType().isF32())
3210 auto [aHi, aHiValue] = splatBF16(a);
3211 Value aLo = splatBF16(a - aHiValue).first;
3212 Value bSplat = splatBF16(b).first;
3214 Value x2 = toBF16(aievec::MulElemOp::create(rewriter, loc, f32Type, x, x));
3215 Value x3 = toBF16(aievec::MulElemOp::create(rewriter, loc, f32Type, x2, x));
3216 Value arg = aievec::MulElemOp::create(rewriter, loc, f32Type, x, aHi);
3217 arg = aievec::FMAElemOp::create(rewriter, loc, f32Type, x, aLo, arg,
3219 arg = aievec::FMAElemOp::create(rewriter, loc, f32Type, x3, bSplat, arg,
3221 Value result = aievec::TanhOp::create(rewriter, loc, f32Type, arg);
3222 if (srcType.getElementType().isBF16())
3223 result = toBF16(result);
3225 rewriter.replaceOp(erfOp, result);
3232template <
typename OpTy>
3234 using OpConversionPattern<OpTy>::OpConversionPattern;
3239 ConversionPatternRewriter &rewriter)
const override {
3240 Type type = adaptor.getOperand().getType();
3241 if (!type.isBF16() && !type.isF32())
3244 Location loc = op.getLoc();
3245 auto vecType = VectorType::get({16}, type);
3246 Value splat = aievec::BroadcastScalarOp::create(rewriter, loc, vecType,
3247 adaptor.getOperand());
3248 Value result = OpTy::create(rewriter, loc, splat);
3249 rewriter.replaceOpWithNewOp<vector::ExtractOp>(op, result, 0);
3256template <
typename OpTy>
3258 using OpConversionPattern<OpTy>::OpConversionPattern;
3263 ConversionPatternRewriter &rewriter)
const override {
3264 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
3265 if (!srcType || srcType.isScalable() || srcType.getRank() != 1 ||
3266 srcType.getNumElements() != 1)
3269 Location loc = op.getLoc();
3271 vector::ExtractOp::create(rewriter, loc, adaptor.getOperand(), 0);
3272 Value result = OpTy::create(rewriter, loc, scalar);
3273 Value poison = ub::PoisonOp::create(rewriter, loc, srcType);
3274 rewriter.replaceOpWithNewOp<vector::InsertOp>(op, result, poison, 0);
3280 using OpConversionPattern::OpConversionPattern;
3284 ConversionPatternRewriter &rewriter)
const override {
3286 if (!matchExpOpForAIE2LUT(adaptor))
3289 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
3291 Location loc = expOp.getLoc();
3292 StringRef funcName =
"getExpBf16";
3294 VectorType v16bf16Ty = mlir::VectorType::get({16}, rewriter.getBF16Type());
3295 VectorType v8i64Ty = mlir::VectorType::get({8}, rewriter.getI64Type());
3296 func::FuncOp fnOp = getOrInsertFuncDecl(
3297 rewriter, expOp->getParentWithTrait<OpTrait::SymbolTable>(), funcName,
3298 TypeRange{v16bf16Ty}, TypeRange{v8i64Ty});
3301 if (laneSize == 32) {
3302 splitWideUnaryVectorOp<math::ExpOp>(
3303 expOp, adaptor.getOperand(), v16bf16Ty, srcType, rewriter,
3304 [&fnOp](Value halfInput, Location loc,
3305 ConversionPatternRewriter &rewriter) -> Value {
3306 VectorType v16bf16Ty =
3307 mlir::VectorType::get({16}, rewriter.getBF16Type());
3308 auto callOp = func::CallOp::create(rewriter, loc, fnOp,
3309 SmallVector<Value>{halfInput});
3311 auto resCastOp = vector::BitCastOp::create(rewriter, loc, accType,
3312 callOp.getResults());
3313 auto shiftParamOp = arith::ConstantOp::create(
3314 rewriter, loc, rewriter.getI32IntegerAttr(0));
3315 auto srsOp = aievec::SRSOp::create(rewriter, loc, v16bf16Ty,
3316 resCastOp.getResult(),
3317 shiftParamOp.getResult());
3318 return srsOp.getResult();
3324 SmallVector<Value> expOperands = {adaptor.getOperand()};
3327 auto callOp = func::CallOp::create(rewriter, loc, fnOp, expOperands);
3328 auto resCastOp = vector::BitCastOp::create(rewriter, loc, accTypeNative,
3329 callOp.getResults());
3331 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
3332 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
3333 expOp, srcType, resCastOp.getResult(), shiftParamOp.getResult());
3340 using OpConversionPattern::OpConversionPattern;
3344 ConversionPatternRewriter &rewriter)
const override {
3345 if (!matchExpOpForAIE2LUT(adaptor))
3347 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
3348 StringRef includeName =
"lut_based_ops.h";
3349 auto moduleOp = expOp->getParentOfType<mlir::ModuleOp>();
3350 rewriter.setInsertionPointToStart(
3351 &moduleOp.getRegion().getBlocks().front());
3352 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
3354 rewriter.setInsertionPoint(expOp);
3356 auto v16bf16OpaqueTy =
3357 emitc::OpaqueType::get(rewriter.getContext(),
"v16bfloat16");
3358 auto opaquedOperand =
3359 UnrealizedConversionCastOp::create(
3360 rewriter, expOp.getLoc(), v16bf16OpaqueTy, adaptor.getOperand())
3362 SmallVector<Value> expOperands = {opaquedOperand};
3365 Type v16accf32OpaqueTy =
3366 emitc::OpaqueType::get(rewriter.getContext(),
"v16accfloat");
3367 auto callOp = emitc::CallOpaqueOp::create(
3368 rewriter, expOp.getLoc(), TypeRange{v16accf32OpaqueTy},
"getExpBf16",
3369 nullptr,
nullptr, expOperands);
3370 auto resCastOp = UnrealizedConversionCastOp::create(
3371 rewriter, expOp.getLoc(), accTypeNative, callOp.getResults());
3372 auto shiftParamOp = arith::ConstantOp::create(
3373 rewriter, expOp.getLoc(), rewriter.getI32IntegerAttr(0));
3374 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
3375 expOp, srcType, resCastOp.getResult(0), shiftParamOp.getResult());
3394 using OpConversionPattern::OpConversionPattern;
3398 ConversionPatternRewriter &rewriter)
const override {
3399 Type srcType = adaptor.getLhs().getType();
3402 auto *defOp = divOp.getLhs().getDefiningOp();
3406 auto constOp = dyn_cast<arith::ConstantOp>(defOp);
3411 if (
auto fType = dyn_cast<FloatType>(srcType)) {
3412 if (fType.getWidth() != 32)
3415 auto floatAttr = dyn_cast<FloatAttr>(constOp.getValue());
3416 if (!floatAttr || !floatAttr.getValue().isExactlyValue(1.0))
3419 rewriter.replaceOpWithNewOp<aievec::InvOp>(divOp, srcType,
3425 if (
auto vecType = dyn_cast<VectorType>(srcType)) {
3426 auto elemType = vecType.getElementType();
3427 if (!elemType.isF32())
3432 if (laneSize != 16 && laneSize != 32)
3436 auto denseAttr = dyn_cast<DenseFPElementsAttr>(constOp.getValue());
3437 if (!denseAttr || !denseAttr.isSplat())
3440 if (!denseAttr.getSplatValue<APFloat>().isExactlyValue(1.0))
3443 rewriter.replaceOpWithNewOp<aievec::InvOp>(divOp, vecType,
3454 using OpConversionPattern::OpConversionPattern;
3458 ConversionPatternRewriter &rewriter)
const override {
3459 auto srcType = dyn_cast<VectorType>(tanhOp.getOperand().getType());
3463 Type scalarType = srcType.getElementType();
3464 if (!isa<FloatType>(scalarType))
3468 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
3469 if (elWidth != 16 || laneSize != 16)
3472 StringRef includeName =
"lut_based_ops.h";
3473 auto moduleOp = tanhOp->getParentOfType<mlir::ModuleOp>();
3474 rewriter.setInsertionPointToStart(
3475 &moduleOp.getRegion().getBlocks().front());
3476 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
3478 rewriter.setInsertionPoint(tanhOp);
3479 Type v16bf16OpaqueTy =
3480 emitc::OpaqueType::get(rewriter.getContext(),
"v16bfloat16");
3481 auto opaquedOperand =
3482 UnrealizedConversionCastOp::create(
3483 rewriter, tanhOp.getLoc(), v16bf16OpaqueTy, adaptor.getOperand())
3485 SmallVector<Value> tanhOperands = {opaquedOperand};
3486 auto callOp = emitc::CallOpaqueOp::create(rewriter, tanhOp.getLoc(),
3487 v16bf16OpaqueTy,
"getTanhBf16",
3488 nullptr,
nullptr, tanhOperands);
3489 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
3490 tanhOp, TypeRange{tanhOp.getResult().getType()}, callOp.getResults());
3499 using OpConversionPattern::OpConversionPattern;
3503 ConversionPatternRewriter &rewriter)
const override {
3504 auto srcType = dyn_cast<VectorType>(sqrtOp.getOperand().getType());
3508 Type scalarType = srcType.getElementType();
3509 if (!isa<FloatType>(scalarType))
3513 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
3514 if (elWidth != 16 || (laneSize != 16 && laneSize != 32))
3517 StringRef includeName =
"vec_math.h";
3518 auto moduleOp = sqrtOp->getParentOfType<mlir::ModuleOp>();
3519 rewriter.setInsertionPointToStart(
3520 &moduleOp.getRegion().getBlocks().front());
3521 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
3523 rewriter.setInsertionPoint(sqrtOp);
3524 Type vLNbf16OpaqueTy;
3527 emitc::OpaqueType::get(rewriter.getContext(),
"v16bfloat16");
3530 emitc::OpaqueType::get(rewriter.getContext(),
"v32bfloat16");
3531 auto opaquedOperand =
3532 UnrealizedConversionCastOp::create(
3533 rewriter, sqrtOp.getLoc(), vLNbf16OpaqueTy, adaptor.getOperand())
3535 SmallVector<Value> sqrtOperands = {opaquedOperand};
3536 auto callOp = emitc::CallOpaqueOp::create(
3537 rewriter, sqrtOp.getLoc(), TypeRange{vLNbf16OpaqueTy},
"getSqrtBf16",
3538 nullptr,
nullptr, sqrtOperands);
3539 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
3540 sqrtOp, TypeRange{sqrtOp.getResult().getType()}, callOp.getResults());
3547 using OpConversionPattern::OpConversionPattern;
3551 ConversionPatternRewriter &rewriter)
const override {
3552 auto srcType = dyn_cast<VectorType>(adaptor.getOperand().getType());
3556 Type scalarType = srcType.getElementType();
3557 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
3561 if (!isa<FloatType>(scalarType) || laneSize != 16 || elWidth != 16)
3564 StringRef funcName =
"getRsqrtBf16";
3566 VectorType v16bf16Ty = mlir::VectorType::get({16}, rewriter.getBF16Type());
3567 VectorType v8i64Ty = mlir::VectorType::get({8}, rewriter.getI64Type());
3568 func::FuncOp fnOp = getOrInsertFuncDecl(
3569 rewriter, rsqrtOp->getParentWithTrait<OpTrait::SymbolTable>(), funcName,
3570 TypeRange{v16bf16Ty}, TypeRange{v8i64Ty});
3572 SmallVector<Value> rsqrtOperands = {adaptor.getOperand()};
3576 func::CallOp::create(rewriter, rsqrtOp.getLoc(), fnOp, rsqrtOperands);
3577 auto resCastOp = vector::BitCastOp::create(
3578 rewriter, rsqrtOp.getLoc(), accTypeNative, callOp.getResults());
3579 auto shiftParamOp = arith::ConstantOp::create(
3580 rewriter, rsqrtOp.getLoc(), rewriter.getI32IntegerAttr(0));
3581 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
3582 rsqrtOp, srcType, resCastOp.getResult(), shiftParamOp.getResult());
3591 using OpConversionPattern::OpConversionPattern;
3595 ConversionPatternRewriter &rewriter)
const override {
3596 auto srcType = dyn_cast<VectorType>(rsqrtOp.getOperand().getType());
3600 Type scalarType = srcType.getElementType();
3601 if (!isa<FloatType>(scalarType))
3605 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
3606 if (elWidth != 16 || (laneSize != 16 && laneSize != 32))
3609 StringRef includeName =
"vec_math.h";
3610 auto moduleOp = rsqrtOp->getParentOfType<mlir::ModuleOp>();
3611 rewriter.setInsertionPointToStart(
3612 &moduleOp.getRegion().getBlocks().front());
3613 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
3615 rewriter.setInsertionPoint(rsqrtOp);
3616 Type vLNbf16OpaqueTy;
3619 emitc::OpaqueType::get(rewriter.getContext(),
"v16bfloat16");
3622 emitc::OpaqueType::get(rewriter.getContext(),
"v32bfloat16");
3623 auto opaquedOperand =
3624 UnrealizedConversionCastOp::create(
3625 rewriter, rsqrtOp.getLoc(), vLNbf16OpaqueTy, adaptor.getOperand())
3627 SmallVector<Value> rsqrtOperands = {opaquedOperand};
3628 auto callOp = emitc::CallOpaqueOp::create(
3629 rewriter, rsqrtOp.getLoc(), TypeRange{vLNbf16OpaqueTy},
"getRsqrtBf16",
3630 nullptr,
nullptr, rsqrtOperands);
3631 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
3632 rsqrtOp, TypeRange{rsqrtOp.getResult().getType()}, callOp.getResults());
3641 using OpConversionPattern::OpConversionPattern;
3645 ConversionPatternRewriter &rewriter)
const override {
3646 auto srcType = dyn_cast<VectorType>(erfOp.getOperand().getType());
3650 Type scalarType = srcType.getElementType();
3651 if (!isa<FloatType>(scalarType))
3655 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
3656 if (elWidth != 16 || (laneSize != 16 && laneSize != 32))
3659 StringRef includeName =
"vec_math.h";
3660 auto moduleOp = erfOp->getParentOfType<mlir::ModuleOp>();
3661 rewriter.setInsertionPointToStart(
3662 &moduleOp.getRegion().getBlocks().front());
3663 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
3665 rewriter.setInsertionPoint(erfOp);
3666 Type vLNbf16OpaqueTy;
3669 emitc::OpaqueType::get(rewriter.getContext(),
"v16bfloat16");
3672 emitc::OpaqueType::get(rewriter.getContext(),
"v32bfloat16");
3673 auto opaquedOperand =
3674 UnrealizedConversionCastOp::create(
3675 rewriter, erfOp.getLoc(), vLNbf16OpaqueTy, adaptor.getOperand())
3677 SmallVector<Value> erfOperands = {opaquedOperand};
3678 auto callOp = emitc::CallOpaqueOp::create(
3679 rewriter, erfOp.getLoc(), TypeRange{vLNbf16OpaqueTy},
"getErfBf16",
3680 nullptr,
nullptr, erfOperands);
3681 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
3682 erfOp, TypeRange{erfOp.getResult().getType()}, callOp.getResults());
3690template <
typename SrcOpTy>
3692 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
3697 ConversionPatternRewriter &rewriter)
const override {
3698 auto vecTy = dyn_cast<VectorType>(absOp.getOperand().getType());
3702 Type elemTy = vecTy.getElementType();
3705 unsigned elWidth = elemTy.getIntOrFloatBitWidth();
3707 StringRef includeName =
"vec_math.h";
3708 auto moduleOp = absOp->template getParentOfType<mlir::ModuleOp>();
3709 rewriter.setInsertionPointToStart(
3710 &moduleOp.getRegion().getBlocks().front());
3711 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
3713 rewriter.setInsertionPoint(absOp);
3714 std::ostringstream typeName;
3715 typeName <<
"v" << laneSize;
3716 if (isa<FloatType>(elemTy)) {
3718 typeName <<
"bfloat16";
3720 typeName <<
"float";
3722 typeName <<
"int" << elWidth;
3724 emitc::OpaqueType::get(rewriter.getContext(), typeName.str());
3725 auto opaquedOperand =
3726 UnrealizedConversionCastOp::create(rewriter, absOp.getLoc(),
3727 vecOpaqueTy, adaptor.getOperand())
3729 SmallVector<Value> absOperands = {opaquedOperand};
3730 auto callOp = emitc::CallOpaqueOp::create(rewriter, absOp.getLoc(),
3731 TypeRange{vecOpaqueTy},
"getAbs",
3732 nullptr,
nullptr, absOperands);
3733 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
3734 absOp, TypeRange{absOp.getResult().getType()}, callOp.getResults());
3743template <
typename SrcOpTy>
3745 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
3750 ConversionPatternRewriter &rewriter)
const override {
3751 VectorType srcType = cast<VectorType>(extOp.getIn().getType());
3752 VectorType dstType = cast<VectorType>(extOp.getOut().getType());
3754 Type scalarType = dstType.getElementType();
3755 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
3757 isa<IntegerType>(scalarType) && (elWidth == 32 || elWidth == 64)
3761 aievec::UPSOp::create(rewriter, extOp.getLoc(), accType, extOp.getIn());
3763 if (dstType.getElementType().getIntOrFloatBitWidth() == 16) {
3764 auto shiftParamOp = arith::ConstantOp::create(
3765 rewriter, extOp.getLoc(), rewriter.getI32IntegerAttr(0));
3766 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
3767 extOp, dstType, upsOp.getResult(), shiftParamOp.getResult());
3769 rewriter.replaceOpWithNewOp<aievec::CastOp>(
3770 extOp, dstType, upsOp.getResult(),
false);
3797 : OpConversionPattern<arith::SIToFPOp> {
3798 using OpConversionPattern<arith::SIToFPOp>::OpConversionPattern;
3801 Location loc, Value srcI16,
unsigned lanes) {
3802 Type i16Ty = rewriter.getI16Type();
3803 Type i32Ty = rewriter.getI32Type();
3804 Type bf16Ty = rewriter.getBF16Type();
3805 Type f32Ty = rewriter.getF32Type();
3806 VectorType vecI16 = VectorType::get({lanes}, i16Ty);
3807 VectorType vecI32 = VectorType::get({lanes}, i32Ty);
3808 VectorType vecBF16 = VectorType::get({lanes}, bf16Ty);
3809 VectorType vecF32 = VectorType::get({lanes}, f32Ty);
3811 DenseElementsAttr magicI16Attr = DenseElementsAttr::get(
3812 vecI16, rewriter.getI16IntegerAttr(
static_cast<int16_t
>(0x4b01)));
3814 arith::ConstantOp::create(rewriter, loc, vecI16, magicI16Attr);
3815 Value magicBF16Vec =
3816 vector::BitCastOp::create(rewriter, loc, vecBF16, magicI16Vec);
3818 aievec::UPSOp::create(rewriter, loc, vecF32, magicBF16Vec);
3819 Value magicAccI = aievec::CastOp::create(rewriter, loc, vecI32, magicAccF,
3821 Value vAccI = aievec::UPSOp::create(rewriter, loc, vecI32, srcI16);
3822 Value vSumI = arith::AddIOp::create(rewriter, loc, vAccI, magicAccI);
3823 Value vSumAccF = aievec::CastOp::create(rewriter, loc, vecF32, vSumI,
3826 aievec::SubElemOp::create(rewriter, loc, vecF32, vSumAccF, magicAccF);
3828 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
3829 return aievec::SRSOp::create(rewriter, loc, vecBF16, vDiffAccF, shiftCst)
3835 ConversionPatternRewriter &rewriter)
const override {
3836 auto srcTy = dyn_cast<VectorType>(adaptor.getIn().getType());
3837 auto dstTy = dyn_cast<VectorType>(op.getType());
3838 if (!srcTy || !dstTy || srcTy.getRank() != 1 || dstTy.getRank() != 1)
3840 if (!srcTy.getElementType().isInteger(16))
3842 if (!dstTy.getElementType().isBF16())
3844 unsigned lanes = srcTy.getNumElements();
3845 if (lanes != 16 && lanes != 32 && lanes != 64)
3848 Location loc = op.getLoc();
3849 if (lanes == 16 || lanes == 32) {
3851 rewriter.replaceOp(op, out);
3857 SmallVector<int64_t> loMask, hiMask, catMask;
3858 for (int64_t i = 0; i < 32; ++i)
3859 loMask.push_back(i);
3860 for (int64_t i = 32; i < 64; ++i)
3861 hiMask.push_back(i);
3862 for (int64_t i = 0; i < 64; ++i)
3863 catMask.push_back(i);
3864 Value lo = vector::ShuffleOp::create(rewriter, loc, adaptor.getIn(),
3865 adaptor.getIn(), loMask)
3867 Value hi = vector::ShuffleOp::create(rewriter, loc, adaptor.getIn(),
3868 adaptor.getIn(), hiMask)
3873 vector::ShuffleOp::create(rewriter, loc, loBF16, hiBF16, catMask)
3875 rewriter.replaceOp(op, cat);
3890 : OpConversionPattern<arith::ExtUIOp> {
3891 using OpConversionPattern<arith::ExtUIOp>::OpConversionPattern;
3895 ConversionPatternRewriter &rewriter)
const override {
3896 auto srcTy = dyn_cast<VectorType>(adaptor.getIn().getType());
3897 auto dstTy = dyn_cast<VectorType>(extOp.getType());
3898 if (!srcTy || !dstTy)
3900 if (srcTy.getRank() != 1 || dstTy.getRank() != 1)
3902 if (!srcTy.getElementType().isInteger(4) ||
3903 !dstTy.getElementType().isInteger(8))
3905 unsigned lanes = srcTy.getNumElements();
3906 if (lanes != dstTy.getNumElements())
3908 if (lanes != 64 && lanes != 128)
3911 auto bitcastOp = adaptor.getIn().getDefiningOp<vector::BitCastOp>();
3914 auto bitcastSrcTy = dyn_cast<VectorType>(bitcastOp.getSource().getType());
3915 if (!bitcastSrcTy || bitcastSrcTy.getRank() != 1 ||
3916 !bitcastSrcTy.getElementType().isInteger(8))
3918 if (bitcastSrcTy.getNumElements() * 2 != lanes)
3921 rewriter.replaceOpWithNewOp<aievec::UnpackOp>(extOp, dstTy,
3922 bitcastOp.getSource());
3934template <
typename SrcOpTy>
3936 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
3941 ConversionPatternRewriter &rewriter)
const override {
3942 auto srcType = dyn_cast<VectorType>(adaptor.getIn().getType());
3943 auto dstType = dyn_cast<VectorType>(op.getType());
3944 if (!srcType || !dstType)
3946 if (srcType.getRank() != 1 || dstType.getRank() != 1)
3948 if (srcType.getNumElements() != dstType.getNumElements())
3951 Location loc = op.getLoc();
3952 Type scalarDstTy = dstType.getElementType();
3953 int64_t lanes = srcType.getNumElements();
3956 Value result = arith::ConstantOp::create(rewriter, loc, dstType,
3957 rewriter.getZeroAttr(dstType));
3959 for (int64_t i = 0; i < lanes; ++i) {
3960 Value scalar = vector::ExtractOp::create(rewriter, loc, adaptor.getIn(),
3961 ArrayRef<int64_t>{i});
3962 Value cvt = SrcOpTy::create(rewriter, loc, scalarDstTy, scalar);
3963 result = vector::InsertOp::create(rewriter, loc, cvt, result,
3964 ArrayRef<int64_t>{i});
3967 rewriter.replaceOp(op, result);
3981template <
typename SrcOpTy>
3983 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
3988 ConversionPatternRewriter &rewriter)
const override {
3989 VectorType srcType = cast<VectorType>(truncOp.getIn().getType());
3990 VectorType dstType = cast<VectorType>(truncOp.getOut().getType());
3991 Type scalarType = srcType.getElementType();
3992 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
3994 isa<IntegerType>(scalarType) && (elWidth == 32 || elWidth == 64)
3998 auto shiftParamOp = arith::ConstantOp::create(
3999 rewriter, truncOp.getLoc(), rewriter.getI32IntegerAttr(0));
4000 if (elWidth == 16) {
4001 auto upsOp = aievec::UPSOp::create(rewriter, truncOp.getLoc(), accType,
4003 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
4004 truncOp, dstType, upsOp.getResult(), shiftParamOp.getResult());
4006 auto castOp = aievec::CastOp::create(rewriter, truncOp.getLoc(), accType,
4007 truncOp.getIn(),
true);
4008 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
4009 truncOp, dstType, castOp.getResult(), shiftParamOp.getResult());
4024static std::optional<Value>
4025getUnOpaquedOperandOfEmitCOpaqueCallOp(Operation *op, StringRef funcName) {
4026 auto uccOp = dyn_cast<UnrealizedConversionCastOp>(op);
4030 auto inVal = uccOp.getInputs()[0];
4031 if (!isa<emitc::OpaqueType>(inVal.getType()))
4034 auto callOp = inVal.getDefiningOp<emitc::CallOpaqueOp>();
4035 if (callOp.getCallee() != funcName)
4038 auto callOperandsUccOp =
4039 callOp.getOperands()[0].getDefiningOp<UnrealizedConversionCastOp>();
4040 if (!callOperandsUccOp)
4043 return callOperandsUccOp.getInputs()[0];
4059template <
typename DivFOpTy>
4060static bool hasSigmoidComputationChain(DivFOpTy divfOp, arith::NegFOp &negOp) {
4061 auto *lhsDefOp = divfOp.getLhs().getDefiningOp();
4064 auto constOp = dyn_cast<arith::ConstantOp>(lhsDefOp);
4068 auto cstDense = dyn_cast<DenseFPElementsAttr>(constOp.getValue());
4072 if (cstDense.template getSplatValue<APFloat>().convertToFloat() != 1.0f)
4075 Operation *addLvalOp;
4076 Operation *addRvalOp;
4082 auto *rhsDefOp = divfOp.getRhs().getDefiningOp();
4085 auto addOp = dyn_cast<arith::AddFOp>(rhsDefOp);
4087 auto srsOp = dyn_cast<aievec::SRSOp>(rhsDefOp);
4092 dyn_cast<aievec::AddElemOp>(srsOp.getSource().getDefiningOp());
4096 auto lUpsOp = dyn_cast<aievec::UPSOp>(addElemOp.getLhs().getDefiningOp());
4097 auto rUpsOp = dyn_cast<aievec::UPSOp>(addElemOp.getRhs().getDefiningOp());
4098 if (!lUpsOp || !rUpsOp)
4101 addLvalOp = lUpsOp.getSource().getDefiningOp();
4102 addRvalOp = rUpsOp.getSource().getDefiningOp();
4105 auto addDefOp = isa<arith::ConstantOp>(addLvalOp)
4106 ? dyn_cast<aievec::SRSOp>(addRvalOp)
4107 : dyn_cast<
aievec::SRSOp>(addLvalOp);
4109 addLvalOp = isa<arith::ConstantOp>(addLvalOp)
4110 ? dyn_cast<math::ExpOp>(addRvalOp)
4111 : dyn_cast<math::ExpOp>(addLvalOp);
4113 addLvalOp = addDefOp.getSource().getDefiningOp();
4115 addRvalOp = isa<arith::ConstantOp>(addLvalOp)
4116 ? lUpsOp.getSource().getDefiningOp()
4117 : rUpsOp.getSource().getDefiningOp();
4119 addLvalOp = addOp.getLhs().getDefiningOp();
4120 addRvalOp = addOp.getRhs().getDefiningOp();
4123 if (!addLvalOp || !addRvalOp)
4126 auto addLvalExpOp = dyn_cast<math::ExpOp>(addLvalOp);
4127 auto addRvalExpOp = dyn_cast<math::ExpOp>(addRvalOp);
4128 auto addLvalExpOpIn =
4129 getUnOpaquedOperandOfEmitCOpaqueCallOp(addLvalOp,
"getExpBf16")
4131 auto addRvalExpOpIn =
4132 getUnOpaquedOperandOfEmitCOpaqueCallOp(addRvalOp,
"getExpBf16")
4134 if (!addLvalExpOpIn && addLvalExpOp)
4135 addLvalExpOpIn = addLvalExpOp.getOperand();
4136 if (!addRvalExpOpIn && addRvalExpOp)
4137 addRvalExpOpIn = addRvalExpOp.getOperand();
4139 if (!((addLvalExpOpIn && isa<arith::ConstantOp>(addRvalOp)) ||
4140 (addRvalExpOpIn && isa<arith::ConstantOp>(addLvalOp))))
4143 constOp = isa<arith::ConstantOp>(addLvalOp)
4144 ? cast<arith::ConstantOp>(addLvalOp)
4145 : cast<
arith::ConstantOp>(addRvalOp);
4147 cstDense = dyn_cast<DenseFPElementsAttr>(constOp.getValue());
4150 if (cstDense.template getSplatValue<APFloat>().convertToFloat() != 1.0f)
4153 auto expOperand = addLvalExpOpIn ? addLvalExpOpIn : addRvalExpOpIn;
4155 negOp = expOperand.getDefiningOp<arith::NegFOp>();
4157 return negOp !=
nullptr;
4174 using OpConversionPattern::OpConversionPattern;
4178 ConversionPatternRewriter &rewriter)
const override {
4179 auto srcType = dyn_cast<VectorType>(adaptor.getLhs().getType());
4183 Type scalarType = srcType.getElementType();
4184 if (!isa<FloatType>(scalarType))
4188 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
4189 if (elWidth != 16 || (laneSize != 16 && laneSize != 32))
4192 arith::NegFOp negOp =
nullptr;
4193 if (!hasSigmoidComputationChain(adaptor, negOp))
4196 StringRef includeName =
"vec_math.h";
4197 auto moduleOp = divfOp->getParentOfType<mlir::ModuleOp>();
4198 rewriter.setInsertionPointToStart(
4199 &moduleOp.getRegion().getBlocks().front());
4200 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
4202 rewriter.setInsertionPoint(divfOp);
4206 emitc::OpaqueType::get(rewriter.getContext(),
"v16bfloat16");
4209 emitc::OpaqueType::get(rewriter.getContext(),
"v32bfloat16");
4210 auto opaquedOperand =
4211 UnrealizedConversionCastOp::create(rewriter, divfOp.getLoc(),
4212 vecOpaqueTy, negOp.getOperand())
4214 SmallVector<Value> sigmoidOperands = {opaquedOperand};
4215 auto callOp = emitc::CallOpaqueOp::create(
4216 rewriter, divfOp.getLoc(), TypeRange{vecOpaqueTy},
"getSigmoidBf16",
4217 nullptr,
nullptr, sigmoidOperands);
4218 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
4219 divfOp, TypeRange{adaptor.getLhs().getType()}, callOp.getResults());
4227 using OpConversionPattern::OpConversionPattern;
4231 ConversionPatternRewriter &rewriter)
const override {
4232 auto srcType = dyn_cast<VectorType>(ceilOp.getOperand().getType());
4236 Type scalarType = srcType.getElementType();
4237 if (!isa<FloatType>(scalarType))
4241 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
4242 if (elWidth != 16 || (laneSize != 16 && laneSize != 32))
4245 StringRef includeName =
"vec_math.h";
4246 auto moduleOp = ceilOp->getParentOfType<mlir::ModuleOp>();
4247 rewriter.setInsertionPointToStart(
4248 &moduleOp.getRegion().getBlocks().front());
4249 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
4251 rewriter.setInsertionPoint(ceilOp);
4255 emitc::OpaqueType::get(rewriter.getContext(),
"v16bfloat16");
4258 emitc::OpaqueType::get(rewriter.getContext(),
"v32bfloat16");
4259 auto opaquedOperand =
4260 UnrealizedConversionCastOp::create(rewriter, ceilOp.getLoc(),
4261 vecOpaqueTy, adaptor.getOperand())
4263 SmallVector<Value> ceilOperands = {opaquedOperand};
4264 auto callOp = emitc::CallOpaqueOp::create(
4265 rewriter, ceilOp.getLoc(), TypeRange{vecOpaqueTy},
"getCeilBf16",
4266 nullptr,
nullptr, ceilOperands);
4267 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
4268 ceilOp, TypeRange{ceilOp.getResult().getType()}, callOp.getResults());
4276 using OpConversionPattern::OpConversionPattern;
4280 ConversionPatternRewriter &rewriter)
const override {
4281 auto srcType = dyn_cast<VectorType>(floorOp.getOperand().getType());
4285 Type scalarType = srcType.getElementType();
4286 if (!isa<FloatType>(scalarType))
4290 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
4291 if (elWidth != 16 || (laneSize != 16 && laneSize != 32))
4294 StringRef includeName =
"vec_math.h";
4295 auto moduleOp = floorOp->getParentOfType<mlir::ModuleOp>();
4296 rewriter.setInsertionPointToStart(
4297 &moduleOp.getRegion().getBlocks().front());
4298 emitc::IncludeOp::create(rewriter, moduleOp.getLoc(), includeName,
false);
4300 rewriter.setInsertionPoint(floorOp);
4304 emitc::OpaqueType::get(rewriter.getContext(),
"v16bfloat16");
4307 emitc::OpaqueType::get(rewriter.getContext(),
"v32bfloat16");
4308 auto opaquedOperand =
4309 UnrealizedConversionCastOp::create(rewriter, floorOp.getLoc(),
4310 vecOpaqueTy, adaptor.getOperand())
4312 SmallVector<Value> floorOperands = {opaquedOperand};
4313 auto callOp = emitc::CallOpaqueOp::create(
4314 rewriter, floorOp.getLoc(), TypeRange{vecOpaqueTy},
"getFloorBf16",
4315 nullptr,
nullptr, floorOperands);
4316 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
4317 floorOp, TypeRange{floorOp.getResult().getType()}, callOp.getResults());
4326 using OpConversionPattern::OpConversionPattern;
4330 ConversionPatternRewriter &rewriter)
const override {
4331 auto srcType = dyn_cast<VectorType>(negOp.getOperand().getType());
4335 Type scalarType = srcType.getElementType();
4336 if (!isa<FloatType>(scalarType))
4340 if (laneSize != 16 && laneSize != 32)
4343 Location loc = negOp.getLoc();
4346 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
4347 if (elWidth == 16) {
4349 aievec::UPSOp::create(rewriter, loc, accType, adaptor.getOperand());
4351 aievec::NegOp::create(rewriter, loc, accType, upsOp.getResult());
4352 auto shiftParamOp = arith::ConstantOp::create(
4353 rewriter, negOp.getLoc(), rewriter.getI32IntegerAttr(0));
4354 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
4355 negOp, srcType, aieNegOp.getResult(), shiftParamOp.getResult());
4357 auto castOp = aievec::CastOp::create(
4358 rewriter, loc, accType, adaptor.getOperand(),
true);
4360 aievec::NegOp::create(rewriter, loc, accType, castOp.getResult());
4361 rewriter.replaceOpWithNewOp<aievec::CastOp>(
4362 negOp, srcType, aieNegOp.getResult(),
false);
4371static bool hasConstNegOneValue(arith::ConstantOp constOp,
unsigned elWidth) {
4375 auto cstDense = dyn_cast<DenseIntElementsAttr>(constOp.getValue());
4380 return cstDense.getSplatValue<int32_t>() == -1;
4382 return cstDense.getSplatValue<int16_t>() == -1;
4384 return cstDense.getSplatValue<int8_t>() == -1;
4391 using OpConversionPattern::OpConversionPattern;
4395 ConversionPatternRewriter &rewriter)
const override {
4396 auto srcType = dyn_cast<VectorType>(xorOp.getLhs().getType());
4400 Type scalarType = srcType.getElementType();
4401 if (!isa<IntegerType>(scalarType))
4405 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
4406 if (laneSize * elWidth != 512)
4409 auto lhsConstOp = xorOp.getLhs().getDefiningOp<arith::ConstantOp>();
4410 auto rhsConstOp = xorOp.getRhs().getDefiningOp<arith::ConstantOp>();
4414 if ((lhsConstOp && hasConstNegOneValue(lhsConstOp, elWidth)) ||
4415 (rhsConstOp && hasConstNegOneValue(rhsConstOp, elWidth))) {
4416 Value val = hasConstNegOneValue(lhsConstOp, elWidth) ? adaptor.getRhs()
4418 rewriter.replaceOpWithNewOp<aievec::BnegOp>(xorOp, srcType, val);
4420 rewriter.replaceOpWithNewOp<aievec::BxorOp>(
4421 xorOp, srcType, adaptor.getLhs(), adaptor.getRhs());
4427template <
typename SrcOpTy,
typename DstOpTy>
4429 using OpConversionPattern<SrcOpTy>::OpConversionPattern;
4434 ConversionPatternRewriter &rewriter)
const override {
4435 VectorType srcType = dyn_cast<VectorType>(srcOp.getLhs().getType());
4439 Type scalarType = srcType.getElementType();
4440 if (!isa<IntegerType>(scalarType))
4444 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
4445 if (laneSize * elWidth != 512)
4448 rewriter.replaceOpWithNewOp<DstOpTy>(srcOp, srcOp.getResult().getType(),
4449 adaptor.getLhs(), adaptor.getRhs());
4464 : OpConversionPattern<arith::ShRSIOp> {
4465 using OpConversionPattern::OpConversionPattern;
4469 ConversionPatternRewriter &rewriter)
const override {
4470 auto srcType = dyn_cast<VectorType>(adaptor.getLhs().getType());
4474 Type scalarType = srcType.getElementType();
4476 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
4477 if (laneSize * elWidth != 512)
4481 dyn_cast<aievec::BroadcastOp>(adaptor.getRhs().getDefiningOp());
4486 arith::ConstantOp::create(rewriter, bcastOp.getLoc(),
4487 rewriter.getI32IntegerAttr(bcastOp.getIdx()));
4488 auto extElemOp = aievec::ExtElemOp::create(
4489 rewriter, bcastOp.getLoc(), scalarType, bcastOp, constOp.getResult());
4490 Location loc = rsOp.getLoc();
4496 auto rsOpLow = aievec::ExtOp::create(rewriter, loc, halfSrcType,
4497 adaptor.getLhs(), 0);
4498 auto rsOpHigh = aievec::ExtOp::create(rewriter, loc, halfSrcType,
4499 adaptor.getLhs(), 1);
4502 aievec::UPSOp::create(rewriter, loc, accType, rsOpLow.getResult());
4504 aievec::SRSOp::create(rewriter, loc, halfSrcType,
4505 upsOpLow.getResult(), extElemOp.getResult());
4507 aievec::UPSOp::create(rewriter, loc, accType, rsOpHigh.getResult());
4509 aievec::SRSOp::create(rewriter, loc, halfSrcType,
4510 upsOpHigh.getResult(), extElemOp.getResult());
4511 SmallVector<Value> inputSources = {srsOpLow.getResult(),
4512 srsOpHigh.getResult()};
4513 rewriter.replaceOpWithNewOp<aievec::ConcatOp>(rsOp, srcType,
4518 aievec::UPSOp::create(rewriter, loc, accType, adaptor.getLhs());
4519 rewriter.replaceOpWithNewOp<aievec::SRSOp>(
4520 rsOp, srcType, upsOp.getResult(), extElemOp.getResult());
4543 using OpConversionPattern::OpConversionPattern;
4546 : OpConversionPattern(context, benefit) {}
4551 auto defOp = val.getDefiningOp<arith::ConstantOp>();
4553 return std::nullopt;
4554 auto denseAttr = dyn_cast<DenseIntElementsAttr>(defOp.getValue());
4555 if (!denseAttr || !denseAttr.isSplat())
4556 return std::nullopt;
4557 return denseAttr.getSplatValue<APInt>().getSExtValue();
4563 static std::optional<Value>
4566 if (
auto constOp = rhs.getDefiningOp<arith::ConstantOp>()) {
4567 auto denseAttr = dyn_cast<DenseIntElementsAttr>(constOp.getValue());
4568 if (denseAttr && denseAttr.isSplat()) {
4569 int64_t shiftVal = denseAttr.getSplatValue<APInt>().getSExtValue();
4570 return arith::ConstantOp::create(rewriter, loc,
4571 rewriter.getI32IntegerAttr(shiftVal))
4576 if (
auto bcastOp = dyn_cast<aievec::BroadcastOp>(rhs.getDefiningOp())) {
4577 auto constOp = arith::ConstantOp::create(
4578 rewriter, bcastOp.getLoc(),
4579 rewriter.getI32IntegerAttr(bcastOp.getIdx()));
4580 return aievec::ExtElemOp::create(rewriter, bcastOp.getLoc(),
4581 rewriter.getI32Type(), bcastOp,
4582 constOp.getResult())
4585 return std::nullopt;
4590 ConversionPatternRewriter &rewriter)
const override {
4591 auto dstType = dyn_cast<VectorType>(truncOp.getOut().getType());
4595 Type dstScalarType = dstType.getElementType();
4596 if (!isa<IntegerType>(dstScalarType))
4600 Value source = adaptor.getIn();
4604 arith::MinSIOp minOp =
nullptr;
4605 arith::MaxSIOp maxOp =
nullptr;
4607 if (
auto minsiOp = source.getDefiningOp<arith::MinSIOp>()) {
4608 if (
auto maxsiOp = minsiOp.getLhs().getDefiningOp<arith::MaxSIOp>()) {
4611 source = maxOp.getLhs();
4613 }
else if (
auto maxsiOp = source.getDefiningOp<arith::MaxSIOp>()) {
4614 if (
auto minsiOp = maxsiOp.getLhs().getDefiningOp<arith::MinSIOp>()) {
4617 source = minOp.getLhs();
4622 if (minOp && maxOp) {
4625 if (!loVal || !hiVal)
4628 unsigned dstBits = dstScalarType.getIntOrFloatBitWidth();
4630 if (dstBits == 0 || dstBits > 63)
4632 uint64_t one = 1ULL;
4633 int64_t unsignedLo = 0;
4634 int64_t unsignedHi =
static_cast<int64_t
>((one << dstBits) - 1);
4635 int64_t signedLo = -
static_cast<int64_t
>(one << (dstBits - 1));
4636 int64_t signedHi =
static_cast<int64_t
>((one << (dstBits - 1)) - 1);
4638 if (*loVal == unsignedLo && *hiVal == unsignedHi) {
4640 }
else if (*loVal == signedLo && *hiVal == signedHi) {
4649 auto shrsiOp = source.getDefiningOp<arith::ShRSIOp>();
4653 auto srcType = dyn_cast<VectorType>(shrsiOp.getLhs().getType());
4657 Type srcScalarType = srcType.getElementType();
4658 if (!isa<IntegerType>(srcScalarType))
4661 unsigned srcElWidth = srcScalarType.getIntOrFloatBitWidth();
4662 unsigned dstElWidth = dstScalarType.getIntOrFloatBitWidth();
4663 if (dstElWidth >= srcElWidth)
4666 Location loc = truncOp.getLoc();
4669 auto shiftVal =
getShiftValue(shrsiOp.getRhs(), rewriter, loc);
4674 Value wideInput = shrsiOp.getLhs();
4677 bool needsPadding = (laneSize % 16 != 0);
4679 VectorType paddedSrcType = srcType;
4680 VectorType paddedDstType = dstType;
4684 unsigned paddedLanes = ((laneSize + 15) / 16) * 16;
4689 auto zeroAttr = rewriter.getZeroAttr(paddedSrcType);
4691 arith::ConstantOp::create(rewriter, loc, zeroAttr).getResult();
4692 SmallVector<int64_t> offsets(1, 0);
4693 SmallVector<int64_t> strides(1, 1);
4694 wideInput = vector::InsertStridedSliceOp::create(
4695 rewriter, loc, wideInput, zeroPad, offsets, strides)
4703 Type accScalarType = paddedSrcType.getElementType();
4704 unsigned accElWidth = accScalarType.getIntOrFloatBitWidth();
4706 if (accElWidth == 16) {
4709 aievec::UPSOp::create(rewriter, loc, accType, wideInput).getResult();
4712 accValue = aievec::CastOp::create(rewriter, loc, paddedSrcType, wideInput,
4716 auto srsOp = aievec::SRSOp::create(rewriter, loc, paddedDstType, accValue,
4719 Value result = srsOp.getResult();
4723 SmallVector<int64_t> offsets(1, 0);
4724 SmallVector<int64_t> sizes = {
static_cast<int64_t
>(laneSize)};
4725 SmallVector<int64_t> strides(1, 1);
4726 result = vector::ExtractStridedSliceOp::create(rewriter, loc, result,
4727 offsets, sizes, strides)
4731 rewriter.replaceOp(truncOp, result);
4736 SmallVector<Operation *, 3> opsToErase;
4737 if (minOp && minOp->use_empty())
4738 opsToErase.push_back(minOp);
4739 if (maxOp && maxOp->use_empty())
4740 opsToErase.push_back(maxOp);
4741 if (shrsiOp->use_empty())
4742 opsToErase.push_back(shrsiOp);
4743 for (Operation *op : opsToErase)
4744 rewriter.eraseOp(op);
4757 using OpConversionPattern::OpConversionPattern;
4761 auto defOp = val.getDefiningOp<arith::ConstantOp>();
4763 return std::nullopt;
4764 auto intAttr = dyn_cast<IntegerAttr>(defOp.getValue());
4766 return std::nullopt;
4767 return intAttr.getInt();
4772 ConversionPatternRewriter &rewriter)
const override {
4774 Type dstType = truncOp.getOut().getType();
4775 if (isa<VectorType>(dstType))
4778 auto dstIntType = dyn_cast<IntegerType>(dstType);
4782 unsigned dstBits = dstIntType.getWidth();
4783 if (dstBits != 8 && dstBits != 16)
4786 auto srcIntType = dyn_cast<IntegerType>(truncOp.getIn().getType());
4787 if (!srcIntType || srcIntType.getWidth() != 32)
4791 Value source = truncOp.getIn();
4794 arith::MinSIOp minOp =
nullptr;
4795 arith::MaxSIOp maxOp =
nullptr;
4797 if (
auto minsiOp = source.getDefiningOp<arith::MinSIOp>()) {
4798 if (
auto maxsiOp = minsiOp.getLhs().getDefiningOp<arith::MaxSIOp>()) {
4801 source = maxOp.getLhs();
4803 }
else if (
auto maxsiOp = source.getDefiningOp<arith::MaxSIOp>()) {
4804 if (
auto minsiOp = maxsiOp.getLhs().getDefiningOp<arith::MinSIOp>()) {
4807 source = minOp.getLhs();
4812 if (minOp && maxOp) {
4815 if (!loVal || !hiVal)
4818 if (dstBits == 0 || dstBits > 63)
4820 uint64_t one = 1ULL;
4821 int64_t unsignedLo = 0;
4822 int64_t unsignedHi =
static_cast<int64_t
>((one << dstBits) - 1);
4823 int64_t signedLo = -
static_cast<int64_t
>(one << (dstBits - 1));
4824 int64_t signedHi =
static_cast<int64_t
>((one << (dstBits - 1)) - 1);
4826 if (*loVal == unsignedLo && *hiVal == unsignedHi) {
4828 }
else if (*loVal == signedLo && *hiVal == signedHi) {
4836 Location loc = truncOp.getLoc();
4839 arith::ShRSIOp shrsiOp = source.getDefiningOp<arith::ShRSIOp>();
4842 if (!isa<IntegerType>(shrsiOp.getLhs().getType()))
4844 preShiftVal = shrsiOp.getLhs();
4845 shiftVal = shrsiOp.getRhs();
4850 preShiftVal = source;
4851 shiftVal = arith::ConstantOp::create(rewriter, loc,
4852 rewriter.getI32IntegerAttr(0));
4856 unsigned srcLanes = 512 / srcIntType.getWidth();
4860 auto bcast = aievec::BroadcastScalarOp::create(rewriter, loc, bcastVecType,
4864 VectorType srsOutType;
4870 unsigned accLanes = srcLanes * 2;
4871 VectorType accVecType =
4873 auto concatSrc = aievec::ConcatOp::create(
4874 rewriter, loc, accVecType,
4875 SmallVector<Value>({bcast.getResult(), bcast.getResult()}));
4877 aievec::CastOp::create(rewriter, loc, accVecType,
4878 concatSrc.getResult(),
true)
4885 accValue = aievec::CastOp::create(rewriter, loc, bcastVecType,
4886 bcast.getResult(),
true)
4892 auto srsOp = aievec::SRSOp::create(rewriter, loc, srsOutType, accValue,
4896 unsigned extLanes = 512 / dstBits;
4898 auto concatForExt = aievec::ConcatOp::create(
4899 rewriter, loc, extVecType,
4900 SmallVector<Value>({srsOp.getResult(), srsOp.getResult()}));
4904 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
4905 rewriter.replaceOpWithNewOp<aievec::ExtElemOp>(
4906 truncOp, dstIntType, concatForExt.getResult(), zeroIdx.getResult());
4909 SmallVector<Operation *, 3> opsToErase;
4910 if (minOp && minOp->use_empty())
4911 opsToErase.push_back(minOp);
4912 if (maxOp && maxOp->use_empty())
4913 opsToErase.push_back(maxOp);
4914 if (shrsiOp && shrsiOp->use_empty())
4915 opsToErase.push_back(shrsiOp);
4916 for (Operation *op : opsToErase)
4917 rewriter.eraseOp(op);
4927 using OpConversionPattern::OpConversionPattern;
4931 ConversionPatternRewriter &rewriter)
const override {
4933 Type resultType = rsOp.getType();
4934 if (isa<VectorType>(resultType))
4937 auto intType = dyn_cast<IntegerType>(resultType);
4938 if (!intType || intType.getWidth() != 32)
4941 Location loc = rsOp.getLoc();
4945 auto lhsBcast = aievec::BroadcastScalarOp::create(rewriter, loc, vecType,
4951 aievec::UPSOp::create(rewriter, loc, accType, lhsBcast.getResult());
4954 auto srsOp = aievec::SRSOp::create(rewriter, loc, vecType,
4955 upsOp.getResult(), adaptor.getRhs());
4959 arith::ConstantOp::create(rewriter, loc, rewriter.getI32IntegerAttr(0));
4960 rewriter.replaceOpWithNewOp<aievec::ExtElemOp>(
4961 rsOp, intType, srsOp.getResult(), zeroIdx.getResult());
4977static LogicalResult analyzeContraction(vector::ContractionOp op,
4980 llvm::raw_string_ostream os(why);
4981 if (op.getKind() != vector::CombiningKind::ADD) {
4982 os <<
"the combining kind is not add";
4985 auto accTy = dyn_cast<VectorType>(op.getAccType());
4987 os <<
"the accumulator is a scalar";
4990 SmallVector<AffineMap, 3> maps = op.getIndexingMapsArray();
4991 if (!llvm::all_of(maps, [](AffineMap map) {
4992 return map.isProjectedPermutation(
false);
4994 os <<
"an indexing map is not a projected permutation";
4997 enum Role { M, N, K, Other };
4998 unsigned numDims = maps[0].getNumDims();
4999 SmallVector<int64_t> dimSize(numDims, 1);
5000 SmallVector<std::array<bool, 3>> indexes(numDims, {
false,
false,
false});
5001 ArrayRef<int64_t> shapes[3] = {op.getLhsType().getShape(),
5002 op.getRhsType().getShape(), accTy.getShape()};
5003 for (
unsigned operand = 0; operand < 3; ++operand)
5004 for (
auto [i, expr] : llvm::enumerate(maps[operand].getResults())) {
5005 unsigned d = cast<AffineDimExpr>(expr).getPosition();
5006 dimSize[d] = shapes[operand][i];
5007 indexes[d][operand] =
true;
5009 SmallVector<vector::IteratorType> iterators = op.getIteratorTypesArray();
5010 std::optional<unsigned> dimOf[3];
5011 for (
unsigned d = 0; d < numDims; ++d) {
5012 if (dimSize[d] == 1)
5014 auto [inLhs, inRhs, inAcc] = indexes[d];
5015 bool reduced = iterators[d] == vector::IteratorType::reduction;
5017 if (inLhs && !inRhs && inAcc && !reduced)
5019 else if (!inLhs && inRhs && inAcc && !reduced)
5021 else if (inLhs && inRhs && !inAcc && reduced)
5023 if (r == Other || dimOf[r]) {
5024 os <<
"d" << d <<
" of size " << dimSize[d]
5025 <<
" is not the only m, n or k dim larger than 1";
5030 auto sizeOf = [&](Role r) -> int64_t {
5031 std::optional<unsigned> d = dimOf[r];
5032 return d ? dimSize[*d] : 1;
5038 auto swapped = [&](AffineMap map, Role first, Role second) {
5039 if (!dimOf[first] || !dimOf[second])
5041 return *map.getResultPosition(
5042 getAffineDimExpr(*dimOf[second], map.getContext())) <
5043 *map.getResultPosition(
5044 getAffineDimExpr(*dimOf[first], map.getContext()));
5059template <
typename MatMulOpTy>
5061 : OpConversionPattern<vector::ContractionOp> {
5062 using OpConversionPattern::OpConversionPattern;
5065 std::is_same_v<MatMulOpTy, aievec::MatMulOp_AIE2P>;
5067 static Value
reshape(OpBuilder &b, Value v, ArrayRef<int64_t> shape) {
5068 auto vecTy = cast<VectorType>(v.getType());
5069 auto newTy = VectorType::get(shape, vecTy.getElementType());
5072 return vector::ShapeCastOp::create(b, v.getLoc(), newTy, v).getResult();
5077 ConversionPatternRewriter &rewriter)
const override {
5078 StringRef target =
isAIE2P ?
"AIE2P" :
"AIE2";
5081 if (failed(analyzeContraction(contractOp, tile, why))) {
5082 contractOp.emitError()
5083 <<
"cannot lower to an " << target <<
" matrix multiply: " << why;
5087 Value lhsIn = adaptor.getLhs(), rhsIn = adaptor.getRhs();
5088 Value lhsOrig = contractOp.getLhs(), rhsOrig = contractOp.getRhs();
5089 int64_t m = tile.
m, n = tile.
n, k = tile.
k;
5092 std::swap(lhsIn, rhsIn);
5093 std::swap(lhsOrig, rhsOrig);
5097 std::tie(lhsT, rhsT) =
5098 std::make_pair(!rhsT && m > 1 && k > 1, !lhsT && n > 1 && k > 1);
5100 SmallVector<int64_t, 2> lhsShape =
5101 lhsT ? SmallVector<int64_t, 2>{k, m} : SmallVector<int64_t, 2>{m, k};
5102 SmallVector<int64_t, 2> rhsShape =
5103 rhsT ? SmallVector<int64_t, 2>{n, k} : SmallVector<int64_t, 2>{k, n};
5105 VectorType::get({m, n}, getElementTypeOrSelf(adaptor.getAcc()));
5110 auto lhsSigned = getSignednessOfWideningOp(lhsIn);
5112 lhsSigned = getSignednessOfWideningOp(lhsOrig);
5113 auto rhsSigned = getSignednessOfWideningOp(rhsIn);
5115 rhsSigned = getSignednessOfWideningOp(rhsOrig);
5121 auto retype = [&](Value v, std::optional<bool> isSigned) -> Value {
5124 auto vecTy = cast<VectorType>(v.getType());
5125 auto intTy = dyn_cast<IntegerType>(vecTy.getElementType());
5126 if (!intTy || !intTy.isSignless())
5128 auto signednessTy = IntegerType::get(intTy.getContext(), intTy.getWidth(),
5129 *isSigned ? IntegerType::Signed
5130 : IntegerType::Unsigned);
5131 return UnrealizedConversionCastOp::create(rewriter, v.getLoc(),
5132 vecTy.clone(signednessTy), v)
5136 auto tileFits = [&](Value lhs, Value rhs,
bool report) {
5137 auto emitError = [&]() {
5138 return contractOp.emitError()
5139 <<
"cannot lower to an " << target <<
" matrix multiply: ";
5142 isAIE2P, VectorType::get(lhsShape, getElementTypeOrSelf(lhs)),
5143 VectorType::get(rhsShape, getElementTypeOrSelf(rhs)), accTy,
5145 report ? llvm::function_ref<InFlightDiagnostic()>(emitError)
5153 if (!tileFits(lhsIn, rhsIn,
false)) {
5154 lhsIn = getSourceOfWideningOp(lhsIn).value_or(lhsIn);
5155 rhsIn = getSourceOfWideningOp(rhsIn).value_or(rhsIn);
5156 if (!tileFits(lhsIn, rhsIn,
true))
5159 Value acc =
reshape(rewriter, adaptor.getAcc(), accTy.getShape());
5160 Value lhs =
reshape(rewriter, lhsIn, lhsShape);
5161 Value rhs =
reshape(rewriter, rhsIn, rhsShape);
5164 MatMulOpTy::create(rewriter, contractOp.getLoc(), acc.getType(),
5165 retype(lhs, lhsSigned), retype(rhs, rhsSigned), acc);
5166 matmulOp.setLhsTransposed(lhsT);
5167 matmulOp.setRhsTransposed(rhsT);
5170 reshape(rewriter, matmulOp.getResult(),
5171 cast<VectorType>(adaptor.getAcc().getType()).getShape()));
5183 : OpConversionPattern<vector::TransposeOp> {
5184 using OpConversionPattern::OpConversionPattern;
5187 ConversionPatternRewriter &rewriter)
const override {
5188 auto resTy = transpOp.getResultVectorType();
5189 auto resShape = resTy.getShape();
5190 auto elemTyBitWidth = resTy.getElementTypeBitWidth();
5191 auto vBitWidth = std::accumulate(resShape.begin(), resShape.end(),
5192 elemTyBitWidth, std::multiplies<>());
5193 if (vBitWidth != 512)
5196 if (elemTyBitWidth != 8 && elemTyBitWidth != 16 && elemTyBitWidth != 32)
5200 for (int64_t i = 0; i < static_cast<int64_t>(resShape.size() - 2); ++i)
5201 if (resShape[i] != 1)
5205 ArrayRef<int64_t> perm = transpOp.getPermutation();
5206 for (int64_t i = 0; i < static_cast<int64_t>(perm.size() - 2); ++i)
5209 if (perm.back() !=
static_cast<int64_t
>(perm.size() - 2))
5212 auto shuffleMode = aievec::ShuffleMode::T32_4X4;
5213 if (elemTyBitWidth == 8) {
5214 switch (resShape.back()) {
5216 shuffleMode = aievec::ShuffleMode::T8_4X16;
5219 shuffleMode = aievec::ShuffleMode::T8_8X8;
5222 shuffleMode = aievec::ShuffleMode::T8_16X4;
5227 }
else if (elemTyBitWidth == 16) {
5228 switch (resShape.back()) {
5230 shuffleMode = aievec::ShuffleMode::T16_2X16;
5233 shuffleMode = aievec::ShuffleMode::T16_4X8;
5236 shuffleMode = aievec::ShuffleMode::T16_8X4;
5239 shuffleMode = aievec::ShuffleMode::T16_16X2;
5244 }
else if (resShape.back() != 4)
5248 VectorType::get({512 / elemTyBitWidth}, resTy.getElementType());
5249 auto loc = transpOp.getLoc();
5250 auto flatInput = vector::ShapeCastOp::create(rewriter, loc, flatVecTy,
5251 adaptor.getVector());
5252 auto shuffOp = aievec::ShuffleOp::create(rewriter, loc, flatVecTy,
5253 flatInput,
nullptr, shuffleMode);
5254 rewriter.replaceOpWithNewOp<vector::ShapeCastOp>(transpOp, resTy, shuffOp);
5265populateAIEVecCommonConversionPatterns(RewritePatternSet &patterns) {
5285static void populateAIEVecV1ConversionPatterns(RewritePatternSet &patterns) {
5303populateAIEVecV2CommonConversionPatterns(RewritePatternSet &patterns) {
5315 >(patterns.getContext());
5361 >(patterns.getContext());
5365static void populateAIEVecV2ConversionPatterns(RewritePatternSet &patterns) {
5366 populateAIEVecV2CommonConversionPatterns(patterns);
5368 patterns.getContext());
5372 patterns.getContext());
5378 : OpConversionPattern<vector::BroadcastOp> {
5379 using OpConversionPattern::OpConversionPattern;
5383 ConversionPatternRewriter &rewriter)
const override {
5385 if (adaptor.getSource().getDefiningOp<vector::ExtractOp>())
5388 auto resultType = cast<VectorType>(bcastOp.getResult().getType());
5390 Type scalarType = resultType.getElementType();
5391 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
5393 auto src = bcastOp.getSource();
5396 if (laneSize * elWidth == 512 || laneSize * elWidth == 256) {
5397 Value newOp = aievec::BroadcastScalarOp::create(
5398 rewriter, bcastOp.getLoc(), flatResultType, src);
5399 if (resultType != flatResultType)
5400 newOp = vector::ShapeCastOp::create(rewriter, bcastOp.getLoc(),
5402 rewriter.replaceOp(bcastOp, newOp);
5406 if (laneSize * elWidth == 1024) {
5408 auto aieBcastOp = aievec::BroadcastScalarOp::create(
5409 rewriter, bcastOp.getLoc(), vecType, src);
5410 Value newOp = aievec::ConcatOp::create(
5411 rewriter, bcastOp.getLoc(), flatResultType,
5412 SmallVector<Value>({aieBcastOp.getResult(), aieBcastOp.getResult()}));
5413 if (resultType != flatResultType)
5414 newOp = vector::ShapeCastOp::create(rewriter, bcastOp.getLoc(),
5416 rewriter.replaceOp(bcastOp, newOp);
5426static bool isFlattenableElementwise(Operation *op) {
5427 if (op->getNumResults() != 1)
5429 auto resultType = dyn_cast<VectorType>(op->getResult(0).getType());
5430 if (!resultType || resultType.getRank() == 1 || resultType.isScalable())
5436 if (isa<arith::ExtFOp>(op) &&
5437 llvm::any_of(op->getUsers(), [](Operation *user) {
5438 return isa<vector::ContractionOp>(user);
5445 return llvm::all_of(op->getOperandTypes(), [&](Type type) {
5446 auto operandType = dyn_cast<VectorType>(type);
5447 return !operandType || operandType.getShape() == resultType.getShape();
5458template <
typename OpTy>
5460 using OpConversionPattern<OpTy>::OpConversionPattern;
5465 ConversionPatternRewriter &rewriter)
const override {
5466 if (!isFlattenableElementwise(op))
5469 auto resultType = cast<VectorType>(op.getType());
5471 Location loc = op.getLoc();
5473 SmallVector<Value> flatOperands;
5474 flatOperands.reserve(adaptor.getOperands().size());
5475 for (Value operand : adaptor.getOperands()) {
5476 auto operandType = dyn_cast<VectorType>(operand.getType());
5478 flatOperands.push_back(operand);
5485 if (
auto cstOp = operand.template getDefiningOp<arith::ConstantOp>()) {
5486 if (
auto dense = dyn_cast<DenseElementsAttr>(cstOp.getValue())) {
5487 if (dense.isSplat()) {
5488 flatOperands.push_back(arith::ConstantOp::create(
5490 DenseElementsAttr::get(flatOperandType,
5491 dense.getSplatValue<Attribute>())));
5496 flatOperands.push_back(
5497 vector::ShapeCastOp::create(rewriter, loc, flatOperandType, operand));
5500 auto flatOp = OpTy::create(rewriter, loc, TypeRange{flatResultType},
5501 flatOperands, op.getProperties(),
5502 op->getDiscardableAttrDictionary().getValue());
5503 rewriter.replaceOpWithNewOp<vector::ShapeCastOp>(op, resultType,
5504 flatOp->getResult(0));
5512static SmallVector<int64_t, 5> getAIE2PNativeLanes(Operation *op) {
5513 Value v = isa<arith::CmpIOp, arith::CmpFOp>(op) ? op->getOperand(0)
5515 auto type = dyn_cast<VectorType>(v.getType());
5516 if (!type || !type.getElementType().isIntOrFloat())
5518 Type elemType = type.getElementType();
5519 unsigned bitWidth = elemType.getIntOrFloatBitWidth();
5520 bool isInt = isa<IntegerType>(elemType) &&
5521 (bitWidth == 8 || bitWidth == 16 || bitWidth == 32);
5526 if (isa<arith::AddFOp, arith::SubFOp>(op)) {
5527 if (elemType.isF32())
5528 return {16, 32, 64};
5529 if (elemType.isBF16())
5536 if (isa<arith::AddIOp, arith::SubIOp>(op)) {
5539 SmallVector<int64_t, 5> lanes;
5540 for (int64_t n = 2; n <= 512 / bitWidth; n *= 2)
5547 if (isa<math::TanhOp, math::ErfOp, math::Exp2Op>(op)) {
5548 if (elemType.isF32() || elemType.isBF16())
5553 if (isa<arith::MaximumFOp, arith::MaxNumFOp, arith::MinimumFOp>(op)) {
5554 if (elemType.isBF16())
5562 if (isa<arith::CmpIOp, arith::CmpFOp, arith::SelectOp>(op)) {
5563 if (
auto cmpOp = dyn_cast<arith::CmpFOp>(op);
5564 cmpOp && !llvm::is_contained({CmpFPredicate::OEQ, CmpFPredicate::ONE,
5565 CmpFPredicate::OLT, CmpFPredicate::OLE,
5566 CmpFPredicate::OGT, CmpFPredicate::OGE},
5567 cmpOp.getPredicate()))
5569 if (elemType.isBF16() || elemType.isInteger(16))
5571 if (elemType.isInteger(32))
5579static bool isAIE2PNativeWidth(Operation *op) {
5580 auto type = dyn_cast<VectorType>(op->getResult(0).getType());
5581 return type && !type.isScalable() &&
5582 llvm::is_contained(getAIE2PNativeLanes(op), type.getNumElements());
5586static Operation *getSelectCompare(arith::SelectOp op) {
5587 Operation *cmp = skipShapeCastRoundTrip(op.getCondition()).getDefiningOp();
5588 return isa_and_nonnull<arith::CmpIOp, arith::CmpFOp>(cmp) ? cmp :
nullptr;
5603static std::optional<int64_t> getAIE2PPartLanes(Operation *op) {
5604 if (op->getNumResults() != 1 || isa<arith::CmpIOp, arith::CmpFOp>(op))
5605 return std::nullopt;
5606 auto type = dyn_cast<VectorType>(op->getResult(0).getType());
5607 if (!type || type.isScalable())
5608 return std::nullopt;
5609 int64_t lanes = type.getNumElements();
5610 if (lanes < 2 || llvm::any_of(
5611 op->getOperandTypes(),
5613 auto vt = dyn_cast<VectorType>(t);
5614 return !vt || vt.getShape() != type.getShape();
5616 return std::nullopt;
5618 SmallVector<int64_t, 5> native = getAIE2PNativeLanes(op);
5619 if (
auto selOp = dyn_cast<arith::SelectOp>(op)) {
5620 Operation *cmp = getSelectCompare(selOp);
5622 return std::nullopt;
5623 SmallVector<int64_t, 5> cmpNative = getAIE2PNativeLanes(cmp);
5625 native, [&](int64_t n) {
return !llvm::is_contained(cmpNative, n); });
5627 if (native.empty() || llvm::is_contained(native, lanes))
5628 return std::nullopt;
5630 if (isa<arith::AddIOp, arith::SubIOp>(op) && lanes < native.back())
5631 return std::nullopt;
5633 for (int64_t part : llvm::reverse(native))
5634 if (part < lanes && lanes % part == 0 && lanes / part <=
kAIE2PMaxParts)
5636 if (isa<arith::SelectOp>(op))
5637 return std::nullopt;
5638 for (int64_t part : native)
5639 if (part > lanes && part % lanes == 0)
5641 return std::nullopt;
5648static Value getAIE2PPart(ConversionPatternRewriter &rewriter, Location loc,
5649 Value v, int64_t partLanes, int64_t index) {
5650 auto type = cast<VectorType>(v.getType());
5651 auto partType = VectorType::get({partLanes}, type.getElementType());
5652 int64_t lanes = type.getNumElements();
5653 if (
auto cstOp = v.getDefiningOp<arith::ConstantOp>())
5654 if (
auto dense = dyn_cast<DenseElementsAttr>(cstOp.getValue());
5655 dense && dense.isSplat())
5656 return arith::ConstantOp::create(
5658 DenseElementsAttr::get(partType, dense.getSplatValue<Attribute>()));
5659 if (
auto bcastOp = v.getDefiningOp<vector::BroadcastOp>())
5660 if (!isa<VectorType>(bcastOp.getSourceType()))
5661 return vector::BroadcastOp::create(rewriter, loc, partType,
5662 bcastOp.getSource());
5663 if (partLanes < lanes) {
5664 if (
auto concatOp = v.getDefiningOp<aievec::ConcatOp>())
5665 if (concatOp.getSources().front().getType() == partType)
5666 return concatOp.getSources()[index];
5667 return aievec::ExtOp::create(rewriter, loc, partType, v, index);
5669 SmallVector<Value> copies(partLanes / lanes, v);
5670 return aievec::ConcatOp::create(rewriter, loc, partType, copies);
5676static Value getAIE2PMaskPart(ConversionPatternRewriter &rewriter, Location loc,
5677 arith::SelectOp selOp, int64_t partLanes,
5679 Operation *cmp = getSelectCompare(selOp);
5680 OperationState state(loc, cmp->getName());
5681 for (Value operand : cmp->getOperands())
5682 state.addOperands(getAIE2PPart(
5683 rewriter, loc, rewriter.getRemappedValue(operand), partLanes, index));
5684 state.addTypes(VectorType::get({partLanes}, rewriter.getI1Type()));
5685 state.addAttributes(cmp->getAttrs());
5686 return rewriter.create(state)->getResult(0);
5694template <
typename OpTy>
5696 using OpConversionPattern<OpTy>::OpConversionPattern;
5701 ConversionPatternRewriter &rewriter)
const override {
5702 auto type = dyn_cast<VectorType>(op->getResult(0).getType());
5703 if (!type || type.getRank() != 1)
5705 std::optional<int64_t> partLanes = getAIE2PPartLanes(op);
5708 int64_t lanes = type.getNumElements();
5709 auto partType = VectorType::get({*partLanes}, type.getElementType());
5710 Location loc = op.getLoc();
5711 auto createPart = [&](int64_t index) -> Value {
5712 SmallVector<Value> operands;
5713 for (Value operand : adaptor.getOperands()) {
5714 if constexpr (std::is_same_v<OpTy, arith::SelectOp>) {
5715 if (operands.empty()) {
5717 getAIE2PMaskPart(rewriter, loc, op, *partLanes, index));
5722 getAIE2PPart(rewriter, loc, operand, *partLanes, index));
5724 return OpTy::create(rewriter, loc, TypeRange{partType}, operands,
5726 op->getDiscardableAttrDictionary().getValue())
5730 if (*partLanes > lanes) {
5731 rewriter.replaceOpWithNewOp<aievec::ExtOp>(op, type, createPart(0), 0);
5734 SmallVector<Value> parts;
5735 for (int64_t i = 0; i < lanes / *partLanes; ++i)
5736 parts.push_back(createPart(i));
5737 rewriter.replaceOpWithNewOp<aievec::ConcatOp>(op, type, parts);
5746template <
typename... OpTys>
5748 static void addPatterns(RewritePatternSet &patterns, PatternBenefit benefit) {
5759 template <
typename OpTy>
5761 std::optional<ConversionTarget::LegalizationAction> action =
5762 target.getOpAction(OperationName(OpTy::getOperationName(), ctx));
5763 if (action == ConversionTarget::LegalizationAction::Legal)
5764 target.addDynamicallyLegalOp<OpTy>([](Operation *op) {
5765 return !isFlattenableElementwise(op) && !getAIE2PPartLanes(op);
5767 else if (action == ConversionTarget::LegalizationAction::Dynamic)
5768 target.addDynamicallyLegalOp<OpTy>(
5769 [](Operation *op) -> std::optional<bool> {
5770 if (isFlattenableElementwise(op) || getAIE2PPartLanes(op))
5772 return std::nullopt;
5777 arith::MulFOp, arith::DivFOp, arith::AddFOp, arith::SubFOp, arith::NegFOp,
5778 arith::TruncFOp, arith::ExtFOp, math::ExpOp, math::TanhOp, math::ErfOp,
5779 math::Exp2Op, arith::MaximumFOp, arith::MaxNumFOp, arith::MinimumFOp,
5780 arith::CmpFOp, arith::CmpIOp, arith::SelectOp, arith::AddIOp, arith::SubIOp,
5781 arith::MulIOp, arith::IndexCastOp>;
5783static void populateAIEVecV2PConversionPatterns(
5784 RewritePatternSet &patterns, std::shared_ptr<AIE2PShufflePlanner> planner) {
5785 populateAIEVecV2CommonConversionPatterns(patterns);
5787 patterns.getContext());
5799 patterns.getContext());
5824static bool isInSigmoidOperationChain(math::ExpOp expOp) {
5825 if (!expOp.getOperand().getDefiningOp<arith::NegFOp>())
5828 arith::AddFOp addOp =
nullptr;
5829 for (Operation *user : expOp->getUsers()) {
5830 addOp = dyn_cast<arith::AddFOp>(user);
5838 auto *addLvalOp = addOp.getLhs().getDefiningOp();
5839 auto *addRvalOp = addOp.getRhs().getDefiningOp();
5840 if (!((isa<math::ExpOp>(addLvalOp) && isa<arith::ConstantOp>(addRvalOp)) ||
5841 (isa<math::ExpOp>(addRvalOp) && isa<arith::ConstantOp>(addLvalOp))))
5844 auto constOp = isa<arith::ConstantOp>(addLvalOp)
5845 ? cast<arith::ConstantOp>(addLvalOp)
5846 : cast<
arith::ConstantOp>(addRvalOp);
5848 auto cstDense = dyn_cast<DenseFPElementsAttr>(constOp.getValue());
5852 if (cstDense.getSplatValue<APFloat>().convertToFloat() != 1.0f)
5855 arith::DivFOp divOp =
nullptr;
5856 for (Operation *user : addOp->getUsers()) {
5857 divOp = dyn_cast<arith::DivFOp>(user);
5865 constOp = dyn_cast<arith::ConstantOp>(divOp.getLhs().getDefiningOp());
5868 cstDense = dyn_cast<DenseFPElementsAttr>(constOp.getValue());
5871 if (cstDense.getSplatValue<APFloat>().convertToFloat() != 1.0f)
5877static void configureAIEVecCommonLegalizations(ConversionTarget &target) {
5879 .addLegalDialect<xilinx::aievec::aie1::AIEVecAIE1Dialect,
5880 xilinx::aievec::AIEVecDialect, arith::ArithDialect,
5881 ub::UBDialect, emitc::EmitCDialect, func::FuncDialect>();
5882 target.addIllegalOp<vector::ExtractStridedSliceOp>();
5883 target.addLegalOp<vector::BitCastOp>();
5885 target.addDynamicallyLegalOp<arith::ExtFOp>([](arith::ExtFOp extfOp) {
5886 auto srcType = dyn_cast<VectorType>(extfOp.getIn().getType());
5887 auto dstType = dyn_cast<VectorType>(extfOp.getOut().getType());
5888 if (!srcType || !dstType)
5891 Type srcScalarType = srcType.getElementType();
5892 Type dstScalarType = dstType.getElementType();
5893 if (!isa<FloatType>(srcScalarType) || !isa<FloatType>(dstScalarType))
5898 unsigned srcElWidth = srcScalarType.getIntOrFloatBitWidth();
5899 unsigned dstElWidth = dstScalarType.getIntOrFloatBitWidth();
5900 return srcElWidth != 16 || srcLaneSize != 16 || dstElWidth != 32 ||
5904 target.addDynamicallyLegalOp<arith::ExtSIOp>([](arith::ExtSIOp extsiOp) {
5905 auto srcType = dyn_cast<VectorType>(extsiOp.getIn().getType());
5906 auto dstType = dyn_cast<VectorType>(extsiOp.getOut().getType());
5907 if (!srcType || !dstType)
5910 Type srcScalarType = srcType.getElementType();
5911 Type dstScalarType = dstType.getElementType();
5912 if (!isa<IntegerType>(srcScalarType) || !isa<IntegerType>(dstScalarType))
5917 unsigned srcElWidth = srcScalarType.getIntOrFloatBitWidth();
5918 unsigned dstElWidth = dstScalarType.getIntOrFloatBitWidth();
5919 return srcLaneSize != 32 || (dstElWidth <= srcElWidth) ||
5920 (dstLaneSize != srcLaneSize);
5929 target.addDynamicallyLegalOp<arith::ExtUIOp>([](arith::ExtUIOp extuiOp) {
5930 auto srcType = dyn_cast<VectorType>(extuiOp.getIn().getType());
5931 auto dstType = dyn_cast<VectorType>(extuiOp.getOut().getType());
5932 if (!srcType || !dstType)
5934 if (srcType.getRank() != 1 || dstType.getRank() != 1)
5936 Type srcScalarType = srcType.getElementType();
5937 Type dstScalarType = dstType.getElementType();
5938 if (!srcScalarType.isInteger(4) || !dstScalarType.isInteger(8))
5940 unsigned lanes = srcType.getNumElements();
5941 if (lanes != 64 && lanes != 128)
5943 auto bitcastOp = extuiOp.getIn().getDefiningOp<vector::BitCastOp>();
5946 auto bitcastSrcType = dyn_cast<VectorType>(bitcastOp.getSource().getType());
5947 return !bitcastSrcType || bitcastSrcType.getRank() != 1 ||
5948 !bitcastSrcType.getElementType().isInteger(8) ||
5949 bitcastSrcType.getNumElements() * 2 != lanes;
5952 target.addDynamicallyLegalOp<arith::TruncFOp>([](arith::TruncFOp truncfOp) {
5953 auto srcType = dyn_cast<VectorType>(truncfOp.getIn().getType());
5954 auto dstType = dyn_cast<VectorType>(truncfOp.getOut().getType());
5955 if (!srcType || !dstType)
5958 Type srcScalarType = srcType.getElementType();
5959 Type dstScalarType = dstType.getElementType();
5960 if (!isa<FloatType>(srcScalarType) || !isa<FloatType>(dstScalarType))
5965 unsigned srcElWidth = srcScalarType.getIntOrFloatBitWidth();
5966 unsigned dstElWidth = dstScalarType.getIntOrFloatBitWidth();
5967 return srcElWidth != 32 || srcLaneSize != 16 || dstElWidth != 16 ||
5971 target.addDynamicallyLegalOp<arith::TruncIOp>([](arith::TruncIOp trunciOp) {
5972 auto srcType = dyn_cast<VectorType>(trunciOp.getIn().getType());
5973 auto dstType = dyn_cast<VectorType>(trunciOp.getOut().getType());
5974 if (!srcType || !dstType) {
5977 return !(!srcType && !dstType && isSRSCompoundCandidate(trunciOp));
5980 Type srcScalarType = srcType.getElementType();
5981 Type dstScalarType = dstType.getElementType();
5982 if (!isa<IntegerType>(srcScalarType) || !isa<IntegerType>(dstScalarType))
5986 if (isSRSCompoundCandidate(trunciOp))
5991 unsigned srcElWidth = srcScalarType.getIntOrFloatBitWidth();
5992 unsigned dstElWidth = dstScalarType.getIntOrFloatBitWidth();
5994 return srcLaneSize != 32 || (dstElWidth >= srcElWidth) ||
5995 (dstLaneSize != srcLaneSize);
5998 target.addDynamicallyLegalOp<math::TanhOp>([](math::TanhOp tanhOp) {
5999 auto srcType = dyn_cast<VectorType>(tanhOp.getOperand().getType());
6003 Type scalarType = srcType.getElementType();
6004 if (!isa<FloatType>(scalarType))
6008 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6009 return elWidth != 16 || laneSize != 16;
6012 target.addDynamicallyLegalOp<math::SqrtOp>([](math::SqrtOp sqrtOp) {
6013 auto srcType = dyn_cast<VectorType>(sqrtOp.getOperand().getType());
6017 Type scalarType = srcType.getElementType();
6018 if (!isa<FloatType>(scalarType))
6022 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6023 return elWidth != 16 || (laneSize != 16 && laneSize != 32);
6026 target.addDynamicallyLegalOp<math::ErfOp>([](math::ErfOp erfOp) {
6027 auto srcType = dyn_cast<VectorType>(erfOp.getOperand().getType());
6031 Type scalarType = srcType.getElementType();
6032 if (!isa<FloatType>(scalarType))
6036 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6037 return elWidth != 16 || (laneSize != 16 && laneSize != 32);
6040 target.addDynamicallyLegalOp<math::AbsFOp>([](math::AbsFOp absfOp) {
6041 auto srcType = dyn_cast<VectorType>(absfOp.getOperand().getType());
6045 Type scalarType = srcType.getElementType();
6047 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6048 return elWidth * laneSize != 512 && elWidth * laneSize != 256;
6051 target.addDynamicallyLegalOp<math::AbsIOp>([](math::AbsIOp absiOp) {
6052 auto srcType = dyn_cast<VectorType>(absiOp.getOperand().getType());
6056 Type scalarType = srcType.getElementType();
6058 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6059 return elWidth * laneSize != 512 && elWidth * laneSize != 256;
6062 target.addDynamicallyLegalOp<math::CeilOp>([](math::CeilOp ceilOp) {
6063 auto srcType = dyn_cast<VectorType>(ceilOp.getOperand().getType());
6066 Type scalarType = srcType.getElementType();
6067 if (!isa<FloatType>(scalarType))
6071 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6072 return elWidth != 16 || (laneSize != 16 && laneSize != 32);
6075 target.addDynamicallyLegalOp<math::FloorOp>([](math::FloorOp floorOp) {
6076 auto srcType = dyn_cast<VectorType>(floorOp.getOperand().getType());
6079 Type scalarType = srcType.getElementType();
6080 if (!isa<FloatType>(scalarType))
6084 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6085 return elWidth != 16 || (laneSize != 16 && laneSize != 32);
6088 target.addDynamicallyLegalOp<arith::NegFOp>([](arith::NegFOp negOp) {
6089 auto srcType = dyn_cast<VectorType>(negOp.getOperand().getType());
6092 if (Type scalarType = srcType.getElementType(); !isa<FloatType>(scalarType))
6096 return laneSize != 16;
6099 target.addDynamicallyLegalOp<arith::ShRSIOp>([](arith::ShRSIOp rsOp) {
6100 auto srcType = dyn_cast<VectorType>(rsOp.getLhs().getType());
6104 if (
auto intType = dyn_cast<IntegerType>(rsOp.getLhs().getType()))
6105 if (intType.getWidth() == 32) {
6108 return shrsiUsedByCompoundSRS(rsOp);
6115 if (shrsiUsedByCompoundSRS(rsOp))
6118 Type scalarType = srcType.getElementType();
6120 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6122 return laneSize * elWidth != 512;
6125 target.addDynamicallyLegalOp<arith::AddFOp>(
6126 [](arith::AddFOp op) {
return !isa<VectorType>(op.getType()); });
6127 target.addDynamicallyLegalOp<arith::SubFOp>(
6128 [](arith::SubFOp op) {
return !isa<VectorType>(op.getType()); });
6139 auto isRank1Vector = [](Type t) {
6140 auto vt = dyn_cast<VectorType>(t);
6141 return vt && vt.getRank() == 1;
6143 target.addDynamicallyLegalOp<arith::SIToFPOp>(
6144 [=](arith::SIToFPOp op) {
return !isRank1Vector(op.getType()); });
6145 target.addDynamicallyLegalOp<arith::UIToFPOp>(
6146 [=](arith::UIToFPOp op) {
return !isRank1Vector(op.getType()); });
6147 target.addDynamicallyLegalOp<arith::FPToSIOp>(
6148 [=](arith::FPToSIOp op) {
return !isRank1Vector(op.getType()); });
6149 target.addDynamicallyLegalOp<arith::FPToUIOp>(
6150 [=](arith::FPToUIOp op) {
return !isRank1Vector(op.getType()); });
6151 target.addLegalOp<vector::ExtractOp, vector::InsertOp>();
6154static void configureAIEVecV1Legalizations(ConversionTarget &target) {
6155 target.addDynamicallyLegalOp<arith::MulIOp>(
6156 [](arith::MulIOp op) {
return !isa<VectorType>(op.getType()); });
6157 target.addDynamicallyLegalOp<arith::MulFOp>(
6158 [](arith::MulFOp op) {
return !isa<VectorType>(op.getType()); });
6159 target.addDynamicallyLegalOp<aievec::aie1::FMAOp>(
6160 [](xilinx::aievec::aie1::FMAOp op) {
6161 auto *lhsDefOp = op.getLhs().getDefiningOp();
6162 aievec::ConcatOp concatOp =
nullptr;
6164 concatOp = dyn_cast<aievec::ConcatOp>(op.getLhs().getDefiningOp());
6168 vector::BroadcastOp srcBcast =
nullptr;
6169 if (
auto *lhsOp = concatOp.getSources()[0].getDefiningOp())
6170 srcBcast = dyn_cast<vector::BroadcastOp>(lhsOp);
6172 auto *rhsOp = op.getRhs().getDefiningOp();
6175 srcBcast = dyn_cast<vector::BroadcastOp>(rhsOp);
6179 if (
auto *srcOp = srcBcast.getSource().getDefiningOp())
6180 return !isa<vector::ExtractOp>(srcOp);
6185 target.addDynamicallyLegalOp<aievec::aie1::AddOp>([](aievec::aie1::AddOp op) {
6186 auto lSrsOp = op.getLhs().getDefiningOp<aievec::SRSOp>();
6187 auto rSrsOp = op.getRhs().getDefiningOp<aievec::SRSOp>();
6189 !lSrsOp.getSource().getDefiningOp<aievec::aie1::MulOp>()) &&
6191 !rSrsOp.getSource().getDefiningOp<aievec::aie1::MulOp>());
6193 target.addLegalDialect<memref::MemRefDialect>();
6197configureAIEVecV2PLegalizations(ConversionTarget &target,
6198 std::shared_ptr<AIE2PShufflePlanner> planner) {
6202 target.addDynamicallyLegalOp<math::RsqrtOp>([](math::RsqrtOp rsqrtOp) {
6203 auto vecType = dyn_cast<VectorType>(rsqrtOp.getOperand().getType());
6206 return !vecType || !vecType.getElementType().isBF16();
6211 target.addDynamicallyLegalOp<math::ExpOp>([](math::ExpOp expOp) {
6212 auto srcType = dyn_cast<VectorType>(expOp.getOperand().getType());
6216 Type scalarType = srcType.getElementType();
6217 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6220 if (scalarType.isF32())
6221 return srcType.isScalable() || (laneSize != 16 && laneSize != 32);
6223 if (!scalarType.isBF16() || (laneSize != 16 && laneSize != 32) ||
6226 if (expOp->hasOneUse() && isInSigmoidOperationChain(expOp))
6235 target.addDynamicallyLegalOp<math::TanhOp>([](math::TanhOp tanhOp) {
6236 return !isAIE2PAccFloatUnaryOrScalarType(tanhOp.getOperand().getType());
6238 target.addDynamicallyLegalOp<math::ErfOp>([](math::ErfOp erfOp) {
6239 return !isAIE2PAccFloatUnaryOrScalarType(erfOp.getOperand().getType());
6241 target.addDynamicallyLegalOp<math::Exp2Op>([](math::Exp2Op exp2Op) {
6242 return !isAIE2PAccFloatUnaryOrScalarType(exp2Op.getOperand().getType());
6247 target.addDynamicallyLegalOp<arith::DivFOp>([](arith::DivFOp divfOp) {
6248 Type srcType = divfOp.getLhs().getType();
6252 dyn_cast_or_null<arith::ConstantOp>(divfOp.getLhs().getDefiningOp());
6257 if (srcType.isF32()) {
6258 auto floatAttr = dyn_cast<FloatAttr>(constOp.getValue());
6260 return !floatAttr || !floatAttr.getValue().isExactlyValue(1.0);
6264 if (
auto vecType = dyn_cast<VectorType>(srcType)) {
6265 if (vecType.getElementType().isF32()) {
6267 if (laneSize == 16 || laneSize == 32) {
6268 auto denseAttr = dyn_cast<DenseFPElementsAttr>(constOp.getValue());
6269 if (denseAttr && denseAttr.isSplat() &&
6270 denseAttr.getSplatValue<APFloat>().isExactlyValue(1.0))
6280 target.addDynamicallyLegalOp<arith::ExtFOp>([](arith::ExtFOp extfOp) {
6281 auto srcType = dyn_cast<VectorType>(extfOp.getIn().getType());
6282 auto dstType = dyn_cast<VectorType>(extfOp.getOut().getType());
6283 if (!srcType || !dstType)
6286 Type srcScalarType = srcType.getElementType();
6287 Type dstScalarType = dstType.getElementType();
6288 if (!isa<FloatType>(srcScalarType) || !isa<FloatType>(dstScalarType))
6293 return (srcLaneSize % 16 != 0) || (dstLaneSize % 16 != 0);
6297 target.addDynamicallyLegalOp<arith::TruncFOp>([](arith::TruncFOp truncfOp) {
6298 auto srcType = dyn_cast<VectorType>(truncfOp.getIn().getType());
6299 auto dstType = dyn_cast<VectorType>(truncfOp.getOut().getType());
6300 if (!srcType || !dstType)
6303 Type srcScalarType = srcType.getElementType();
6304 Type dstScalarType = dstType.getElementType();
6305 if (!isa<FloatType>(srcScalarType) || !isa<FloatType>(dstScalarType))
6310 return (srcLaneSize % 16 != 0) || (dstLaneSize % 16 != 0);
6314 target.addDynamicallyLegalOp<arith::ExtSIOp>([](arith::ExtSIOp extsiOp) {
6315 auto srcType = dyn_cast<VectorType>(extsiOp.getIn().getType());
6316 auto dstType = dyn_cast<VectorType>(extsiOp.getOut().getType());
6317 if (!srcType || !dstType)
6320 Type srcScalarType = srcType.getElementType();
6321 Type dstScalarType = dstType.getElementType();
6322 if (!isa<IntegerType>(srcScalarType) || !isa<IntegerType>(dstScalarType))
6327 return (srcLaneSize % 16 != 0) || (dstLaneSize % 16 != 0);
6331 target.addDynamicallyLegalOp<arith::TruncIOp>([](arith::TruncIOp trunciOp) {
6332 auto srcType = dyn_cast<VectorType>(trunciOp.getIn().getType());
6333 auto dstType = dyn_cast<VectorType>(trunciOp.getOut().getType());
6334 if (!srcType || !dstType) {
6336 return !(!srcType && !dstType && isSRSCompoundCandidate(trunciOp));
6338 Type srcScalarType = srcType.getElementType();
6339 Type dstScalarType = dstType.getElementType();
6340 if (!isa<IntegerType>(srcScalarType) || !isa<IntegerType>(dstScalarType))
6345 if (isSRSCompoundCandidate(trunciOp))
6350 return (srcLaneSize % 16 != 0) || (dstLaneSize % 16 != 0);
6355 target.addDynamicallyLegalOp<arith::AddFOp>([](arith::AddFOp op) {
6356 auto resultType = dyn_cast<VectorType>(op.getType());
6360 Type scalarType = resultType.getElementType();
6363 if (scalarType.isBF16() || scalarType.isF32())
6364 return !isAIE2PNativeWidth(op);
6367 if (isa<FloatType>(scalarType))
6368 return laneSize != 16 && laneSize != 32;
6371 return laneSize != 16;
6376 target.addDynamicallyLegalOp<arith::SubFOp>([](arith::SubFOp op) {
6377 auto resultType = dyn_cast<VectorType>(op.getType());
6381 Type scalarType = resultType.getElementType();
6384 if (scalarType.isBF16() || scalarType.isF32())
6385 return !isAIE2PNativeWidth(op);
6388 if (isa<FloatType>(scalarType))
6389 return laneSize != 16 && laneSize != 32;
6392 return laneSize != 16;
6397 target.addDynamicallyLegalOp<arith::NegFOp>([](arith::NegFOp negOp) {
6398 auto srcType = dyn_cast<VectorType>(negOp.getOperand().getType());
6402 Type scalarType = srcType.getElementType();
6408 if (!scalarType.isBF16() && !scalarType.isF32())
6419 return laneSize != 32 || srcType.getRank() != 1;
6426 target.addDynamicallyLegalOp<arith::MulFOp>([](arith::MulFOp op) {
6427 auto resultType = dyn_cast<VectorType>(op.getType());
6431 auto isAddOp = [](Operation *user) {
return isa<arith::AddFOp>(user); };
6432 if (resultType.getRank() == 1 && op->hasOneUse() &&
6433 llvm::any_of(op->getUsers(), isAddOp) &&
6434 !(holdsBF16(op.getLhs()) && holdsBF16(op.getRhs())))
6437 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6440 if (laneSize == 16 && (resultElWidth == 16 || resultElWidth == 32))
6442 if (laneSize == 32 && resultElWidth == 16)
6444 if ((laneSize == 32 || laneSize == 64) && resultElWidth == 32 &&
6445 resultType.getRank() == 1 && holdsBF16(op.getLhs()) &&
6446 holdsBF16(op.getRhs()))
6459static void configureAIEVecV2Legalizations(ConversionTarget &target) {
6460 target.addLegalOp<UnrealizedConversionCastOp>();
6461 target.addLegalOp<vector::ShapeCastOp>();
6464 llvm::SmallSet<std::pair<unsigned, unsigned>, 16> laneSizeElWidthPairSet;
6465 laneSizeElWidthPairSet.insert({64, 8});
6466 laneSizeElWidthPairSet.insert({32, 16});
6467 laneSizeElWidthPairSet.insert({16, 32});
6468 laneSizeElWidthPairSet.insert({32, 32});
6471 llvm::SmallSet<unsigned, 16> elWidthSet;
6472 elWidthSet.insert(8);
6473 elWidthSet.insert(16);
6474 elWidthSet.insert(32);
6476 target.addDynamicallyLegalOp<arith::AddFOp>([](arith::AddFOp op) {
6477 auto resultType = dyn_cast<VectorType>(op.getType());
6481 Type scalarType = resultType.getElementType();
6483 unsigned resultElWidth = scalarType.getIntOrFloatBitWidth();
6489 if (laneSize == 32 && resultElWidth == 16)
6492 if (laneSize == 32 && resultElWidth == 32)
6498 target.addDynamicallyLegalOp<arith::SubFOp>([](arith::SubFOp op) {
6499 auto resultType = dyn_cast<VectorType>(op.getType());
6503 Type scalarType = resultType.getElementType();
6505 unsigned resultElWidth = scalarType.getIntOrFloatBitWidth();
6511 if (laneSize == 32 && resultElWidth == 16)
6514 if (laneSize == 32 && resultElWidth == 32)
6520 target.addDynamicallyLegalOp<arith::MulIOp>([](arith::MulIOp op) {
6521 auto resultType = dyn_cast<VectorType>(op.getType());
6524 auto isAddOp = [&](Operation *op) {
return isa<arith::AddIOp>(op); };
6526 if (op->hasOneUse() && llvm::any_of(op->getUsers(), isAddOp))
6529 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6532 return (laneSize != 32 || (resultElWidth != 16 && resultElWidth != 8)) &&
6533 ((laneSize != 16 && laneSize != 32) || resultElWidth != 32);
6536 target.addDynamicallyLegalOp<arith::MulFOp>([](arith::MulFOp op) {
6537 auto resultType = dyn_cast<VectorType>(op.getType());
6541 auto isAddOp = [&](Operation *op) {
return isa<arith::AddFOp>(op); };
6543 if (op->hasOneUse() && llvm::any_of(op->getUsers(), isAddOp) &&
6544 !(holdsBF16(op.getLhs()) && holdsBF16(op.getRhs())))
6547 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6551 if (laneSize == 16 && (resultElWidth == 16 || resultElWidth == 32))
6553 if (laneSize == 32 && resultElWidth == 16)
6555 if (laneSize == 32 && resultElWidth == 32 && holdsBF16(op.getLhs()) &&
6556 holdsBF16(op.getRhs()))
6562 target.addDynamicallyLegalOp<arith::MinSIOp>([=](arith::MinSIOp op) {
6563 auto resultType = dyn_cast<VectorType>(op.getType());
6566 if (
auto intType = dyn_cast<IntegerType>(op.getType())) {
6567 unsigned w = intType.getWidth();
6568 if (w == 8 || w == 16 || w == 32) {
6571 return scalarClampInCompoundSRS(op);
6577 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6580 return !elWidthSet.count(resultElWidth) || laneSize * resultElWidth != 512;
6583 target.addDynamicallyLegalOp<arith::MaxSIOp>([=](arith::MaxSIOp op) {
6584 auto resultType = dyn_cast<VectorType>(op.getType());
6587 if (
auto intType = dyn_cast<IntegerType>(op.getType())) {
6588 unsigned w = intType.getWidth();
6589 if (w == 8 || w == 16 || w == 32) {
6592 return scalarClampInCompoundSRS(op);
6598 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6601 return !elWidthSet.count(resultElWidth) || laneSize * resultElWidth != 512;
6604 target.addDynamicallyLegalOp<arith::MinUIOp>([=](arith::MinUIOp op) {
6605 auto resultType = dyn_cast<VectorType>(op.getType());
6609 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6611 unsigned totalBits = laneSize * resultElWidth;
6613 return !elWidthSet.count(resultElWidth) ||
6614 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16));
6617 target.addDynamicallyLegalOp<arith::MaxUIOp>([=](arith::MaxUIOp op) {
6618 auto resultType = dyn_cast<VectorType>(op.getType());
6622 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6624 unsigned totalBits = laneSize * resultElWidth;
6626 return !elWidthSet.count(resultElWidth) ||
6627 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16));
6630 target.addDynamicallyLegalOp<arith::MinimumFOp>([=](arith::MinimumFOp op) {
6631 auto resultType = dyn_cast<VectorType>(op.getType());
6635 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6637 unsigned totalBits = laneSize * resultElWidth;
6639 return !elWidthSet.count(resultElWidth) ||
6640 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16));
6643 target.addDynamicallyLegalOp<arith::MaximumFOp>([=](arith::MaximumFOp op) {
6644 auto resultType = dyn_cast<VectorType>(op.getType());
6648 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6650 unsigned totalBits = laneSize * resultElWidth;
6652 return !elWidthSet.count(resultElWidth) ||
6653 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16));
6656 target.addDynamicallyLegalOp<arith::MaxNumFOp>([=](arith::MaxNumFOp op) {
6657 auto resultType = dyn_cast<VectorType>(op.getType());
6661 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6663 unsigned totalBits = laneSize * resultElWidth;
6665 return !elWidthSet.count(resultElWidth) ||
6666 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16));
6669 target.addDynamicallyLegalOp<arith::MinNumFOp>([=](arith::MinNumFOp op) {
6670 auto resultType = dyn_cast<VectorType>(op.getType());
6674 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6676 unsigned totalBits = laneSize * resultElWidth;
6678 return !elWidthSet.count(resultElWidth) ||
6679 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16));
6682 target.addDynamicallyLegalOp<arith::CmpIOp>([=](arith::CmpIOp op) {
6683 auto lhsType = dyn_cast<VectorType>(op.getLhs().getType());
6687 auto lhsElWidth = lhsType.getElementType().getIntOrFloatBitWidth();
6689 unsigned totalBits = laneSize * lhsElWidth;
6691 return !elWidthSet.count(lhsElWidth) ||
6692 (totalBits != 512 && (totalBits != 256 || lhsElWidth != 16));
6695 target.addDynamicallyLegalOp<arith::CmpFOp>([=](arith::CmpFOp op) {
6696 auto lhsType = dyn_cast<VectorType>(op.getLhs().getType());
6700 auto lhsElWidth = lhsType.getElementType().getIntOrFloatBitWidth();
6702 unsigned totalBits = laneSize * lhsElWidth;
6704 return !elWidthSet.count(lhsElWidth) ||
6705 (totalBits != 512 && (totalBits != 256 || lhsElWidth != 16));
6708 target.addDynamicallyLegalOp<arith::SelectOp>([=](arith::SelectOp op) {
6709 auto resultType = dyn_cast<VectorType>(op.getType());
6713 auto resultElWidth = resultType.getElementType().getIntOrFloatBitWidth();
6715 unsigned totalBits = laneSize * resultElWidth;
6717 return !elWidthSet.count(resultElWidth) ||
6718 (totalBits != 512 && (totalBits != 256 || resultElWidth != 16));
6721 target.addDynamicallyLegalOp<vector::ReductionOp>(
6722 [=](vector::ReductionOp op) {
6723 if (
auto kind = op.getKind(); kind != vector::CombiningKind::ADD &&
6724 kind != vector::CombiningKind::MINSI &&
6725 kind != vector::CombiningKind::MINUI &&
6726 kind != vector::CombiningKind::MINIMUMF &&
6727 kind != vector::CombiningKind::MINNUMF &&
6728 kind != vector::CombiningKind::MAXSI &&
6729 kind != vector::CombiningKind::MAXUI &&
6730 kind != vector::CombiningKind::MAXIMUMF &&
6731 kind != vector::CombiningKind::MAXNUMF)
6734 auto vType = dyn_cast<VectorType>(op.getVector().getType());
6738 llvm::SmallSet<std::pair<unsigned, signed>, 16> laneSizeElWidthPairSet;
6739 laneSizeElWidthPairSet.insert({64, 8});
6740 laneSizeElWidthPairSet.insert({32, 16});
6741 laneSizeElWidthPairSet.insert({32, 32});
6742 laneSizeElWidthPairSet.insert({16, 32});
6744 Type scalarType = vType.getElementType();
6745 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6748 if (isa<IntegerType>(scalarType) &&
6749 !laneSizeElWidthPairSet.count(std::make_pair(laneSize, elWidth)))
6752 if (isa<FloatType>(scalarType) && laneSize != 16 && laneSize != 32)
6759 target.addDynamicallyLegalOp<arith::ExtFOp>([](arith::ExtFOp extfOp) {
6760 auto srcType = dyn_cast<VectorType>(extfOp.getIn().getType());
6761 auto dstType = dyn_cast<VectorType>(extfOp.getOut().getType());
6762 if (!srcType || !dstType)
6765 Type srcScalarType = srcType.getElementType();
6766 Type dstScalarType = dstType.getElementType();
6767 if (!isa<FloatType>(srcScalarType) || !isa<FloatType>(dstScalarType))
6772 return (srcLaneSize % 16 != 0) || (dstLaneSize % 16 != 0);
6776 target.addDynamicallyLegalOp<arith::TruncFOp>([](arith::TruncFOp truncfOp) {
6777 auto srcType = dyn_cast<VectorType>(truncfOp.getIn().getType());
6778 auto dstType = dyn_cast<VectorType>(truncfOp.getOut().getType());
6779 if (!srcType || !dstType)
6782 Type srcScalarType = srcType.getElementType();
6783 Type dstScalarType = dstType.getElementType();
6784 if (!isa<FloatType>(srcScalarType) || !isa<FloatType>(dstScalarType))
6789 return (srcLaneSize % 16 != 0) || (dstLaneSize % 16 != 0);
6793 target.addDynamicallyLegalOp<arith::ExtSIOp>([](arith::ExtSIOp extsiOp) {
6794 auto srcType = dyn_cast<VectorType>(extsiOp.getIn().getType());
6795 auto dstType = dyn_cast<VectorType>(extsiOp.getOut().getType());
6796 if (!srcType || !dstType)
6799 Type srcScalarType = srcType.getElementType();
6800 Type dstScalarType = dstType.getElementType();
6801 if (!isa<IntegerType>(srcScalarType) || !isa<IntegerType>(dstScalarType))
6806 return (srcLaneSize % 16 != 0) || (dstLaneSize % 16 != 0);
6810 target.addDynamicallyLegalOp<arith::TruncIOp>([](arith::TruncIOp trunciOp) {
6811 auto srcType = dyn_cast<VectorType>(trunciOp.getIn().getType());
6812 auto dstType = dyn_cast<VectorType>(trunciOp.getOut().getType());
6813 if (!srcType || !dstType) {
6815 return !(!srcType && !dstType && isSRSCompoundCandidate(trunciOp));
6817 Type srcScalarType = srcType.getElementType();
6818 Type dstScalarType = dstType.getElementType();
6819 if (!isa<IntegerType>(srcScalarType) || !isa<IntegerType>(dstScalarType))
6824 if (isSRSCompoundCandidate(trunciOp))
6829 return (srcLaneSize % 16 != 0) || (dstLaneSize % 16 != 0);
6832 target.addIllegalOp<vector::ContractionOp, vector::TransposeOp,
6837 target.addDynamicallyLegalOp<math::ExpOp>([](math::ExpOp expOp) {
6838 auto srcType = dyn_cast<VectorType>(expOp.getOperand().getType());
6842 Type scalarType = srcType.getElementType();
6843 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6846 if (!isa<FloatType>(scalarType) || (laneSize != 16 && laneSize != 32) ||
6849 if (expOp->hasOneUse() && isInSigmoidOperationChain(expOp))
6855 target.addDynamicallyLegalOp<math::RsqrtOp>([](math::RsqrtOp rsqrtOp) {
6856 auto srcType = dyn_cast<VectorType>(rsqrtOp.getOperand().getType());
6860 Type scalarType = srcType.getElementType();
6861 if (!isa<FloatType>(scalarType))
6865 unsigned elWidth = scalarType.getIntOrFloatBitWidth();
6866 return elWidth != 16 || (laneSize != 16 && laneSize != 32);
6889 StringRef
getArgument() const final {
return "test-lower-vector-to-aievec"; }
6891 return "Lower vector operations to AIE vector intrinsics";
6895 affine::AffineDialect, xilinx::aievec::aie1::AIEVecAIE1Dialect,
6896 xilinx::aievec::AIEVecDialect, arith::ArithDialect,
6897 memref::MemRefDialect, scf::SCFDialect, ub::UBDialect,
6898 vector::VectorDialect, emitc::EmitCDialect, xilinx::AIE::AIEDialect>();
6902 *
this,
"aie-target",
6904 "Select AIE version: \"aie\", \"aie2\", or \"aie2p\". This will "
6905 "determine the vector size and available operations."),
6906 llvm::cl::init(
"aie")};
6909 auto *op = getOperation();
6910 MLIRContext *context = &getContext();
6911 RewritePatternSet patterns(context);
6912 ConversionTarget target(*context);
6919 target.addLegalOp<xilinx::AIE::RuntimeSequenceOp>();
6920 target.markOpRecursivelyLegal<xilinx::AIE::RuntimeSequenceOp>();
6925 if (targetStr ==
"aieml" || targetStr ==
"aie2")
6927 else if (targetStr ==
"aie2p")
6929 else if (targetStr !=
"aie") {
6930 op->emitError() <<
"unknown AIE target '" <<
aieTarget <<
"'";
6931 return signalPassFailure();
6935 populateAIEVecCommonConversionPatterns(patterns);
6936 configureAIEVecCommonLegalizations(target);
6938 populateAIEVecV1ConversionPatterns(patterns);
6939 configureAIEVecV1Legalizations(target);
6941 populateAIEVecV2ConversionPatterns(patterns);
6942 configureAIEVecV2Legalizations(target);
6944 auto planner = std::make_shared<AIE2PShufflePlanner>();
6945 populateAIEVecV2PConversionPatterns(patterns, planner);
6946 configureAIEVecV2Legalizations(target);
6947 configureAIEVecV2PLegalizations(target, planner);
6951 llvm_unreachable(
"AIE version is misconfigured");
6954 if (failed(applyPartialConversion(op, target, std::move(patterns))))
6955 return signalPassFailure();
6959static std::unique_ptr<Pass>
6961 return std::make_unique<LowerVectorToAIEVec>(options);
6975 MLIRContext *context = &getContext();
6976 RewritePatternSet patterns(context);
6977 ConversionTarget target(*context);
6979 target.addLegalDialect<aievec::AIEVecDialect>();
6980 target.addDynamicallyLegalOp<aievec::UPDOp>([](aievec::UPDOp op) {
6981 return op.getVector() ||
6982 (op->hasOneUse() && isa<aievec::UPDOp>(*op->getUsers().begin())) ||
6983 llvm::all_of(op->getUsers(),
6984 [](Operation *op) { return isa<aievec::ExtOp>(op); });
6987 if (
auto *op = getOperation();
6988 failed(applyPartialConversion(op, target, std::move(patterns)))) {
6989 return signalPassFailure();
7002 MLIRContext *context = &getContext();
7003 RewritePatternSet patterns(context);
7004 ConversionTarget target(*context);
7006 target.addLegalDialect<aievec::AIEVecDialect>();
7007 target.addDynamicallyLegalOp<aievec::ExtOp>([](aievec::ExtOp op) {
7008 auto *defOp = op.getSource().getDefiningOp();
7009 return !defOp || !isa<aievec::UPDOp>(defOp) || !defOp->hasOneUse() ||
7013 if (
auto *op = getOperation();
7014 failed(applyPartialConversion(op, target, std::move(patterns)))) {
7015 return signalPassFailure();
7027 pm.addPass(createLowerVectorToAIEVec(options));
7028 pm.addPass(createCanonicalizerPass());
7031 pm.addPass(std::make_unique<ExtendUPDOpsPass>());
7032 pm.addPass(createCSEPass());
7033 pm.addPass(std::make_unique<SimplifyUPDOpsPass>());
7034 pm.addPass(createCanonicalizerPass());
LowerVectorAddOrSubOpToAIEVecAddElemOrSubElemOp< arith::SubFOp, aievec::SubElemOp > LowerVectorSubFOpToAIEVecSubElemOp
LowerVectorMinMaxOpToAIEVecMinMaxOp< arith::MaxNumFOp, aievec::MaxOp > LowerVectorMaxNumFFOpToAIEVecMaxOp
LowerVectorCmpOpToAIEVecCmpOp< arith::CmpIOp, CmpIPredicate > LowerVectorCmpIOpToAIEVecCmpOp
ScalarizeVectorIntFpConversionOpPattern< arith::FPToUIOp > ScalarizeVectorFPToUIOpPattern
AIE2PElementwiseOps< arith::MulFOp, arith::DivFOp, arith::AddFOp, arith::SubFOp, arith::NegFOp, arith::TruncFOp, arith::ExtFOp, math::ExpOp, math::TanhOp, math::ErfOp, math::Exp2Op, arith::MaximumFOp, arith::MaxNumFOp, arith::MinimumFOp, arith::CmpFOp, arith::CmpIOp, arith::SelectOp, arith::AddIOp, arith::SubIOp, arith::MulIOp, arith::IndexCastOp > AIE2PElementwise
OneToOneVectorOpToAIEVecOpPattern< arith::SubIOp, aievec::aie1::SubOp > LowerVectorSubIOpToAIEVecSubOp
ScalarizeVectorIntFpConversionOpPattern< arith::FPToSIOp > ScalarizeVectorFPToSIOpPattern
OneToOneVectorOpToAIEVecOpPattern< arith::SubFOp, aievec::aie1::SubOp > LowerVectorSubFOpToAIEVecSubOp
LowerVectorUMinMaxOpToCmpSelOp< arith::MaxUIOp, arith::CmpIPredicate::ugt > LowerVectorMaxUIOpToCmpSelOp
ScalarizeVectorIntFpConversionOpPattern< arith::UIToFPOp > ScalarizeVectorUIToFPOpPattern
LowerVectorMinMaxOpToAIEVecMinMaxOp< arith::MaxSIOp, aievec::MaxOp > LowerVectorMaxSIOpToAIEVecMaxOp
LowerScalarMinMaxToAIEVecMinMaxOp< arith::MinSIOp, aievec::MinOp > LowerScalarMinSIOpToAIEVecMinOp
LowerVectorContractionOpToAIEVecMatMulPattern< aievec::MatMulOp_AIE2P > LowerVectorContractionOpToAIEVecMatMulOpAIE2P
OneToOneVectorOpToAIEVecOpPattern< arith::AddFOp, aievec::aie1::AddOp > LowerVectorAddFOpToAIEVecAddOp
ComputeAbsOpPattern< math::AbsIOp > ComputeAbsIOpPattern
constexpr int64_t kAIE2PMaxParts
LowerTruncOpPattern< arith::TruncFOp > LowerTruncFOpPattern
ScalarizeVectorIntFpConversionOpPattern< arith::SIToFPOp > ScalarizeVectorSIToFPOpPattern
ComputeBandAndBorOpPattern< arith::OrIOp, aievec::BorOp > ComputeBorOpPattern
LowerVectorAddOrSubOpToAIEVecAddElemOrSubElemOp< arith::AddFOp, aievec::AddElemOp > LowerVectorAddFOpToAIEVecAddElemOp
LowerExtOpPattern< arith::ExtFOp > LowerExtFOpPattern
OneToOneVectorOpToAIEVecOpPattern< arith::MulFOp, aievec::aie1::MulOp > LowerVectorMulFOpToAIEVecMulOp
ComputeAbsOpPattern< math::AbsFOp > ComputeAbsFOpPattern
LowerVectorAddOrSubOpToAIEVecAddElemOrSubElemOp< arith::SubIOp, aievec::SubElemOp > LowerVectorSubIOpToAIEVecSubElemOp
LowerVectorUMinMaxOpToCmpSelOp< arith::MinUIOp, arith::CmpIPredicate::ult > LowerVectorMinUIOpToCmpSelOp
ComputeBandAndBorOpPattern< arith::AndIOp, aievec::BandOp > ComputeBandOpPattern
LowerVectorContractionOpToAIEVecMatMulPattern< aievec::MatMulOp > LowerVectorContractionOpToAIEVecMatMulOpAIE2
LowerVectorMinMaxOpToAIEVecMinMaxOp< arith::MinimumFOp, aievec::MinOp > LowerVectorMinimumFOpToAIEVecMinOp
LowerVectorCmpOpToAIEVecCmpOp< arith::CmpFOp, CmpFPredicate > LowerVectorCmpFOpToAIEVecCmpOp
LowerTruncOpPattern< arith::TruncIOp > LowerTruncIOpPattern
LowerExtOpPattern< arith::ExtSIOp > LowerExtSIOpPattern
LowerVectorAddOrSubOpToAIEVecAddElemOrSubElemOp< arith::AddIOp, aievec::AddElemOp > LowerVectorAddIOpToAIEVecAddElemOp
LowerVectorMinMaxOpToAIEVecMinMaxOp< arith::MaximumFOp, aievec::MaxOp > LowerVectorMaximumFOpToAIEVecMaxOp
LowerScalarMinMaxToAIEVecMinMaxOp< arith::MaxSIOp, aievec::MaxOp > LowerScalarMaxSIOpToAIEVecMaxOp
LowerVectorMinMaxOpToAIEVecMinMaxOp< arith::MinSIOp, aievec::MinOp > LowerVectorMinSIOpToAIEVecMinOp
mlir::VectorType getFlattenedVectorType(mlir::VectorType vecTy)
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)
SmallVector< NamedAttribute > buildFMAOpSplatAttrForElemTy(aievec::aie1::FMAOp fmaOp, int64_t bcastPos, int64_t step=1)
std::optional< int64_t > getTransferReadAlignmentOffset(TransferReadLikeOp readOp, mlir::VectorType vType, int64_t alignment)
void populateAIE2PShufflePlannerPatterns(mlir::RewritePatternSet &patterns, std::shared_ptr< AIE2PShufflePlanner > planner)
mlir::VectorType createVectorType(unsigned lanes, mlir::Type elementType)
int32_t getElementSizeInBits(mlir::VectorType type)
void buildLowerVectorToAIEVec(mlir::OpPassManager &pm, const LowerVectorToAIEVecOptions &options)
mlir::VectorType getVectorOpDestType(mlir::VectorType type, bool AIE2)
void configureAIE2PShufflePlannerLegality(mlir::ConversionTarget &target, std::shared_ptr< AIE2PShufflePlanner > planner)
static void markIllegal(ConversionTarget &target, MLIRContext *ctx)
static void addPatterns(RewritePatternSet &patterns, PatternBenefit benefit)
static void markIllegal(ConversionTarget &target, MLIRContext *ctx)
LogicalResult matchAndRewrite(SrcOpTy absOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(SrcOpTy srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(arith::XOrIOp xorOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::CeilOp ceilOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::ErfOp erfOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::ErfOp erfOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::ExpOp expOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::ExpOp expOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::FloorOp floorOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::NegFOp negOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(OpTy op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename OpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(math::RsqrtOp rsqrtOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::RsqrtOp rsqrtOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(OpTy op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename OpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(arith::DivFOp divfOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::ShRSIOp rsOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::SqrtOp sqrtOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::TanhOp tanhOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::DivFOp divOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(math::ExpOp expOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename MathOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(MathOpTy op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::AddFOp addOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
ConvertMulAddFToAIEVecFMAElemOpPattern(MLIRContext *context, unsigned shiftParam=0)
LogicalResult matchAndRewrite(arith::AddIOp addOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
ConvertMulAddToAIEVecFMAElemOpPattern(MLIRContext *context, unsigned shiftParam=0)
LogicalResult matchAndRewrite(aievec::aie1::AddOp addOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::MulFOp mulOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::MulFOp mulOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
ConvertMulFToAIEVecMulElemOpPattern(MLIRContext *context, unsigned shiftParam=0)
LogicalResult matchAndRewrite(arith::MulIOp mulOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
ConvertMulIToAIEVecMulElemOpPattern(MLIRContext *context, unsigned shiftParam=0)
LogicalResult matchAndRewrite(vector::BroadcastOp bcastOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::BroadcastOp bcastOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::FMAOp fmaOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::FMAOp fmaOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
ConvertVectorFMAOpToAIEVecFMAElemOpPattern(MLIRContext *context, unsigned shiftParam=0)
ExpandUPDToUPDAndExtPattern(MLIRContext *context)
LogicalResult matchAndRewrite(aievec::UPDOp updOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
void runOnOperation() override
typename OpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(OpTy op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(aievec::aie1::FMAOp fmaOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::BroadcastOp bcastOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(aievec::ExtOp extOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
FuseExtIntoUPDPattern(MLIRContext *context)
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(SrcOpTy extOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::ExtUIOp extOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(SrcOpTy srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::ShRSIOp rsOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::TruncIOp truncOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
static std::optional< int64_t > getScalarConstantValue(Value val)
LogicalResult matchAndRewrite(SrcOpTy truncOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(arith::AddIOp addOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(SrcOpTy srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(SrcOpTy srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
static Value reshape(OpBuilder &b, Value v, ArrayRef< int64_t > shape)
LogicalResult matchAndRewrite(vector::ContractionOp contractOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
static constexpr bool isAIE2P
LogicalResult matchAndRewrite(SrcOpTy srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(arith::MulIOp mulOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::ReductionOp srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::ReductionOp srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::ReductionOp srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::ReductionOp srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::ReductionOp srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(vector::ReductionOp srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
static Value emitMagicSiToFp(ConversionPatternRewriter &rewriter, Location loc, Value srcI16, unsigned lanes)
LogicalResult matchAndRewrite(arith::SIToFPOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(arith::SelectOp srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
void getDependentDialects(DialectRegistry ®istry) const override
LowerVectorToAIEVec(const LowerVectorToAIEVecOptions &options)
void runOnOperation() override
StringRef getDescription() const final
Option< std::string > aieTarget
LowerVectorToAIEVec()=default
StringRef getArgument() const final
LogicalResult matchAndRewrite(vector::TransferReadOp readOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LowerVectorTransferReadToAIEUPD(MLIRContext *context, int64_t minVectorSize, int64_t maxVectorSize, int64_t alignment, int64_t maxLoadSize)
LogicalResult matchAndRewrite(vector::TransposeOp transpOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(SrcOpTy srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename OpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(OpTy op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(SrcOpTy srcOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
typename SrcOpTy::Adaptor OpAdaptor
LogicalResult matchAndRewrite(SrcOpTy op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
ShiftClampTruncToSRSPattern(MLIRContext *context, PatternBenefit benefit=2)
static std::optional< Value > getShiftValue(Value rhs, ConversionPatternRewriter &rewriter, Location loc)
static std::optional< int64_t > getConstantSplatValue(Value val)
LogicalResult matchAndRewrite(arith::TruncIOp truncOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
void runOnOperation() override
Options for the "lower-vector-to-aievec" pipeline.
PassOptions::Option< std::string > aieTarget