18#include "llvm/ADT/MapVector.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/Support/DebugLog.h"
21#include "llvm/Support/InterleavedRange.h"
24#define DEBUG_TYPE "vector-unroll"
34 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr))
35 return constExpr.getValue() == 0;
40 for (
const auto &dim : llvm::enumerate(permutationMap.
getResults())) {
41 int64_t elementOffset = elementOffsets[dim.index()];
42 if (isBroadcast(dim.value()) || elementOffset == 0)
44 unsigned pos = cast<AffineDimExpr>(dim.value()).getPosition();
49 affine::AffineApplyOp::create(builder, loc, map,
indices[pos]);
61 assert(offsets.size() <= originalIndices.size() &&
62 "Offsets should not exceed the number of original indices");
65 auto start =
indices.size() - offsets.size();
66 for (
auto [i, offset] : llvm::enumerate(offsets)) {
68 indices[start + i] = arith::AddIOp::create(
69 rewriter, loc, originalIndices[start + i],
85 return builder.
create(state);
90static std::optional<SmallVector<int64_t>>
93 if (
options.filterConstraint && failed(
options.filterConstraint(op))) {
94 LDBG() <<
"--no filter constraint -> BAIL";
99 auto maskableOp = dyn_cast<vector::MaskableOpInterface>(op);
100 if (maskableOp && maskableOp.isMasked()) {
101 LDBG() <<
"--op is masked -> BAIL";
105 "vector unrolling expects the native shape or native"
106 "shape call back function to be set");
107 auto unrollableVectorOp = dyn_cast<VectorUnrollOpInterface>(op);
108 if (!unrollableVectorOp) {
109 LDBG() <<
"--not an unrollable op -> BAIL";
112 auto maybeUnrollShape = unrollableVectorOp.getIterationShapeToUnroll();
113 if (!maybeUnrollShape) {
114 LDBG() <<
"--could not get shape of op " << *op <<
" -> BAIL";
117 LDBG() <<
"--vector op shape: " << llvm::interleaved(*maybeUnrollShape);
119 std::optional<SmallVector<int64_t>> targetShape =
options.nativeShape(op);
121 LDBG() <<
"--no unrolling target shape defined " << *op <<
"-> SKIP";
124 LDBG() <<
"--target shape: " << llvm::interleaved(*targetShape);
127 if (!maybeShapeRatio) {
128 LDBG() <<
"--could not compute integral shape ratio -> BAIL";
131 if (llvm::all_of(*maybeShapeRatio, [](
int64_t v) {
return v == 1; })) {
132 LDBG() <<
"--no unrolling needed -> SKIP";
135 LDBG() <<
"--found an integral shape ratio to unroll to -> SUCCESS";
143 llvm::to_vector(llvm::seq<int64_t>(0,
static_cast<int64_t>(numLoops)));
144 if (
options.traversalOrderCallback !=
nullptr) {
145 std::optional<SmallVector<int64_t>> order =
146 options.traversalOrderCallback(op);
148 loopOrder = std::move(*order);
156struct UnrollTransferReadPattern
158 UnrollTransferReadPattern(MLIRContext *context,
159 const vector::UnrollVectorOptions &options,
160 PatternBenefit benefit = 1)
161 : OpRewritePattern<vector::TransferReadOp>(context, benefit),
164 LogicalResult matchAndRewrite(vector::TransferReadOp readOp,
165 PatternRewriter &rewriter)
const override {
167 if (readOp.getTransferRank() == 0)
169 if (readOp.getMask())
174 auto sourceVectorType = readOp.getVectorType();
175 SmallVector<int64_t> strides(targetShape->size(), 1);
176 Location loc = readOp.getLoc();
177 ArrayRef<int64_t> originalSize = sourceVectorType.getShape();
181 arith::ConstantOp::create(rewriter, loc, sourceVectorType,
184 VectorType::get(*targetShape, sourceVectorType.getElementType());
185 SmallVector<Value> originalIndices(readOp.getIndices().begin(),
186 readOp.getIndices().end());
187 SmallVector<int64_t> loopOrder =
189 for (SmallVector<int64_t> elementOffsets :
190 StaticTileOffsetRange(originalSize, *targetShape, loopOrder)) {
192 sliceTransferIndices(elementOffsets, originalIndices,
193 readOp.getPermutationMap(), loc, rewriter);
194 auto slicedRead = vector::TransferReadOp::create(
195 rewriter, loc, targetType, readOp.getBase(),
indices,
196 readOp.getPermutationMapAttr(), readOp.getPadding(), readOp.getMask(),
197 readOp.getInBoundsAttr());
200 loc, slicedRead,
result, elementOffsets, strides);
207 vector::UnrollVectorOptions options;
210struct UnrollTransferWritePattern
212 UnrollTransferWritePattern(MLIRContext *context,
213 const vector::UnrollVectorOptions &options,
214 PatternBenefit benefit = 1)
215 : OpRewritePattern<vector::TransferWriteOp>(context, benefit),
218 LogicalResult matchAndRewrite(vector::TransferWriteOp writeOp,
219 PatternRewriter &rewriter)
const override {
221 if (writeOp.getTransferRank() == 0)
224 if (writeOp.getMask())
229 auto sourceVectorType = writeOp.getVectorType();
230 SmallVector<int64_t> strides(targetShape->size(), 1);
231 Location loc = writeOp.getLoc();
232 ArrayRef<int64_t> originalSize = sourceVectorType.getShape();
236 if (originalSize.size() != targetShape->size())
239 "expected source input vector rank to match target shape rank");
241 SmallVector<Value> originalIndices(writeOp.getIndices().begin(),
242 writeOp.getIndices().end());
243 SmallVector<int64_t> loopOrder =
246 for (SmallVector<int64_t> elementOffsets :
247 StaticTileOffsetRange(originalSize, *targetShape, loopOrder)) {
248 Value slicedVector = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
249 loc, writeOp.getVector(), elementOffsets, *targetShape, strides);
251 sliceTransferIndices(elementOffsets, originalIndices,
252 writeOp.getPermutationMap(), loc, rewriter);
253 Operation *slicedWrite = vector::TransferWriteOp::create(
254 rewriter, loc, slicedVector,
255 resultTensor ? resultTensor : writeOp.getBase(),
indices,
256 writeOp.getPermutationMapAttr(), writeOp.getInBoundsAttr());
259 resultTensor = slicedWrite->
getResult(0);
262 rewriter.
replaceOp(writeOp, resultTensor);
269 vector::UnrollVectorOptions options;
272struct OffsetMapInfo {
273 static unsigned getHashValue(
const SmallVector<int64_t> &v) {
274 return static_cast<unsigned>(llvm::hash_combine_range(v));
277 static bool isEqual(
const SmallVector<int64_t> &
lhs,
278 const SmallVector<int64_t> &
rhs) {
283struct UnrollContractionPattern
285 UnrollContractionPattern(MLIRContext *context,
286 const vector::UnrollVectorOptions &options,
287 PatternBenefit benefit = 1)
288 : OpRewritePattern<vector::ContractionOp>(context, benefit),
291 LogicalResult matchAndRewrite(vector::ContractionOp contractOp,
292 PatternRewriter &rewriter)
const override {
296 auto dstVecType = cast<VectorType>(contractOp.getResultType());
297 SmallVector<int64_t> originalSize = *contractOp.getIterationShapeToUnroll();
299 Location loc = contractOp.getLoc();
300 unsigned accIndex = vector::ContractionOp::getAccOperandIndex();
301 AffineMap dstAffineMap = contractOp.getIndexingMapsArray()[accIndex];
303 SmallVector<int64_t>, Value,
304 llvm::DenseMap<SmallVector<int64_t>, unsigned, OffsetMapInfo>>
308 contractOp.getIteratorTypes().size(), contractOp, options);
310 for (SmallVector<int64_t> offsets :
311 StaticTileOffsetRange(originalSize, *targetShape, loopOrder)) {
312 SmallVector<Value> slicesOperands(contractOp.getNumOperands());
315 auto extractOperand = [&](
unsigned index, Value operand,
316 AffineMap permutationMap,
317 ArrayRef<int64_t> operandOffets) {
319 permutationMap, ArrayRef<int64_t>(*targetShape));
320 SmallVector<int64_t> operandStrides(operandOffets.size(), 1);
321 slicesOperands[index] =
323 loc, operand, operandOffets, operandShape, operandStrides);
327 AffineMap lhsPermutationMap = contractOp.getIndexingMapsArray()[0];
328 SmallVector<int64_t> lhsOffets =
330 extractOperand(0, contractOp.getLhs(), lhsPermutationMap, lhsOffets);
333 AffineMap rhsPermutationMap = contractOp.getIndexingMapsArray()[1];
334 SmallVector<int64_t> rhsOffets =
336 extractOperand(1, contractOp.getRhs(), rhsPermutationMap, rhsOffets);
338 AffineMap accPermutationMap = contractOp.getIndexingMapsArray()[2];
339 SmallVector<int64_t> accOffets =
343 auto *accIt = accCache.find(accOffets);
344 if (accIt != accCache.end())
345 slicesOperands[2] = accIt->second;
347 extractOperand(2, contractOp.getAcc(), accPermutationMap, accOffets);
349 SmallVector<int64_t> dstShape =
351 auto targetType = VectorType::get(dstShape, dstVecType.getElementType());
353 rewriter, loc, contractOp, slicesOperands, targetType);
355 SmallVector<int64_t> dstOffets =
359 accCache[dstOffets] = newOp->
getResult(0);
362 Value
result = arith::ConstantOp::create(rewriter, loc, dstVecType,
364 for (
const auto &it : accCache) {
365 SmallVector<int64_t> dstStrides(it.first.size(), 1);
367 loc, it.second,
result, it.first, dstStrides);
374 vector::UnrollVectorOptions options;
377struct UnrollMultiReductionPattern
379 UnrollMultiReductionPattern(MLIRContext *context,
380 const vector::UnrollVectorOptions &options,
381 PatternBenefit benefit = 1)
382 : OpRewritePattern<vector::MultiDimReductionOp>(context, benefit),
385 LogicalResult matchAndRewrite(vector::MultiDimReductionOp reductionOp,
386 PatternRewriter &rewriter)
const override {
387 std::optional<SmallVector<int64_t>> targetShape =
391 SmallVector<int64_t> originalSize =
392 *reductionOp.getIterationShapeToUnroll();
393 Location loc = reductionOp.getLoc();
394 auto resultType = reductionOp->getResult(0).getType();
399 SmallVector<int64_t> adjustedTargetShape(originalSize.size(), 1);
400 llvm::copy(*targetShape, adjustedTargetShape.end() - targetShape->size());
405 if (resultType.isIntOrFloat()) {
406 Value accumulator = reductionOp.getAcc();
407 for (SmallVector<int64_t> offsets :
408 StaticTileOffsetRange(originalSize, adjustedTargetShape)) {
409 SmallVector<int64_t> operandStrides(offsets.size(), 1);
410 Value slicedOperand =
412 loc, reductionOp.getSource(), offsets, adjustedTargetShape,
415 rewriter, loc, reductionOp, {slicedOperand, accumulator},
419 rewriter.
replaceOp(reductionOp, accumulator);
425 SmallVector<int64_t>, Value,
426 llvm::DenseMap<SmallVector<int64_t>, unsigned, OffsetMapInfo>>
431 for (SmallVector<int64_t> offsets :
432 StaticTileOffsetRange(originalSize, adjustedTargetShape)) {
433 SmallVector<Value> operands;
434 SmallVector<int64_t> operandStrides(offsets.size(), 1);
435 Value slicedOperand =
437 loc, reductionOp.getSource(), offsets, adjustedTargetShape,
439 operands.push_back(slicedOperand);
440 SmallVector<int64_t> dstShape;
441 SmallVector<int64_t> destOffset;
442 for (
size_t i : llvm::seq(
size_t(0), adjustedTargetShape.size())) {
443 if (!reductionOp.isReducedDim(i)) {
444 destOffset.push_back(offsets[i]);
445 dstShape.push_back(adjustedTargetShape[i]);
449 SmallVector<int64_t> accStrides(destOffset.size(), 1);
452 auto *accIt = accCache.find(destOffset);
453 if (accIt != accCache.end())
456 acc = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
457 loc, reductionOp.getAcc(), destOffset, dstShape, accStrides);
458 operands.push_back(acc);
459 auto targetType = VectorType::get(
460 dstShape, reductionOp.getSourceVectorType().getElementType());
462 operands, targetType);
464 accCache[destOffset] =
result;
467 Value
result = arith::ConstantOp::create(
468 rewriter, loc, reductionOp.getDestType(),
470 for (
const auto &it : accCache) {
471 SmallVector<int64_t> dstStrides(it.first.size(), 1);
473 loc, it.second,
result, it.first, dstStrides);
480 vector::UnrollVectorOptions options;
484 UnrollElementwisePattern(MLIRContext *context,
485 const vector::UnrollVectorOptions &options,
486 PatternBenefit benefit = 1)
487 : RewritePattern(MatchAnyOpTypeTag(), benefit, context),
490 LogicalResult matchAndRewrite(Operation *op,
491 PatternRewriter &rewriter)
const override {
497 int64_t targetShapeRank = targetShape->size();
499 SmallVector<int64_t> originalSize =
500 *cast<VectorUnrollOpInterface>(op).getIterationShapeToUnroll();
501 int64_t originalShapeRank = originalSize.size();
503 Location loc = op->
getLoc();
506 SmallVector<int64_t> adjustedTargetShape(originalShapeRank);
507 int64_t rankDiff = originalShapeRank - targetShapeRank;
508 std::fill(adjustedTargetShape.begin(),
509 adjustedTargetShape.begin() + rankDiff, 1);
510 std::copy(targetShape->begin(), targetShape->end(),
511 adjustedTargetShape.begin() + rankDiff);
513 int64_t adjustedTargetShapeRank = adjustedTargetShape.size();
515 Value
result = arith::ConstantOp::create(rewriter, loc, dstVecType,
517 SmallVector<int64_t> strides(adjustedTargetShapeRank, 1);
518 VectorType unrolledVecType =
519 VectorType::get(*targetShape, dstVecType.getElementType());
522 for (SmallVector<int64_t> offsets :
523 StaticTileOffsetRange(originalSize, adjustedTargetShape)) {
524 SmallVector<Value> extractOperands;
526 auto vecType = dyn_cast<VectorType>(operand.get().getType());
528 extractOperands.push_back(operand.get());
531 Value extracted = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
532 loc, operand.get(), offsets, adjustedTargetShape, strides);
535 if (adjustedTargetShapeRank > targetShapeRank) {
537 loc, VectorType::get(*targetShape, vecType.getElementType()),
540 extractOperands.push_back(extracted);
544 rewriter, loc, op, extractOperands, unrolledVecType);
546 Value computeResult = newOp->
getResult(0);
549 SmallVector<int64_t> insertStrides =
550 (adjustedTargetShapeRank > targetShapeRank)
551 ? SmallVector<int64_t>(targetShapeRank, 1)
555 loc, computeResult,
result, offsets, insertStrides);
562 vector::UnrollVectorOptions options;
565struct UnrollReductionPattern :
public OpRewritePattern<vector::ReductionOp> {
566 UnrollReductionPattern(MLIRContext *context,
567 const vector::UnrollVectorOptions &options,
568 PatternBenefit benefit = 1)
569 : OpRewritePattern<vector::ReductionOp>(context, benefit),
572 LogicalResult matchAndRewrite(vector::ReductionOp reductionOp,
573 PatternRewriter &rewriter)
const override {
574 std::optional<SmallVector<int64_t>> targetShape =
578 SmallVector<int64_t> originalSize =
579 *reductionOp.getIterationShapeToUnroll();
582 Location loc = reductionOp.getLoc();
583 Value accumulator =
nullptr;
584 for (SmallVector<int64_t> offsets :
585 StaticTileOffsetRange(originalSize, *targetShape)) {
586 SmallVector<int64_t> strides(offsets.size(), 1);
587 Value slicedOperand =
589 loc, reductionOp.getVector(), offsets, *targetShape, strides);
591 rewriter, loc, reductionOp, slicedOperand, reductionOp.getType());
604 rewriter.
replaceOp(reductionOp, accumulator);
609 const vector::UnrollVectorOptions options;
612struct UnrollTransposePattern :
public OpRewritePattern<vector::TransposeOp> {
613 UnrollTransposePattern(MLIRContext *context,
614 const vector::UnrollVectorOptions &options,
615 PatternBenefit benefit = 1)
616 : OpRewritePattern<vector::TransposeOp>(context, benefit),
619 LogicalResult matchAndRewrite(vector::TransposeOp transposeOp,
620 PatternRewriter &rewriter)
const override {
621 if (transposeOp.getResultVectorType().getRank() == 0)
626 auto originalVectorType = transposeOp.getResultVectorType();
627 SmallVector<int64_t> strides(targetShape->size(), 1);
628 Location loc = transposeOp.getLoc();
629 ArrayRef<int64_t> originalSize = originalVectorType.getShape();
633 arith::ConstantOp::create(rewriter, loc, originalVectorType,
635 ArrayRef<int64_t> permutation = transposeOp.getPermutation();
638 for (SmallVector<int64_t> elementOffsets :
639 StaticTileOffsetRange(originalSize, *targetShape)) {
640 SmallVector<int64_t> permutedOffsets(elementOffsets.size());
641 SmallVector<int64_t> permutedShape(elementOffsets.size());
643 for (
auto indices : llvm::enumerate(permutation)) {
644 permutedOffsets[
indices.value()] = elementOffsets[
indices.index()];
647 Value slicedOperand =
649 loc, transposeOp.getVector(), permutedOffsets, permutedShape,
651 Value transposedSlice = rewriter.
createOrFold<vector::TransposeOp>(
652 loc, slicedOperand, permutation);
654 loc, transposedSlice,
result, elementOffsets, strides);
661 vector::UnrollVectorOptions options;
665 UnrollGatherPattern(MLIRContext *context,
666 const vector::UnrollVectorOptions &options,
667 PatternBenefit benefit = 1)
668 : OpRewritePattern<vector::GatherOp>(context, benefit), options(options) {
671 LogicalResult matchAndRewrite(vector::GatherOp gatherOp,
672 PatternRewriter &rewriter)
const override {
673 VectorType sourceVectorType = gatherOp.getVectorType();
674 if (sourceVectorType.getRank() == 0)
679 SmallVector<int64_t> strides(targetShape->size(), 1);
680 Location loc = gatherOp.getLoc();
681 ArrayRef<int64_t> originalSize = gatherOp.getVectorType().getShape();
685 arith::ConstantOp::create(rewriter, loc, sourceVectorType,
688 VectorType::get(*targetShape, sourceVectorType.getElementType());
690 SmallVector<int64_t> loopOrder =
692 for (SmallVector<int64_t> elementOffsets :
693 StaticTileOffsetRange(originalSize, *targetShape, loopOrder)) {
697 Value indexSubVec = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
698 loc, gatherOp.getIndices(), elementOffsets, *targetShape, strides);
699 Value maskSubVec = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
700 loc, gatherOp.getMask(), elementOffsets, *targetShape, strides);
701 Value passThruSubVec =
703 loc, gatherOp.getPassThru(), elementOffsets, *targetShape,
705 auto slicedGather = vector::GatherOp::create(
706 rewriter, loc, targetType, gatherOp.getBase(), gatherOp.getOffsets(),
707 indexSubVec, maskSubVec, passThruSubVec);
710 loc, slicedGather,
result, elementOffsets, strides);
717 vector::UnrollVectorOptions options;
721 UnrollLoadPattern(MLIRContext *context,
722 const vector::UnrollVectorOptions &options,
723 PatternBenefit benefit = 1)
724 : OpRewritePattern<vector::LoadOp>(context, benefit), options(options) {}
726 LogicalResult matchAndRewrite(vector::LoadOp loadOp,
727 PatternRewriter &rewriter)
const override {
728 VectorType vecType = loadOp.getVectorType();
734 Location loc = loadOp.getLoc();
735 ArrayRef<int64_t> originalShape = vecType.getShape();
736 SmallVector<int64_t> strides(targetShape->size(), 1);
738 Value
result = arith::ConstantOp::create(rewriter, loc, vecType,
741 SmallVector<int64_t> loopOrder =
745 VectorType::get(*targetShape, vecType.getElementType());
747 for (SmallVector<int64_t> offsets :
748 StaticTileOffsetRange(originalShape, *targetShape, loopOrder)) {
751 Value slicedLoad = vector::LoadOp::create(rewriter, loc, targetVecType,
754 loc, slicedLoad,
result, offsets, strides);
761 vector::UnrollVectorOptions options;
765 UnrollStorePattern(MLIRContext *context,
766 const vector::UnrollVectorOptions &options,
767 PatternBenefit benefit = 1)
768 : OpRewritePattern<vector::StoreOp>(context, benefit), options(options) {}
770 LogicalResult matchAndRewrite(vector::StoreOp storeOp,
771 PatternRewriter &rewriter)
const override {
772 VectorType vecType = storeOp.getVectorType();
778 Location loc = storeOp.getLoc();
779 ArrayRef<int64_t> originalShape = vecType.getShape();
780 SmallVector<int64_t> strides(targetShape->size(), 1);
782 Value base = storeOp.getBase();
783 Value vector = storeOp.getValueToStore();
785 SmallVector<int64_t> loopOrder =
788 for (SmallVector<int64_t> offsets :
789 StaticTileOffsetRange(originalShape, *targetShape, loopOrder)) {
793 loc, vector, offsets, *targetShape, strides);
794 vector::StoreOp::create(rewriter, loc,
slice, base,
indices);
801 vector::UnrollVectorOptions options;
804struct UnrollBroadcastPattern :
public OpRewritePattern<vector::BroadcastOp> {
805 UnrollBroadcastPattern(MLIRContext *context,
806 const vector::UnrollVectorOptions &options,
807 PatternBenefit benefit = 1)
808 : OpRewritePattern<vector::BroadcastOp>(context, benefit),
811 LogicalResult matchAndRewrite(vector::BroadcastOp broadcastOp,
812 PatternRewriter &rewriter)
const override {
817 Location loc = broadcastOp.getLoc();
818 VectorType srcType = dyn_cast<VectorType>(broadcastOp.getSourceType());
819 VectorType resType = broadcastOp.getResultVectorType();
821 SmallVector<int64_t> originalShape =
822 *broadcastOp.getIterationShapeToUnroll();
825 SmallVector<int64_t> adjustedTargetShape(originalShape.size(), 1);
826 llvm::copy(*targetShape, adjustedTargetShape.end() - targetShape->size());
828 VectorType targetType =
829 resType.cloneWith(adjustedTargetShape, resType.getElementType());
830 Value
result = arith::ConstantOp::create(rewriter, loc, resType,
833 SmallVector<int64_t> strides(originalShape.size(), 1);
835 for (SmallVector<int64_t> offsets :
836 StaticTileOffsetRange(originalShape, adjustedTargetShape)) {
840 newSrc = broadcastOp.getSource();
843 int64_t rank = srcType.getRank();
844 SmallVector<int64_t> srcOffsets(offsets.end() - rank, offsets.end());
845 SmallVector<int64_t> srcShape(adjustedTargetShape.end() - rank,
846 adjustedTargetShape.end());
847 SmallVector<int64_t> srcStrides(strides.end() - rank, strides.end());
849 for (int64_t i = 0; i < rank; ++i) {
850 if (srcType.getDimSize(i) == 1) {
855 newSrc = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
856 loc, broadcastOp.getSource(), srcOffsets, srcShape, srcStrides);
871 vector::UnrollVectorOptions options;
891struct UnrollToElements final :
public OpRewritePattern<vector::ToElementsOp> {
892 UnrollToElements(MLIRContext *context,
893 const vector::UnrollVectorOptions &options,
894 PatternBenefit benefit = 1)
895 : OpRewritePattern<vector::ToElementsOp>(context, benefit),
898 LogicalResult matchAndRewrite(vector::ToElementsOp op,
899 PatternRewriter &rewriter)
const override {
902 FailureOr<SmallVector<Value>>
result =
907 SmallVector<Value> vectors = *
result;
909 SmallVector<Value> results;
910 for (Value vector : vectors) {
912 vector::ToElementsOp::create(rewriter, op.getLoc(), vector);
913 llvm::append_range(results, subElements.getResults());
920 vector::UnrollVectorOptions options;
950 UnrollStepPattern(MLIRContext *context,
951 const vector::UnrollVectorOptions &options,
952 PatternBenefit benefit = 1)
953 : OpRewritePattern<vector::StepOp>(context, benefit), options(options) {}
955 LogicalResult matchAndRewrite(vector::StepOp stepOp,
956 PatternRewriter &rewriter)
const override {
957 std::optional<SmallVector<int64_t>> targetShape =
962 VectorType vecType = stepOp.getType();
963 if (vecType.isScalable()) {
967 int64_t originalSize = vecType.getShape()[0];
968 Location loc = stepOp.getLoc();
969 SmallVector<int64_t> strides(1, 1);
971 Value
result = arith::ConstantOp::create(rewriter, loc, vecType,
975 VectorType::get(*targetShape, vecType.getElementType());
976 Value baseStep = vector::StepOp::create(rewriter, loc, targetVecType);
977 for (
const SmallVector<int64_t> &offsets :
978 StaticTileOffsetRange({originalSize}, *targetShape)) {
979 Value bcastOffset = arith::ConstantOp::create(
980 rewriter, loc, targetVecType,
983 IntegerAttr::get(targetVecType.getElementType(), offsets[0])));
985 arith::AddIOp::create(rewriter, loc, baseStep, bcastOffset);
988 loc, tileStep,
result, offsets, strides);
995 vector::UnrollVectorOptions options;
1016 UnrollFromElements(MLIRContext *context,
1017 const vector::UnrollVectorOptions &options,
1018 PatternBenefit benefit = 1)
1019 : OpRewritePattern<vector::FromElementsOp>(context, benefit),
1022 LogicalResult matchAndRewrite(vector::FromElementsOp op,
1023 PatternRewriter &rewriter)
const override {
1026 auto unrollFromElementsFn = [&](PatternRewriter &rewriter, Location loc,
1027 VectorType subTy, int64_t index) {
1028 size_t subTyNumElements = subTy.getNumElements();
1029 assert((index + 1) * subTyNumElements <= allElements.size() &&
1032 allElements.slice(index * subTyNumElements, subTyNumElements);
1033 return vector::FromElementsOp::create(rewriter, loc, subTy, subElements);
1040 vector::UnrollVectorOptions options;
1076struct UnrollCreateMaskPattern :
public OpRewritePattern<vector::CreateMaskOp> {
1077 UnrollCreateMaskPattern(MLIRContext *context,
1078 const vector::UnrollVectorOptions &options,
1079 PatternBenefit benefit = 1)
1080 : OpRewritePattern<vector::CreateMaskOp>(context, benefit),
1083 LogicalResult matchAndRewrite(vector::CreateMaskOp createMaskOp,
1084 PatternRewriter &rewriter)
const override {
1089 VectorType resultType = createMaskOp.getVectorType();
1090 SmallVector<int64_t> originalSize =
1091 *createMaskOp.getIterationShapeToUnroll();
1092 Location loc = createMaskOp.getLoc();
1094 Value
result = arith::ConstantOp::create(rewriter, loc, resultType,
1096 VectorType targetVectorType =
1097 VectorType::get(*targetShape, rewriter.
getI1Type());
1098 SmallVector<int64_t> strides(targetShape->size(), 1);
1102 for (SmallVector<int64_t> offsets :
1103 StaticTileOffsetRange(originalSize, *targetShape)) {
1104 SmallVector<Value> unrolledOperands;
1106 for (
auto [i, originalMaskOperand] :
1107 llvm::enumerate(createMaskOp.getOperands())) {
1110 Value adjustedMaskSize = rewriter.
createOrFold<arith::SubIOp>(
1111 loc, originalMaskOperand, offsetVal);
1113 Value unrolledDimSize =
1116 rewriter.
createOrFold<arith::MaxSIOp>(loc, adjustedMaskSize, zero);
1117 Value unrolledOperand = rewriter.
createOrFold<arith::MinSIOp>(
1118 loc, nonNegative, unrolledDimSize);
1119 unrolledOperands.push_back(unrolledOperand);
1122 auto unrolledMask = rewriter.
createOrFold<vector::CreateMaskOp>(
1123 loc, targetVectorType, unrolledOperands);
1125 loc, unrolledMask,
result, offsets, strides);
1132 vector::UnrollVectorOptions options;
1167struct UnrollConstantMaskPattern
1169 UnrollConstantMaskPattern(MLIRContext *context,
1170 const vector::UnrollVectorOptions &options,
1171 PatternBenefit benefit = 1)
1172 : OpRewritePattern<vector::ConstantMaskOp>(context, benefit),
1175 LogicalResult matchAndRewrite(vector::ConstantMaskOp constantMaskOp,
1176 PatternRewriter &rewriter)
const override {
1177 std::optional<SmallVector<int64_t>> targetShape =
1182 VectorType resultType = constantMaskOp.getVectorType();
1183 SmallVector<int64_t> originalSize =
1184 *constantMaskOp.getIterationShapeToUnroll();
1185 Location loc = constantMaskOp.getLoc();
1187 Value
result = arith::ConstantOp::create(rewriter, loc, resultType,
1189 VectorType targetVectorType =
1190 VectorType::get(*targetShape, rewriter.
getI1Type());
1191 SmallVector<int64_t> strides(targetShape->size(), 1);
1195 for (
const SmallVector<int64_t> &offsets :
1196 StaticTileOffsetRange(originalSize, *targetShape)) {
1197 SmallVector<int64_t> unrolledMaskDims;
1199 for (
auto [i, originalMaskDim] :
1200 llvm::enumerate(constantMaskOp.getMaskDimSizes())) {
1203 int64_t adjustedMaskSize =
1204 std::max(originalMaskDim - offsets[i],
static_cast<int64_t
>(0));
1205 int64_t unrolledMaskDim =
1206 std::min(adjustedMaskSize,
static_cast<int64_t
>((*targetShape)[i]));
1207 unrolledMaskDims.push_back(unrolledMaskDim);
1210 auto unrolledMask = rewriter.
createOrFold<vector::ConstantMaskOp>(
1211 loc, targetVectorType, unrolledMaskDims);
1213 loc, unrolledMask,
result, offsets, strides);
1220 vector::UnrollVectorOptions options;
1238 if (extractShape.empty() ||
shape.empty() ||
1239 extractShape.size() >
shape.size())
1242 while (extractShape.size() > 1 && extractShape.front() == 1)
1243 extractShape = extractShape.drop_front();
1245 while (
shape.size() > 1 &&
shape.front() == 1) {
1249 size_t rankDiff =
shape.size() - extractShape.size();
1250 if (!llvm::equal(extractShape.drop_front(),
shape.drop_front(rankDiff + 1)))
1253 int64_t extractElements = ShapedType::getNumElements(extractShape);
1254 int64_t shapeElements = ShapedType::getNumElements(
shape);
1255 return shapeElements % extractElements == 0;
1277static std::optional<SmallVector<int64_t>>
1281 int64_t remainingElements = targetElements;
1284 for (
int i = sourceShape.size() - 1; i >= 0 && remainingElements > 1; --i) {
1285 int64_t takeFromDim = std::min(remainingElements, sourceShape[i]);
1286 extractShape.insert(extractShape.begin(), takeFromDim);
1288 if (remainingElements % takeFromDim != 0)
1289 return std::nullopt;
1290 remainingElements /= takeFromDim;
1294 while (extractShape.size() < sourceShape.size())
1295 extractShape.insert(extractShape.begin(), 1);
1297 if (ShapedType::getNumElements(extractShape) != targetElements)
1298 return std::nullopt;
1300 return extractShape;
1316struct ShapeCastReassociationGroup {
1317 int64_t srcBegin, srcEnd;
1318 int64_t resBegin, resEnd;
1324static std::optional<SmallVector<ShapeCastReassociationGroup>>
1329 int64_t srcRank = sourceShape.size(), resRank = resultShape.size();
1330 while (si < srcRank && ri < resRank) {
1331 int64_t srcBegin = si, resBegin = ri;
1332 int64_t srcProd = sourceShape[si++];
1333 int64_t resProd = resultShape[ri++];
1335 while (srcProd != resProd) {
1336 if (srcProd < resProd) {
1338 return std::nullopt;
1339 srcProd *= sourceShape[si++];
1342 return std::nullopt;
1343 resProd *= resultShape[ri++];
1347 while (si < srcRank && sourceShape[si] == 1)
1349 while (ri < resRank && resultShape[ri] == 1)
1351 groups.push_back({srcBegin, si, resBegin, ri});
1353 if (si != srcRank || ri != resRank)
1354 return std::nullopt;
1405struct UnrollShapeCastPattern :
public OpRewritePattern<vector::ShapeCastOp> {
1406 UnrollShapeCastPattern(MLIRContext *context,
1407 const vector::UnrollVectorOptions &options,
1408 PatternBenefit benefit = 1)
1409 : OpRewritePattern<vector::ShapeCastOp>(context, benefit),
1412 LogicalResult matchAndRewrite(vector::ShapeCastOp shapeCastOp,
1413 PatternRewriter &rewriter)
const override {
1414 std::optional<SmallVector<int64_t>> targetShape =
1419 VectorType sourceType = shapeCastOp.getSourceVectorType();
1420 VectorType resultType = shapeCastOp.getResultVectorType();
1421 ArrayRef<int64_t> sourceShape = sourceType.getShape();
1422 ArrayRef<int64_t> resultShape = resultType.getShape();
1426 std::optional<SmallVector<ShapeCastReassociationGroup>> groups =
1427 computeShapeCastGroups(sourceShape, resultShape);
1430 shapeCastOp,
"cannot align source and result reassociation groups");
1434 SmallVector<int64_t> paddedTarget(resultShape.size(), 1);
1435 llvm::copy(*targetShape,
1436 paddedTarget.end() -
static_cast<int64_t
>(targetShape->size()));
1439 SmallVector<int64_t> extractShapeStorage;
1440 for (
const ShapeCastReassociationGroup &g : *groups) {
1441 ArrayRef<int64_t> resSub =
1442 resultShape.slice(g.resBegin, g.resEnd - g.resBegin);
1443 ArrayRef<int64_t> tgtSub = ArrayRef<int64_t>(paddedTarget)
1444 .slice(g.resBegin, g.resEnd - g.resBegin);
1445 if (!isContiguous(tgtSub, resSub))
1447 shapeCastOp,
"target shape is not contiguous within a "
1448 "reassociation group of the result vector shape");
1450 ArrayRef<int64_t> srcSub =
1451 sourceShape.slice(g.srcBegin, g.srcEnd - g.srcBegin);
1452 int64_t groupTargetElements = ShapedType::getNumElements(tgtSub);
1453 std::optional<SmallVector<int64_t>> groupExtract =
1454 calculateSourceExtractShape(srcSub, groupTargetElements);
1457 shapeCastOp,
"cannot extract the target number of elements "
1458 "contiguously from a source reassociation group");
1459 extractShapeStorage.append(groupExtract->begin(), groupExtract->end());
1461 ArrayRef<int64_t> extractShape = extractShapeStorage;
1463 Location loc = shapeCastOp.getLoc();
1466 Value
result = arith::ConstantOp::create(rewriter, loc, resultType,
1469 VectorType targetType =
1470 VectorType::get(*targetShape, sourceType.getElementType());
1473 SmallVector<int64_t> insertStrides(targetShape->size(), 1);
1475 for (SmallVector<int64_t> resultOffsets :
1476 StaticTileOffsetRange(resultShape, *targetShape)) {
1477 SmallVector<int64_t> sourceOffsets =
1478 calculateSourceOffsets(resultOffsets, sourceShape, resultShape);
1479 Value sourceChunk = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
1480 loc, shapeCastOp.getSource(), sourceOffsets, extractShape,
1482 Value targetChunk = rewriter.
createOrFold<vector::ShapeCastOp>(
1483 loc, targetType, sourceChunk);
1485 loc, targetChunk,
result, resultOffsets, insertStrides);
1493 vector::UnrollVectorOptions options;
1511 UnrollBitCastPattern(MLIRContext *context,
1512 const vector::UnrollVectorOptions &options,
1513 PatternBenefit benefit = 1)
1514 : OpRewritePattern<vector::BitCastOp>(context, benefit),
1517 LogicalResult matchAndRewrite(vector::BitCastOp bitCastOp,
1518 PatternRewriter &rewriter)
const override {
1522 "failed to get target shape");
1524 VectorType sourceType = bitCastOp.getSourceVectorType();
1525 VectorType resultType = bitCastOp.getResultVectorType();
1526 ArrayRef<int64_t> resultShape = resultType.getShape();
1527 Location loc = bitCastOp.getLoc();
1529 if (targetShape->size() != resultShape.size())
1531 bitCastOp,
"target shape rank must match result rank");
1533 unsigned sourceElementBits = sourceType.getElementTypeBitWidth();
1534 unsigned resultElementBits = resultType.getElementTypeBitWidth();
1536 SmallVector<int64_t> sourceSliceShape(targetShape->begin(),
1537 targetShape->end());
1538 int64_t lastDim = sourceSliceShape.size() - 1;
1540 sourceSliceShape[lastDim] =
1541 ((*targetShape)[lastDim] * resultElementBits) / sourceElementBits;
1543 Value
result = arith::ConstantOp::create(rewriter, loc, resultType,
1545 SmallVector<int64_t> resultStrides(targetShape->size(), 1);
1546 SmallVector<int64_t> sourceStrides(sourceSliceShape.size(), 1);
1548 VectorType targetType =
1549 VectorType::get(*targetShape, resultType.getElementType());
1551 for (SmallVector<int64_t> resultOffsets :
1552 StaticTileOffsetRange(resultShape, *targetShape)) {
1553 SmallVector<int64_t> sourceOffsets = resultOffsets;
1554 sourceOffsets[lastDim] =
1555 (resultOffsets[lastDim] * resultElementBits) / sourceElementBits;
1557 Value sourceSlice = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
1558 loc, bitCastOp.getSource(), sourceOffsets, sourceSliceShape,
1560 Value bitcastSlice = rewriter.
createOrFold<vector::BitCastOp>(
1561 loc, targetType, sourceSlice);
1563 loc, bitcastSlice,
result, resultOffsets, resultStrides);
1571 vector::UnrollVectorOptions options;
1591struct UnrollInterleavePattern :
public OpRewritePattern<vector::InterleaveOp> {
1592 UnrollInterleavePattern(MLIRContext *context,
1593 const vector::UnrollVectorOptions &options,
1594 PatternBenefit benefit = 1)
1595 : OpRewritePattern<vector::InterleaveOp>(context, benefit),
1598 LogicalResult matchAndRewrite(vector::InterleaveOp interleaveOp,
1599 PatternRewriter &rewriter)
const override {
1603 "failed to get target shape");
1605 VectorType resultType = interleaveOp.getResultVectorType();
1606 ArrayRef<int64_t> resultShape = resultType.getShape();
1607 Location loc = interleaveOp.getLoc();
1609 if (targetShape->size() != resultShape.size())
1611 interleaveOp,
"target shape rank must match result rank");
1613 SmallVector<int64_t> sourceSliceShape(targetShape->begin(),
1614 targetShape->end());
1615 int64_t lastDim = sourceSliceShape.size() - 1;
1616 sourceSliceShape[lastDim] = (*targetShape)[lastDim] / 2;
1618 Value
result = arith::ConstantOp::create(rewriter, loc, resultType,
1620 SmallVector<int64_t> resultStrides(targetShape->size(), 1);
1621 SmallVector<int64_t> sourceStrides(sourceSliceShape.size(), 1);
1623 VectorType targetType =
1624 VectorType::get(*targetShape, resultType.getElementType());
1626 for (SmallVector<int64_t> resultOffsets :
1627 StaticTileOffsetRange(resultShape, *targetShape)) {
1628 SmallVector<int64_t> sourceOffsets = resultOffsets;
1629 sourceOffsets[lastDim] = resultOffsets[lastDim] / 2;
1631 Value lhsSlice = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
1632 loc, interleaveOp.getLhs(), sourceOffsets, sourceSliceShape,
1634 Value rhsSlice = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
1635 loc, interleaveOp.getRhs(), sourceOffsets, sourceSliceShape,
1637 Value interleaveSlice = rewriter.
createOrFold<vector::InterleaveOp>(
1638 loc, targetType, lhsSlice, rhsSlice);
1640 loc, interleaveSlice,
result, resultOffsets, resultStrides);
1648 vector::UnrollVectorOptions options;
1669struct UnrollDeinterleavePattern
1671 UnrollDeinterleavePattern(MLIRContext *context,
1672 const vector::UnrollVectorOptions &options,
1673 PatternBenefit benefit = 1)
1674 : OpRewritePattern<vector::DeinterleaveOp>(context, benefit),
1677 LogicalResult matchAndRewrite(vector::DeinterleaveOp deinterleaveOp,
1678 PatternRewriter &rewriter)
const override {
1682 "failed to get target shape");
1684 VectorType resultType = deinterleaveOp.getResultVectorType();
1685 ArrayRef<int64_t> resultShape = resultType.getShape();
1686 Location loc = deinterleaveOp.getLoc();
1688 if (targetShape->size() != resultShape.size())
1690 deinterleaveOp,
"target shape rank must match result rank");
1692 SmallVector<int64_t> sourceSliceShape(targetShape->begin(),
1693 targetShape->end());
1694 int64_t lastDim = sourceSliceShape.size() - 1;
1695 sourceSliceShape[lastDim] = (*targetShape)[lastDim] * 2;
1697 Value resultOdd = arith::ConstantOp::create(
1698 rewriter, loc, resultType, rewriter.
getZeroAttr(resultType));
1699 Value resultEven = arith::ConstantOp::create(
1700 rewriter, loc, resultType, rewriter.
getZeroAttr(resultType));
1701 SmallVector<int64_t> resultStrides(targetShape->size(), 1);
1702 SmallVector<int64_t> sourceStrides(sourceSliceShape.size(), 1);
1704 for (SmallVector<int64_t> resultOffsets :
1705 StaticTileOffsetRange(resultShape, *targetShape)) {
1706 SmallVector<int64_t> sourceOffsets = resultOffsets;
1707 sourceOffsets[lastDim] = resultOffsets[lastDim] * 2;
1709 Value sourceSlice = rewriter.
createOrFold<vector::ExtractStridedSliceOp>(
1710 loc, deinterleaveOp.getSource(), sourceOffsets, sourceSliceShape,
1713 auto deinterleaveSlice =
1714 vector::DeinterleaveOp::create(rewriter, loc, sourceSlice);
1716 resultOdd = rewriter.
createOrFold<vector::InsertStridedSliceOp>(
1717 loc, deinterleaveSlice.getRes1(), resultOdd, resultOffsets,
1719 resultEven = rewriter.
createOrFold<vector::InsertStridedSliceOp>(
1720 loc, deinterleaveSlice.getRes2(), resultEven, resultOffsets,
1729 vector::UnrollVectorOptions options;
1734void mlir::vector::populateVectorUnrollPatterns(
1737 patterns.
add<UnrollTransferReadPattern, UnrollTransferWritePattern,
1738 UnrollContractionPattern, UnrollElementwisePattern,
1739 UnrollReductionPattern, UnrollMultiReductionPattern,
1740 UnrollTransposePattern, UnrollGatherPattern, UnrollLoadPattern,
1741 UnrollStorePattern, UnrollBroadcastPattern, UnrollFromElements,
1742 UnrollToElements, UnrollStepPattern, UnrollShapeCastPattern,
1743 UnrollCreateMaskPattern, UnrollConstantMaskPattern,
1744 UnrollBitCastPattern, UnrollInterleavePattern,
1749void mlir::vector::populateVectorContractUnrollPatterns(
1756void mlir::vector::populateVectorToElementsUnrollPatterns(
1762void mlir::vector::populateVectorFromElementsUnrollPatterns(
static LogicalResult extractStrides(AffineExpr e, AffineExpr multiplicativeFactor, MutableArrayRef< AffineExpr > strides, AffineExpr &offset)
Takes a single AffineExpr e and populates the strides array with the strides expressions for each dim...
static llvm::ManagedStatic< PassManagerOptions > options
static SmallVector< Value > slice(OpBuilder &b, Location loc, Value value, VectorType nativeType)
static SmallVector< Value > sliceLoadStoreIndices(PatternRewriter &rewriter, Location loc, OperandRange originalIndices, ArrayRef< int64_t > offsets)
static std::optional< SmallVector< int64_t > > getTargetShape(const vector::UnrollVectorOptions &options, Operation *op)
Return the target shape for unrolling for the given op.
static SmallVector< int64_t > getUnrollOrder(unsigned numLoops, Operation *op, const vector::UnrollVectorOptions &options)
static Operation * cloneOpWithOperandsAndTypes(OpBuilder &builder, Location loc, Operation *op, ArrayRef< Value > operands, ArrayRef< Type > resultTypes)
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
ArrayRef< AffineExpr > getResults() const
TypedAttr getZeroAttr(Type type)
MLIRContext * getContext() const
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This class helps build Operations.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
This class implements the operand iterators for the Operation class.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Operation is the basic unit of execution within MLIR.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
MutableArrayRef< OpOperand > getOpOperands()
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
OperationName getName()
The name of an operation is the key identifier for it.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
RewritePattern is the common base class for all DAG to DAG replacements.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
Type getType() const
Return the type of this value.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
Value makeArithReduction(OpBuilder &b, Location loc, CombiningKind kind, Value v1, Value acc, arith::FastMathFlagsAttr fastmath=nullptr, Value mask=nullptr)
Returns the result value of reducing two scalar/vector values with the corresponding arith operation.
FailureOr< SmallVector< Value > > unrollVectorValue(TypedValue< VectorType >, RewriterBase &)
Generic utility for unrolling values of type vector<NxAxBx...> to N values of type vector<AxBx....
LogicalResult unrollVectorOp(Operation *op, PatternRewriter &rewriter, UnrollVectorOpFn unrollFn)
Include the generated interface declarations.
SmallVector< int64_t > computeStrides(ArrayRef< int64_t > sizes)
SmallVector< int64_t > delinearize(int64_t linearIndex, ArrayRef< int64_t > strides)
Given the strides together with a linear index in the dimension space, return the vector-space offset...
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
SmallVector< T > applyPermutationMap(AffineMap map, llvm::ArrayRef< T > source)
Apply a permutation from map to source and return the result.
int64_t linearize(ArrayRef< int64_t > offsets, ArrayRef< int64_t > basis)
Return the linearized index of 'offsets' w.r.t.
std::optional< SmallVector< int64_t > > computeShapeRatio(ArrayRef< int64_t > shape, ArrayRef< int64_t > subShape)
Return the multi-dimensional integral ratio of subShape to the trailing dimensions of shape.
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
This represents an operation in an abstracted form, suitable for use with the builder APIs.
Attribute propertiesAttr
This Attribute is used to opaquely construct the properties of the operation.
Options that control the vector unrolling.