35#include "llvm/ADT/DenseSet.h"
36#include "llvm/ADT/Repeated.h"
37#include "llvm/ADT/STLExtras.h"
38#include "llvm/ADT/SmallBitVector.h"
39#include "llvm/ADT/SmallVectorExtras.h"
40#include "llvm/ADT/StringRef.h"
41#include "llvm/Support/Casting.h"
42#include "llvm/Support/MathExtras.h"
55 auto verifiable = dyn_cast_or_null<VerifiableTensorEncoding>(encoding);
63 return succeeded(verifiable.verifyEncoding(
shape, elementType,
emit))
73 if (
auto op = arith::ConstantOp::materialize(builder, value, type, loc))
75 if (complex::ConstantOp::isBuildableWith(value, type))
76 return complex::ConstantOp::create(builder, loc, type,
77 llvm::cast<ArrayAttr>(value));
83 auto tensorType = llvm::cast<RankedTensorType>(value.
getType());
84 if (tensorType.isDynamicDim(dim))
85 return builder.
createOrFold<tensor::DimOp>(loc, value, dim);
92 auto tensorType = llvm::cast<RankedTensorType>(value.
getType());
94 for (
int64_t i = 0; i < tensorType.getRank(); ++i)
101 auto tensorType = llvm::dyn_cast<TensorType>(opResult.
getType());
102 assert(tensorType &&
"expected tensor type");
106 auto destOp = opResult.
getDefiningOp<DestinationStyleOpInterface>();
108 return destOp.getTiedOpOperand(opResult)->get();
116 if (!tensorType.hasStaticShape()) {
124 for (
int64_t sz : tensorType.getShape())
125 mixedSizes.push_back(
b.getIndexAttr(sz));
130 if (
auto rankedTensorType = dyn_cast<RankedTensorType>(tensorType))
131 encoding = rankedTensorType.getEncoding();
132 Value emptyTensor = tensor::EmptyOp::create(
133 b, loc, mixedSizes, tensorType.getElementType(), encoding);
141 if (llvm::isa<TensorType>(opResult.getType())) {
143 if (failed(destination))
145 result.push_back(*destination);
152 if (
auto rtp1 = llvm::dyn_cast<RankedTensorType>(tp1)) {
153 if (
auto rtp2 = llvm::dyn_cast<RankedTensorType>(tp2))
154 return rtp1.getShape() == rtp2.getShape() &&
155 rtp1.getElementType() == rtp2.getElementType();
165 llvm::SmallBitVector droppedDims(mixedSizes.size());
166 int64_t shapePos = reducedShape.size() - 1;
168 for (
const auto &size : enumerate(llvm::reverse(mixedSizes))) {
169 size_t idx = mixedSizes.size() - size.index() - 1;
171 bool isStaticUnitSize =
172 isa<Attribute>(size.value()) &&
173 llvm::cast<IntegerAttr>(cast<Attribute>(size.value())).getInt() == 1;
178 assert(isStaticUnitSize &&
"expected unit dim");
179 droppedDims.set(idx);
184 if (!isStaticUnitSize) {
190 if (reducedShape[shapePos] == 1) {
196 droppedDims.set(idx);
199 assert(shapePos < 0 &&
"dimension mismatch");
206static RankedTensorType
210 assert(type.getNumDynamicDims() == dynamicSizes.size() &&
211 "incorrect number of dynamic sizes");
215 for (
int64_t i = 0, e = type.getRank(); i < e; ++i) {
216 if (type.isDynamicDim(i)) {
217 Value dynamicSize = dynamicSizes[ctr++];
219 if (cst.has_value()) {
221 if (cst.value() < 0) {
222 foldedDynamicSizes.push_back(dynamicSize);
225 staticShape[i] = *cst;
227 foldedDynamicSizes.push_back(dynamicSize);
232 return RankedTensorType::get(staticShape, type.getElementType(),
241 if (inputs.size() != 1 || outputs.size() != 1)
243 Type a = inputs.front(),
b = outputs.front();
244 auto aT = dyn_cast<TensorType>(a);
245 auto bT = dyn_cast<TensorType>(
b);
249 if (aT.getElementTypeBitWidth() != bT.getElementTypeBitWidth())
260 using OpRewritePattern<BitcastOp>::OpRewritePattern;
262 LogicalResult matchAndRewrite(BitcastOp tensorBitcast,
263 PatternRewriter &rewriter)
const final {
264 auto tensorBitcastOperand =
265 tensorBitcast.getOperand().getDefiningOp<BitcastOp>();
266 if (!tensorBitcastOperand)
269 auto resultType = cast<TensorType>(tensorBitcast.getType());
270 rewriter.replaceOpWithNewOp<BitcastOp>(tensorBitcast, resultType,
271 tensorBitcastOperand.getOperand());
280 results.
add<ChainedTensorBitcast>(context);
288 setNameFn(getResult(),
"cast");
294 auto sourceType = llvm::dyn_cast<RankedTensorType>(source);
295 auto targetType = llvm::dyn_cast<RankedTensorType>(
target);
298 if (!sourceType || !targetType)
302 if (sourceType.getElementType() != targetType.getElementType())
306 if (sourceType.getRank() != targetType.getRank())
310 if (sourceType.getEncoding() != targetType.getEncoding())
314 for (
auto t : llvm::zip(sourceType.getShape(), targetType.getShape())) {
315 if (ShapedType::isStatic(std::get<0>(t)) &&
316 ShapedType::isDynamic(std::get<1>(t)))
352 castOp.getSource().getType());
385 if (llvm::isa<BlockArgument>(opOperand.get()))
387 auto castOp = opOperand.get().getDefiningOp<tensor::CastOp>();
388 return castOp && canFoldIntoConsumerOp(castOp);
395 newOperands.reserve(op->getNumOperands());
401 for (
OpOperand &opOperand : op->getOpOperands()) {
402 auto tensorCastOp = opOperand.get().getDefiningOp<tensor::CastOp>();
404 newOperands.push_back(fold ? tensorCastOp.getOperand() : opOperand.get());
405 if (op.isDpsInit(&opOperand) &&
406 !llvm::isa<MemRefType>(newOperands.back().getType()))
407 newResTy[dpsInitIdx++] = newOperands.back().getType();
417 auto castOp = operand.get().getDefiningOp<tensor::CastOp>();
419 operand.set(castOp.getOperand());
427 if (inputs.size() != 1 || outputs.size() != 1)
429 Type a = inputs.front(),
b = outputs.front();
430 auto aT = llvm::dyn_cast<TensorType>(a);
431 auto bT = llvm::dyn_cast<TensorType>(
b);
435 if (aT.getElementType() != bT.getElementType())
452 if (rank != two.getRank())
457 for (
int64_t i = 0; i < rank; ++i) {
458 if (one.isDynamicDim(i)) {
459 join.push_back(two.getDimSize(i));
462 if (two.isDynamicDim(i)) {
463 join.push_back(one.getDimSize(i));
466 if (one.getDimSize(i) != two.getDimSize(i))
468 join.push_back(one.getDimSize(i));
478 using OpRewritePattern<CastOp>::OpRewritePattern;
480 LogicalResult matchAndRewrite(CastOp tensorCast,
481 PatternRewriter &rewriter)
const final {
482 auto tensorCastOperand = tensorCast.getOperand().getDefiningOp<CastOp>();
484 if (!tensorCastOperand)
488 llvm::cast<TensorType>(tensorCastOperand.getOperand().getType());
489 auto intermediateType = llvm::cast<TensorType>(tensorCastOperand.getType());
490 auto resultType = llvm::cast<TensorType>(tensorCast.getType());
504 auto newJoin =
joinShapes(sourceType, resultType);
505 if (firstJoin != newJoin)
508 rewriter.replaceOpWithNewOp<CastOp>(tensorCast, resultType,
509 tensorCastOperand.getOperand());
527 using OpRewritePattern<CastOp>::OpRewritePattern;
529 LogicalResult matchAndRewrite(CastOp tensorCast,
530 PatternRewriter &rewriter)
const final {
531 auto extractOperand =
532 tensorCast.getOperand().getDefiningOp<ExtractSliceOp>();
535 auto rankedResultType =
536 llvm::dyn_cast<RankedTensorType>(tensorCast.getType());
537 if (!rankedResultType)
541 rankedResultType.getShape() ==
542 llvm::cast<RankedTensorType>(tensorCast.getSource().getType())
546 SmallVector<OpFoldResult, 4> sizes = extractOperand.getMixedSizes();
548 extractOperand.getStaticSizes(), extractOperand.getType().getShape());
550 for (
size_t i = 0, e = sizes.size(); i < e; i++) {
551 if (dimMask && dimMask->count(i))
553 int64_t dim = rankedResultType.getShape()[dimIndex++];
554 if (ShapedType::isDynamic(dim))
556 sizes[i] = rewriter.getIndexAttr(dim);
559 rewriter.replaceOpWithNewOp<ExtractSliceOp>(
560 tensorCast, rankedResultType, extractOperand.getSource(),
561 extractOperand.getMixedOffsets(), sizes,
562 extractOperand.getMixedStrides());
571 results.
add<ChainedTensorCast, TensorCastExtractSlice>(context);
578RankedTensorType ConcatOp::inferResultType(
int64_t dim,
TypeRange inputTypes) {
579 assert(!inputTypes.empty() &&
"cannot concatenate 0 tensors");
581 llvm::map_to_vector<4>(inputTypes, llvm::CastTo<RankedTensorType>);
582 int64_t concatRank = tensorTypes[0].getRank();
585 assert(dim >= 0 && dim < concatRank &&
"Invalid concatenation dim");
588 for (
int64_t i = 0, e = concatRank; i < e; ++i) {
592 for (
auto tensorType : tensorTypes)
597 for (
auto tensorType : tensorTypes)
600 sizes[dim] = concatSize.asInteger();
601 return RankedTensorType::get(sizes, tensorTypes[0].
getElementType());
606 FailureOr<RankedTensorType> resultType =
607 inferResultType(dim, inputs.
getTypes());
608 assert(succeeded(resultType) &&
"failed to infer concatenation result type");
609 build(builder,
result, *resultType, dim, inputs);
612LogicalResult ConcatOp::verify() {
613 if (getInputs().size() < 1)
617 for (
auto input : getInputs())
618 inputTypes.push_back(cast<RankedTensorType>(input.getType()));
620 RankedTensorType resultType = getResultType();
621 int64_t resultRank = getRank();
622 if (llvm::any_of(inputTypes, [resultRank](RankedTensorType type) {
623 return type.getRank() != resultRank;
625 return emitOpError(
"rank of concatenated inputs must match result rank");
627 Type resultElementType = resultType.getElementType();
628 if (llvm::any_of(inputTypes, [&](RankedTensorType type) {
629 return type.getElementType() != resultElementType;
631 return emitOpError(
"inputs and result element type must match");
634 if (dim >= resultRank)
635 return emitOpError(
"concatenation dim must be less than the tensor rank");
638 for (
int64_t i = 0, e = resultRank; i < e; ++i) {
642 for (
auto tensorType : inputTypes) {
643 FailureOr<SaturatedInteger> maybeSize =
646 return emitOpError(
"static concatenation size mismatch along ")
647 <<
"non-concatenated dimension " << i;
653 for (
auto tensorType : inputTypes)
656 sizes[dim] = concatSize.asInteger();
657 auto inferredResultType =
660 for (
auto [inferredSize, actualSize] :
661 llvm::zip_equal(inferredResultType.getShape(), resultType.getShape())) {
662 bool hasDynamic = ShapedType::isDynamic(inferredSize) ||
663 ShapedType::isDynamic(actualSize);
664 if (!hasDynamic && inferredSize != actualSize)
666 << resultType <<
"does not match inferred shape "
667 << inferredResultType <<
" static sizes";
673FailureOr<SmallVector<Value>> ConcatOp::decomposeOperation(
OpBuilder &builder) {
674 size_t numInputs = getInputs().size();
675 uint64_t concatDim = getDim();
678 inputShapes.reserve(numInputs);
680 concatOffsets.reserve(numInputs);
687 for (
auto [
index, input] : llvm::enumerate(getInputs())) {
691 outputShape = inputShape;
692 concatOffsets.push_back(zero);
694 concatOffsets.push_back(outputShape[concatDim]);
696 builder, loc, addExpr,
697 {outputShape[concatDim], inputShape[concatDim]});
699 inputShapes.emplace_back(std::move(inputShape));
709 for (
auto [
index, input] : llvm::enumerate(getInputs())) {
710 offsets[concatDim] = concatOffsets[
index];
711 auto insertSlice = tensor::InsertSliceOp::create(
722ConcatOp::reifyResultShapes(
OpBuilder &builder,
726 RankedTensorType inferredResultType = inferResultType(dim, inputs.
getTypes());
728 Value init = inputs[0];
736 for (
int64_t i = 0; i < rank; ++i) {
739 if (!
getType().isDynamicDim(i)) {
741 }
else if (!inferredResultType.isDynamicDim(i)) {
744 builder.
getIndexAttr(inferredResultType.getDimSize(i)));
746 reifiedReturnShapes[0][i] =
747 tensor::DimOp::create(builder, init.
getLoc(), init, i).getResult();
751 if (
getType().isDynamicDim(dim)) {
756 for (
auto [idx, input] : llvm::enumerate(inputs.drop_front())) {
759 builder.
createOrFold<tensor::DimOp>(input.getLoc(), input, dim));
767 reifiedReturnShapes[0][dim] =
773void ConcatOp::getAsmResultNames(
775 setNameFn(getResult(),
"concat");
780 if (inputs.size() == 1 && inputs[0].
getType() == getResultType())
788 using OpRewritePattern<ConcatOp>::OpRewritePattern;
790 LogicalResult matchAndRewrite(ConcatOp concatOp,
791 PatternRewriter &rewriter)
const override {
792 if (concatOp.getInputs().size() != 1)
795 concatOp.getInputs()[0]);
820 using OpRewritePattern<ConcatOp>::OpRewritePattern;
822 LogicalResult matchAndRewrite(ConcatOp concatOp,
823 PatternRewriter &rewriter)
const override {
824 int64_t dim = concatOp.getDim();
825 RankedTensorType inferredResultType =
826 ConcatOp::inferResultType(dim, concatOp->getOperandTypes());
829 LogicalResult matched = failure();
832 SmallVector<int64_t> inferredOperandShape(inferredResultType.getShape());
833 for (
auto [operandIdx, operandType] :
834 llvm::enumerate(concatOp->getOperandTypes())) {
836 inferredOperandShape[dim] =
837 cast<RankedTensorType>(operandType).getDimSize(dim);
838 auto inferredOperandType = RankedTensorType::get(
839 inferredOperandShape, inferredResultType.getElementType());
847 CastOp::create(rewriter, concatOp->getLoc(), inferredOperandType,
848 concatOp.getOperand(operandIdx));
850 concatOp->setOperand(operandIdx, castOp->getResult(0));
874 using OpRewritePattern<ConcatOp>::OpRewritePattern;
876 LogicalResult matchAndRewrite(ConcatOp concatOp,
877 PatternRewriter &rewriter)
const override {
878 int64_t dim = concatOp.getDim();
879 RankedTensorType inferredResultType =
880 ConcatOp::inferResultType(dim, concatOp->getOperandTypes());
884 concatOp.getResultType())) {
889 ConcatOp::create(rewriter, concatOp->getLoc(), inferredResultType, dim,
890 concatOp->getOperands());
902 .
add<SingleInputConcatOp, InferConcatOperandTypes, InferConcatResultType>(
911 setNameFn(getResult(),
"dim");
916 auto loc =
result.location;
918 build(builder,
result, source, indexValue);
921std::optional<int64_t> DimOp::getConstantIndex() {
930 auto rankedSourceType = dyn_cast<RankedTensorType>(getSource().
getType());
931 if (!rankedSourceType)
934 if (rankedSourceType.getRank() <= constantIndex)
942 setResultRange(getResult(),
948 std::optional<int64_t>
index = getConstantIndex();
953 auto tensorType = llvm::dyn_cast<RankedTensorType>(getSource().
getType());
960 if (indexVal < 0 || indexVal >= tensorType.getRank())
964 if (!tensorType.isDynamicDim(indexVal)) {
966 return builder.
getIndexAttr(tensorType.getShape()[indexVal]);
969 Operation *definingOp = getSource().getDefiningOp();
972 if (
auto fromElements = dyn_cast_or_null<tensor::GenerateOp>(definingOp)) {
974 llvm::cast<RankedTensorType>(fromElements.getResult().getType());
977 assert(ShapedType::isDynamic(resultType.getShape()[indexVal]));
980 auto dynExtents = fromElements.getDynamicExtents().begin();
981 for (
auto dim : resultType.getShape().take_front(indexVal))
982 if (ShapedType::isDynamic(dim))
985 return Value{*dynExtents};
989 if (
auto sliceOp = dyn_cast_or_null<tensor::ExtractSliceOp>(definingOp)) {
992 if (sliceOp.getType().getRank() == sliceOp.getSourceType().getRank() &&
993 sliceOp.isDynamicSize(indexVal)) {
994 return {sliceOp.getDynamicSize(indexVal)};
1008 using OpRewritePattern<DimOp>::OpRewritePattern;
1010 LogicalResult matchAndRewrite(DimOp dimOp,
1011 PatternRewriter &rewriter)
const override {
1012 auto castOp = dimOp.getSource().getDefiningOp<CastOp>();
1015 Value newSource = castOp.getOperand();
1024 using OpRewritePattern<DimOp>::OpRewritePattern;
1026 LogicalResult matchAndRewrite(DimOp dimOp,
1027 PatternRewriter &rewriter)
const override {
1028 auto source = dimOp.getSource();
1029 auto destOp = source.getDefiningOp<DestinationStyleOpInterface>();
1033 auto resultIndex = cast<OpResult>(source).getResultNumber();
1034 auto *initOperand = destOp.getDpsInitOperand(resultIndex);
1037 dimOp, [&]() { dimOp.getSourceMutable().assign(initOperand->get()); });
1045 using OpRewritePattern<DimOp>::OpRewritePattern;
1047 LogicalResult matchAndRewrite(DimOp dim,
1048 PatternRewriter &rewriter)
const override {
1049 auto reshape = dim.getSource().getDefiningOp<ReshapeOp>();
1057 Location loc = dim.getLoc();
1059 ExtractOp::create(rewriter, loc, reshape.getShape(), dim.getIndex());
1060 if (extract.
getType() != dim.getType())
1062 arith::IndexCastOp::create(rewriter, loc, dim.getType(), extract);
1071 results.
add<DimOfCastOp, DimOfDestStyleOp, DimOfReshapeOp>(context);
1081 assert(none_of(staticShape, ShapedType::isDynamic) &&
1082 "expected only static sizes");
1086void EmptyOp::build(OpBuilder &builder, OperationState &
result,
1087 ArrayRef<int64_t> staticShape, Type elementType,
1088 ValueRange dynamicSizes, Attribute encoding) {
1089 auto tensorType = RankedTensorType::get(staticShape, elementType, encoding);
1090 build(builder,
result, tensorType, dynamicSizes);
1093void EmptyOp::build(OpBuilder &builder, OperationState &
result,
1094 ArrayRef<OpFoldResult> sizes, Type elementType,
1095 Attribute encoding) {
1096 SmallVector<int64_t> staticShape;
1097 SmallVector<Value> dynamicSizes;
1099 build(builder,
result, staticShape, elementType, dynamicSizes, encoding);
1102LogicalResult EmptyOp::verify() {
1108EmptyOp::reifyResultShapes(OpBuilder &builder,
1110 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
1112 for (int64_t i = 0; i <
getType().getRank(); ++i) {
1113 if (
getType().isDynamicDim(i)) {
1122Value EmptyOp::getDynamicSize(
unsigned idx) {
1123 assert(
getType().isDynamicDim(idx) &&
"expected dynamic dim");
1125 for (int64_t i = 0; i < static_cast<int64_t>(idx); ++i)
1126 if (
getType().isDynamicDim(i))
1131SmallVector<OpFoldResult> EmptyOp::getMixedSizes() {
1132 SmallVector<OpFoldResult>
result;
1136 if (ShapedType::isDynamic(dim)) {
1139 result.push_back(
b.getIndexAttr(dim));
1157struct ReplaceEmptyTensorStaticShapeDims : OpRewritePattern<EmptyOp> {
1158 using OpRewritePattern<EmptyOp>::OpRewritePattern;
1160 LogicalResult matchAndRewrite(EmptyOp op,
1161 PatternRewriter &rewriter)
const override {
1162 SmallVector<Value> foldedDynamicSizes;
1164 op.getType(), op.getDynamicSizes(), foldedDynamicSizes);
1167 if (foldedTensorType == op.getType())
1170 auto newOp = EmptyOp::create(rewriter, op.getLoc(), foldedTensorType,
1171 foldedDynamicSizes);
1177struct FoldEmptyTensorWithDimOp :
public OpRewritePattern<DimOp> {
1178 using OpRewritePattern<DimOp>::OpRewritePattern;
1180 LogicalResult matchAndRewrite(tensor::DimOp dimOp,
1181 PatternRewriter &rewriter)
const override {
1182 std::optional<int64_t> maybeConstantIndex = dimOp.getConstantIndex();
1183 auto emptyTensorOp = dimOp.getSource().getDefiningOp<EmptyOp>();
1184 if (!emptyTensorOp || !maybeConstantIndex)
1186 auto emptyTensorType = emptyTensorOp.getType();
1187 if (*maybeConstantIndex < 0 ||
1188 *maybeConstantIndex >= emptyTensorType.getRank() ||
1189 !emptyTensorType.isDynamicDim(*maybeConstantIndex))
1192 emptyTensorOp.getDynamicSize(*maybeConstantIndex));
1212struct FoldEmptyTensorWithCastOp :
public OpRewritePattern<CastOp> {
1213 using OpRewritePattern<CastOp>::OpRewritePattern;
1215 LogicalResult matchAndRewrite(CastOp castOp,
1216 PatternRewriter &rewriter)
const override {
1219 auto producer = castOp.getSource().getDefiningOp<EmptyOp>();
1224 llvm::cast<RankedTensorType>(castOp->getResult(0).getType());
1225 ArrayRef<int64_t> resultShape = resultType.getShape();
1226 SmallVector<OpFoldResult> currMixedSizes = producer.getMixedSizes();
1227 SmallVector<OpFoldResult> newMixedSizes;
1228 newMixedSizes.reserve(currMixedSizes.size());
1229 assert(resultShape.size() == currMixedSizes.size() &&
1230 "mismatch in result shape and sizes of empty op");
1231 for (
auto [newDim, currDim] : llvm::zip(resultShape, currMixedSizes)) {
1234 if (
auto attr = llvm::dyn_cast_if_present<Attribute>(currDim)) {
1235 if (ShapedType::isDynamic(newDim) ||
1236 newDim != llvm::cast<IntegerAttr>(attr).getInt()) {
1241 producer,
"mismatch in static value of shape of empty tensor "
1242 "result and cast result");
1244 newMixedSizes.push_back(attr);
1250 if (ShapedType::isStatic(newDim)) {
1251 newMixedSizes.push_back(rewriter.
getIndexAttr(newDim));
1257 newMixedSizes.push_back(currDim);
1261 resultType.getElementType(),
1262 resultType.getEncoding());
1269void EmptyOp::getCanonicalizationPatterns(RewritePatternSet &results,
1270 MLIRContext *context) {
1271 results.
add<FoldEmptyTensorWithCastOp, FoldEmptyTensorWithDimOp,
1272 ReplaceEmptyTensorStaticShapeDims>(context);
1289struct ExtractFromTensorCast :
public OpRewritePattern<tensor::ExtractOp> {
1290 using OpRewritePattern<tensor::ExtractOp>::OpRewritePattern;
1292 LogicalResult matchAndRewrite(tensor::ExtractOp extract,
1293 PatternRewriter &rewriter)
const final {
1294 auto tensorCast = extract.getTensor().getDefiningOp<tensor::CastOp>();
1297 if (!llvm::isa<RankedTensorType>(tensorCast.getSource().getType()))
1300 extract, tensorCast.getSource(), extract.getIndices());
1315struct ExtractFromCollapseShape :
public OpRewritePattern<tensor::ExtractOp> {
1316 using OpRewritePattern<tensor::ExtractOp>::OpRewritePattern;
1318 LogicalResult matchAndRewrite(tensor::ExtractOp extractOp,
1319 PatternRewriter &rewriter)
const final {
1321 extractOp.getTensor().getDefiningOp<tensor::CollapseShapeOp>();
1324 if (!collapseOp.getSrcType().hasStaticShape())
1327 auto sourceSizes = collapseOp.getSrcType().getShape();
1329 SmallVector<Value>
indices(extractOp.getIndices().begin(),
1330 extractOp.getIndices().end());
1331 SmallVector<Value> sourceIndices;
1332 for (
auto [index, group] :
1333 llvm::zip(
indices, collapseOp.getReassociationIndices())) {
1334 assert(!group.empty() &&
"association indices groups cannot be empty");
1335 auto groupSize = group.size();
1337 if (groupSize == 1) {
1338 sourceIndices.push_back(index);
1342 SmallVector<int64_t> basis =
1343 llvm::map_to_vector(group, [&](int64_t d) {
return sourceSizes[d]; });
1344 auto delinearize = affine::AffineDelinearizeIndexOp::create(
1345 rewriter, extractOp.getLoc(), index, basis,
true);
1346 llvm::append_range(sourceIndices,
delinearize.getResults());
1348 if (collapseOp.getReassociationIndices().empty()) {
1351 cast<RankedTensorType>(collapseOp.getSrcType()).getRank();
1353 rewriter, extractOp.getLoc(), zeroAffineMap,
1354 ArrayRef<OpFoldResult>{});
1355 for (int64_t i = 0; i < srcRank; i++) {
1356 sourceIndices.push_back(
1362 extractOp, collapseOp.getSrc(), sourceIndices);
1369void ExtractOp::getAsmResultNames(
1371 setNameFn(getResult(),
"extracted");
1374LogicalResult ExtractOp::verify() {
1376 auto tensorType = llvm::cast<RankedTensorType>(getTensor().
getType());
1377 if (tensorType.getRank() !=
static_cast<int64_t
>(
getIndices().size()))
1378 return emitOpError(
"incorrect number of indices for extract_element");
1387 auto insertOp = extractOp.getTensor().
getDefiningOp<InsertOp>();
1392 if (insertOp && insertOp.getScalar().getType() == extractOp.getType() &&
1393 llvm::equal(insertOp.getIndices(), extractOp.getIndices(), isSame))
1394 return insertOp.getScalar();
1399OpFoldResult ExtractOp::fold(FoldAdaptor adaptor) {
1400 if (Attribute tensor = adaptor.getTensor()) {
1403 if (
auto splatTensor = llvm::dyn_cast<SplatElementsAttr>(tensor))
1404 return splatTensor.getSplatValue<Attribute>();
1407 if (isa<DenseResourceElementsAttr>(tensor))
1412 SmallVector<uint64_t, 8>
indices;
1413 for (Attribute indice : adaptor.getIndices()) {
1414 if (!indice || !llvm::isa<IntegerAttr>(indice))
1416 indices.push_back(llvm::cast<IntegerAttr>(indice).getInt());
1420 if (
auto fromElementsOp = getTensor().getDefiningOp<FromElementsOp>()) {
1421 auto tensorType = llvm::cast<RankedTensorType>(fromElementsOp.getType());
1422 auto rank = tensorType.getRank();
1423 assert(
static_cast<int64_t
>(
indices.size()) == tensorType.getRank() &&
1427 for (
int i = rank - 1; i >= 0; --i) {
1428 flatIndex +=
indices[i] * stride;
1429 stride *= tensorType.getDimSize(i);
1433 if (
static_cast<int>(fromElementsOp.getElements().size()) <= flatIndex ||
1436 return fromElementsOp.getElements()[flatIndex];
1440 if (Attribute tensor = adaptor.getTensor()) {
1441 auto elementsAttr = llvm::dyn_cast<ElementsAttr>(tensor);
1442 if (elementsAttr && elementsAttr.isValidIndex(
indices))
1443 return elementsAttr.getValues<Attribute>()[
indices];
1452void ExtractOp::getCanonicalizationPatterns(RewritePatternSet &results,
1453 MLIRContext *context) {
1454 results.
add<ExtractFromTensorCast>(context);
1459 patterns.
add<ExtractFromCollapseShape>(patterns.
getContext());
1466void FromElementsOp::getAsmResultNames(
1468 setNameFn(getResult(),
"from_elements");
1473 assert(!elements.empty() &&
"expected at least one element");
1474 Type resultType = RankedTensorType::get(
1475 {
static_cast<int64_t>(elements.size())}, elements.front().
getType());
1476 build(builder,
result, resultType, elements);
1479OpFoldResult FromElementsOp::fold(FoldAdaptor adaptor) {
1484 Type eltType =
getType().getElementType();
1487 if (!llvm::is_contained(adaptor.getElements(),
nullptr))
1510struct ExtractElementFromIndexCast
1511 :
public OpRewritePattern<tensor::ExtractOp> {
1512 using OpRewritePattern<tensor::ExtractOp>::OpRewritePattern;
1514 LogicalResult matchAndRewrite(tensor::ExtractOp extract,
1515 PatternRewriter &rewriter)
const final {
1516 Location loc = extract.getLoc();
1517 auto indexCast = extract.getTensor().getDefiningOp<arith::IndexCastOp>();
1523 auto newExtract = tensor::ExtractOp::create(
1524 rewriter, loc, elementTy, indexCast.getIn(), extract.getIndices());
1535void FromElementsOp::getCanonicalizationPatterns(RewritePatternSet &results,
1536 MLIRContext *context) {
1537 results.
add<ExtractElementFromIndexCast>(context);
1544void GatherOp::getAsmResultNames(
1546 setNameFn(getResult(),
"gather");
1561RankedTensorType GatherOp::inferResultType(RankedTensorType sourceType,
1562 RankedTensorType indicesType,
1563 ArrayRef<int64_t> gatherDims,
1565 SmallVector<int64_t> resultShape(indicesType.getShape().drop_back());
1566 resultShape.reserve(resultShape.size() + sourceType.getRank());
1567 for (int64_t idx : llvm::seq<int64_t>(0, sourceType.getRank())) {
1568 if (llvm::binary_search(gatherDims, idx)) {
1570 resultShape.push_back(1);
1573 resultShape.push_back(sourceType.getDimSize(idx));
1575 return RankedTensorType::Builder(sourceType).setShape(resultShape);
1581 StringRef gatherOrScatter, StringRef sourceOrDest) {
1583 return op->
emitOpError(gatherOrScatter) <<
"_dims must be non-empty";
1585 int64_t numGatherDims = dims.size();
1586 if (numGatherDims > rank)
1588 <<
"_dims overflow " << sourceOrDest <<
" rank";
1591 <<
"_dims length must match the size of last dimension of indices";
1595 <<
"_dims value must be non-negative";
1598 <<
"_dims value must be smaller than " << sourceOrDest <<
" rank";
1600 for (
int64_t i = 1; i < numGatherDims; ++i) {
1601 if (dims[i - 1] >= dims[i])
1603 <<
"_dims values must be strictly increasing";
1608LogicalResult GatherOp::verify() {
1609 int64_t sourceRank = getSourceType().getRank();
1610 ArrayRef<int64_t> gatherDims = getGatherDims();
1612 getIndicesType().
getShape(), sourceRank,
1613 "gather",
"source")))
1616 RankedTensorType expectedResultType = GatherOp::inferResultType(
1617 getSourceType(), getIndicesType(), gatherDims,
false);
1618 RankedTensorType expectedRankReducedResultType = GatherOp::inferResultType(
1619 getSourceType(), getIndicesType(), gatherDims,
true);
1620 if (getResultType() != expectedResultType &&
1621 getResultType() != expectedRankReducedResultType) {
1625 << expectedResultType <<
" or its rank-reduced variant "
1626 << expectedRankReducedResultType <<
" (got: " << getResultType()
1633OpFoldResult GatherOp::fold(FoldAdaptor adaptor) {
1634 if (OpFoldResult reshapedSource = reshapeConstantSource(
1635 llvm::dyn_cast_if_present<DenseElementsAttr>(adaptor.getSource()),
1637 return reshapedSource;
1645void InsertOp::getAsmResultNames(
1647 setNameFn(getResult(),
"inserted");
1650LogicalResult InsertOp::verify() {
1652 auto destType = llvm::cast<RankedTensorType>(getDest().
getType());
1653 if (destType.getRank() !=
static_cast<int64_t
>(
getIndices().size()))
1654 return emitOpError(
"incorrect number of indices");
1658OpFoldResult InsertOp::fold(FoldAdaptor adaptor) {
1659 Attribute scalar = adaptor.getScalar();
1660 Attribute dest = adaptor.getDest();
1662 if (
auto splatDest = llvm::dyn_cast<SplatElementsAttr>(dest))
1663 if (scalar == splatDest.getSplatValue<Attribute>())
1672void GenerateOp::getAsmResultNames(
1674 setNameFn(getResult(),
"generated");
1677LogicalResult GenerateOp::reifyResultShapes(
1679 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
1681 for (
auto dim : llvm::seq<int64_t>(0,
getType().getRank())) {
1682 if (
getType().isDynamicDim(dim)) {
1683 reifiedReturnShapes[0][dim] = getOperand(idx++);
1685 reifiedReturnShapes[0][dim] =
1692LogicalResult GenerateOp::verify() {
1695 RankedTensorType resultType = llvm::cast<RankedTensorType>(
getType());
1702LogicalResult GenerateOp::verifyRegions() {
1703 RankedTensorType resultTy = llvm::cast<RankedTensorType>(
getType());
1705 if (!llvm::all_of(getBody().getArgumentTypes(),
1706 [](Type ty) {
return ty.
isIndex(); }))
1707 return emitError(
"all body arguments must be index");
1708 if (getBody().getNumArguments() != resultTy.getRank())
1709 return emitError(
"must have one body argument per input dimension");
1712 auto yieldOp = cast<YieldOp>(getBody().getBlocks().front().getTerminator());
1714 if (yieldOp.getValue().getType() != resultTy.getElementType())
1716 "body must be terminated with a `yield` operation of the tensor "
1722void GenerateOp::build(
1723 OpBuilder &
b, OperationState &
result, Type resultTy,
1726 build(
b,
result, resultTy, dynamicExtents);
1729 OpBuilder::InsertionGuard guard(
b);
1730 Region *bodyRegion =
result.regions.front().get();
1731 auto rank = llvm::cast<RankedTensorType>(resultTy).getRank();
1732 SmallVector<Type, 2> argumentTypes(rank,
b.getIndexType());
1733 SmallVector<Location, 2> argumentLocs(rank,
result.location);
1735 b.createBlock(bodyRegion, bodyRegion->
end(), argumentTypes, argumentLocs);
1745struct StaticTensorGenerate :
public OpRewritePattern<GenerateOp> {
1746 using OpRewritePattern<GenerateOp>::OpRewritePattern;
1748 LogicalResult matchAndRewrite(GenerateOp generateOp,
1749 PatternRewriter &rewriter)
const final {
1750 SmallVector<Value> foldedDynamicSizes;
1752 generateOp.getType(), generateOp.getDynamicExtents(),
1753 foldedDynamicSizes);
1756 if (foldedTensorType == generateOp.getType())
1759 auto loc = generateOp.getLoc();
1761 GenerateOp::create(rewriter, loc, foldedTensorType, foldedDynamicSizes);
1763 newOp.getBody().begin());
1765 generateOp.getType(), newOp);
1781struct ExtractFromTensorGenerate :
public OpRewritePattern<tensor::ExtractOp> {
1782 using OpRewritePattern<tensor::ExtractOp>::OpRewritePattern;
1784 LogicalResult matchAndRewrite(tensor::ExtractOp extract,
1785 PatternRewriter &rewriter)
const final {
1786 auto tensorFromElements = extract.getTensor().getDefiningOp<GenerateOp>();
1791 Block *body = &tensorFromElements.getBody().front();
1794 rewriter.
clone(op, mapping);
1805void GenerateOp::getCanonicalizationPatterns(RewritePatternSet &results,
1806 MLIRContext *context) {
1808 results.
add<ExtractFromTensorGenerate, StaticTensorGenerate>(context);
1815void RankOp::getAsmResultNames(
function_ref<
void(Value, StringRef)> setNameFn) {
1816 setNameFn(getResult(),
"rank");
1819OpFoldResult RankOp::fold(FoldAdaptor adaptor) {
1821 auto type = getOperand().getType();
1822 auto shapedType = llvm::dyn_cast<ShapedType>(type);
1823 if (shapedType && shapedType.hasRank())
1824 return IntegerAttr::get(IndexType::get(
getContext()), shapedType.getRank());
1825 return IntegerAttr();
1832void ReshapeOp::getAsmResultNames(
1834 setNameFn(getResult(),
"reshape");
1839 for (
auto dim : type.getShape())
1844LogicalResult ReshapeOp::verify() {
1845 TensorType operandType = llvm::cast<TensorType>(getSource().
getType());
1846 TensorType resultType = llvm::cast<TensorType>(getResult().
getType());
1849 return emitOpError(
"element types of source and destination tensor "
1850 "types should be the same");
1854 auto resultRankedType = llvm::dyn_cast<RankedTensorType>(resultType);
1855 auto operandRankedType = llvm::dyn_cast<RankedTensorType>(operandType);
1857 if (resultRankedType) {
1858 if (operandRankedType && resultRankedType.hasStaticShape() &&
1859 operandRankedType.hasStaticShape()) {
1861 return emitOpError(
"source and destination tensor should have the "
1862 "same number of elements");
1864 if (ShapedType::isDynamic(shapeSize))
1865 return emitOpError(
"cannot use shape operand with dynamic length to "
1866 "reshape to statically-ranked tensor type");
1867 if (shapeSize != resultRankedType.getRank())
1869 "length of shape operand differs from the result's tensor rank");
1874OpFoldResult ReshapeOp::fold(FoldAdaptor adaptor) {
1875 if (OpFoldResult reshapedSource = reshapeConstantSource(
1876 llvm::dyn_cast_if_present<DenseElementsAttr>(adaptor.getSource()),
1878 return reshapedSource;
1883 if (
auto reshapeOpProducer = getSource().getDefiningOp<ReshapeOp>()) {
1884 getSourceMutable().assign(reshapeOpProducer.getSource());
1888 auto source = getSource();
1889 auto sourceTy = dyn_cast<RankedTensorType>(source.getType());
1890 auto resultTy = dyn_cast<RankedTensorType>(
getType());
1891 if (!sourceTy || !resultTy || sourceTy != resultTy)
1896 if (sourceTy.getRank() <= 1)
1899 if (
auto fromElements =
getShape().getDefiningOp<tensor::FromElementsOp>()) {
1900 auto elements = fromElements.getElements();
1902 sourceTy.getRank() ==
static_cast<int64_t
>(elements.size());
1903 for (
int id = 0, s = elements.size();
id < s && dynamicNoop; ++
id) {
1904 auto element = elements[id];
1907 dynamicNoop &= cst.value() == sourceTy.getDimSize(
id);
1911 if (
auto dimOp = element.getDefiningOp<tensor::DimOp>()) {
1912 dynamicNoop &= dimOp.getSource() == source;
1916 cst.has_value() && cst.value() ==
static_cast<int64_t
>(id);
1920 dynamicNoop =
false;
1935void CollapseShapeOp::getAsmResultNames(
1937 setNameFn(getResult(),
"collapsed");
1940void ExpandShapeOp::getAsmResultNames(
1942 setNameFn(getResult(),
"expanded");
1945int64_t ExpandShapeOp::getCorrespondingSourceDim(int64_t resultDim) {
1946 assert(resultDim >= 0 && resultDim < getResultType().getRank() &&
1947 "invalid resultDim");
1948 for (
const auto &it : llvm::enumerate(getReassociationIndices()))
1949 if (llvm::is_contained(it.value(), resultDim))
1951 llvm_unreachable(
"could not find reassociation group");
1954FailureOr<SmallVector<OpFoldResult>>
1955ExpandShapeOp::inferOutputShape(OpBuilder &
b, Location loc,
1956 RankedTensorType expandedType,
1957 ArrayRef<ReassociationIndices> reassociation,
1958 ArrayRef<OpFoldResult> inputShape) {
1959 std::optional<SmallVector<OpFoldResult>> outputShape =
1964 return *outputShape;
1967SmallVector<OpFoldResult> ExpandShapeOp::getMixedOutputShape() {
1971void ExpandShapeOp::build(OpBuilder &builder, OperationState &
result,
1972 Type resultType, Value src,
1973 ArrayRef<ReassociationIndices> reassociation,
1974 ArrayRef<OpFoldResult> outputShape) {
1975 auto [staticOutputShape, dynamicOutputShape] =
1977 build(builder,
result, cast<RankedTensorType>(resultType), src,
1979 dynamicOutputShape, staticOutputShape);
1982void ExpandShapeOp::build(OpBuilder &builder, OperationState &
result,
1983 Type resultType, Value src,
1984 ArrayRef<ReassociationIndices> reassociation) {
1985 SmallVector<OpFoldResult> inputShape =
1987 auto tensorResultTy = cast<RankedTensorType>(resultType);
1988 FailureOr<SmallVector<OpFoldResult>> outputShape = inferOutputShape(
1989 builder,
result.location, tensorResultTy, reassociation, inputShape);
1990 SmallVector<OpFoldResult> outputShapeOrEmpty;
1991 if (succeeded(outputShape)) {
1992 outputShapeOrEmpty = *outputShape;
1994 build(builder,
result, tensorResultTy, src, reassociation,
1995 outputShapeOrEmpty);
1998SmallVector<AffineMap, 4> CollapseShapeOp::getReassociationMaps() {
2001SmallVector<ReassociationExprs, 4> CollapseShapeOp::getReassociationExprs() {
2003 getReassociationIndices());
2006SmallVector<AffineMap, 4> ExpandShapeOp::getReassociationMaps() {
2009SmallVector<ReassociationExprs, 4> ExpandShapeOp::getReassociationExprs() {
2011 getReassociationIndices());
2014RankedTensorType CollapseShapeOp::inferCollapsedType(
2015 RankedTensorType type, ArrayRef<ReassociationIndices> reassociation) {
2016 return inferCollapsedType(
2018 type.getContext(), reassociation)));
2024CollapseShapeOp::inferCollapsedType(RankedTensorType type,
2025 ArrayRef<AffineMap> reassociation) {
2026 auto shape = type.getShape();
2027 SmallVector<int64_t, 4> newShape;
2028 newShape.reserve(reassociation.size());
2033 unsigned currentDim = 0;
2034 for (AffineMap m : reassociation) {
2035 unsigned dim = m.getNumResults();
2036 auto band = shape.slice(currentDim, dim);
2038 if (llvm::is_contained(band, ShapedType::kDynamic))
2039 size = ShapedType::kDynamic;
2041 for (
unsigned d = 0; d < dim; ++d)
2042 size *= shape[currentDim + d];
2043 newShape.push_back(size);
2047 return RankedTensorType::get(newShape, type.getElementType());
2050void CollapseShapeOp::build(OpBuilder &
b, OperationState &
result, Value src,
2051 ArrayRef<ReassociationIndices> reassociation,
2052 ArrayRef<NamedAttribute> attrs) {
2053 auto srcType = llvm::cast<RankedTensorType>(src.
getType());
2054 RankedTensorType collapsedType = inferCollapsedType(srcType, reassociation);
2056 RankedTensorType::get(collapsedType.getShape(), srcType.getElementType(),
2057 srcType.getEncoding());
2058 result.addAttribute(getReassociationAttrStrName(),
2060 build(
b,
result, resultType, src, attrs);
2063template <
typename TensorReshapeOp,
bool isExpansion = std::is_same<
2064 TensorReshapeOp, ExpandShapeOp>::value>
2066 RankedTensorType expandedType,
2067 RankedTensorType collapsedType) {
2069 verifyReshapeLikeTypes(op, expandedType, collapsedType, isExpansion)))
2073 if (expandedType.hasStaticShape() && collapsedType.hasStaticShape()) {
2074 int64_t expandedNumElements = expandedType.getNumElements();
2075 int64_t collapsedNumElements = collapsedType.getNumElements();
2076 if (expandedNumElements != collapsedNumElements) {
2077 return op.emitOpError(
"number of elements must be preserved: ")
2078 << expandedNumElements <<
" != " << collapsedNumElements;
2082 auto maps = op.getReassociationMaps();
2083 RankedTensorType expectedType =
2084 CollapseShapeOp::inferCollapsedType(expandedType, maps);
2086 return op.emitOpError(
"expected collapsed type to be ")
2087 << expectedType <<
", but got " << collapsedType;
2091LogicalResult ExpandShapeOp::verify() {
2092 RankedTensorType srcType = getSrc().getType();
2093 RankedTensorType resultType = getResult().getType();
2095 if ((int64_t)getStaticOutputShape().size() != resultType.getRank())
2096 return emitOpError(
"expected number of static shape dims to be equal to "
2097 "the output rank (")
2098 << resultType.getRank() <<
") but found "
2099 << getStaticOutputShape().size() <<
" inputs instead";
2101 if ((int64_t)getOutputShape().size() !=
2102 llvm::count(getStaticOutputShape(), ShapedType::kDynamic))
2103 return emitOpError(
"mismatch in dynamic dims in output_shape and "
2104 "static_output_shape: static_output_shape has ")
2105 << llvm::count(getStaticOutputShape(), ShapedType::kDynamic)
2106 <<
" dynamic dims while output_shape has " << getOutputShape().size()
2117 ArrayRef<int64_t> resShape = getResult().getType().getShape();
2118 for (
auto [pos, shape] : llvm::enumerate(resShape))
2119 if (ShapedType::isStatic(shape) && shape != staticOutputShapes[pos])
2120 return emitOpError(
"invalid output shape provided at pos ") << pos;
2125LogicalResult CollapseShapeOp::verify() {
2126 CollapseShapeOp op = *
this;
2127 if (llvm::any_of(op.getReassociationIndices(),
2129 return op.emitOpError(
"reassociation indices must not be empty");
2131 RankedTensorType srcType = op.getSrc().getType();
2132 RankedTensorType resultType = op.getResult().getType();
2140template <
typename TensorReshapeOp>
2141struct FoldReshapeWithConstant : OpRewritePattern<TensorReshapeOp> {
2142 using OpRewritePattern<TensorReshapeOp>::OpRewritePattern;
2143 LogicalResult matchAndRewrite(TensorReshapeOp reshapeOp,
2144 PatternRewriter &rewriter)
const override {
2145 DenseElementsAttr attr;
2152 if (!reshapeOp.getResultType().hasStaticShape())
2155 reshapeOp.getResultType(), attr.
getRawData());
2162template <
typename TensorReshapeOp>
2163class FoldReshapeWithSplat :
public OpRewritePattern<TensorReshapeOp> {
2165 using OpRewritePattern<TensorReshapeOp>::OpRewritePattern;
2167 LogicalResult matchAndRewrite(TensorReshapeOp reshapeOp,
2168 PatternRewriter &rewriter)
const override {
2169 auto splatOp = reshapeOp.getSrc().template getDefiningOp<tensor::SplatOp>();
2170 if (!splatOp || !splatOp.getAggregate().getType().hasStaticShape())
2174 reshapeOp, reshapeOp.getResultType(), splatOp.getInput());
2181template <
typename TensorReshapeOp>
2182struct FoldReshapeWithFromElements : OpRewritePattern<TensorReshapeOp> {
2183 using OpRewritePattern<TensorReshapeOp>::OpRewritePattern;
2184 LogicalResult matchAndRewrite(TensorReshapeOp reshapeOp,
2185 PatternRewriter &rewriter)
const override {
2187 reshapeOp.getSrc().template getDefiningOp<FromElementsOp>();
2191 auto shapedTy = llvm::cast<ShapedType>(reshapeOp.getType());
2193 if (!shapedTy.hasStaticShape())
2197 fromElements.getElements());
2203struct FoldCollapseOfCastOp :
public OpRewritePattern<CollapseShapeOp> {
2204 using OpRewritePattern<CollapseShapeOp>::OpRewritePattern;
2206 LogicalResult matchAndRewrite(CollapseShapeOp collapseShapeOp,
2207 PatternRewriter &rewriter)
const override {
2208 auto castOp = collapseShapeOp.getSrc().getDefiningOp<tensor::CastOp>();
2212 RankedTensorType srcType =
2213 llvm::cast<RankedTensorType>(castOp.getSource().getType());
2214 RankedTensorType newResultType = CollapseShapeOp::inferCollapsedType(
2215 srcType, collapseShapeOp.getReassociationMaps());
2217 if (newResultType == collapseShapeOp.getResultType()) {
2219 collapseShapeOp.getSrcMutable().assign(castOp.getSource());
2222 auto newOp = CollapseShapeOp::create(rewriter, collapseShapeOp.getLoc(),
2223 newResultType, castOp.getSource(),
2224 collapseShapeOp.getReassociation());
2226 collapseShapeOp, collapseShapeOp.getResultType(), newOp);
2236struct ConvertToStaticExpandShape :
public OpRewritePattern<ExpandShapeOp> {
2237 using OpRewritePattern<ExpandShapeOp>::OpRewritePattern;
2239 LogicalResult matchAndRewrite(ExpandShapeOp expandOp,
2240 PatternRewriter &rewriter)
const override {
2241 auto castOp = expandOp.getSrc().getDefiningOp<CastOp>();
2245 ArrayRef<int64_t> castSrcShape = castOp.getSource().getType().getShape();
2246 SmallVector<ReassociationIndices, 4> reassoc =
2247 expandOp.getReassociationIndices();
2249 SmallVector<int64_t> newOutputShape(expandOp.getResultType().getShape());
2250 SmallVector<Value> dynamicOutputShape;
2251 auto outputIt = expandOp.getOutputShape().begin();
2253 for (
const auto &[inputDim, innerReassoc] : llvm::enumerate(reassoc)) {
2254 for (uint64_t outDim : innerReassoc) {
2255 if (ShapedType::isStatic(newOutputShape[outDim]))
2262 Value val = *outputIt;
2264 if (ShapedType::isDynamic(castSrcShape[inputDim])) {
2265 dynamicOutputShape.push_back(val);
2271 newOutputShape[outDim] = cst.getSExtValue();
2273 dynamicOutputShape.push_back(val);
2279 if (expandOp.getOutputShape().size() == dynamicOutputShape.size())
2283 SmallVector<int64_t> newInputShape(expandOp.getSrcType().getRank(), 1l);
2284 for (
auto inDim : llvm::seq<int>(0, newInputShape.size())) {
2285 for (
auto outDim : reassoc[inDim]) {
2286 auto ofr = newOutputShape[outDim];
2287 if (ShapedType::isDynamic(ofr)) {
2288 newInputShape[inDim] = ShapedType::kDynamic;
2291 newInputShape[inDim] *= ofr;
2295 SmallVector<OpFoldResult> outputOfr =
2300 Type elementType = expandOp.getSrcType().getElementType();
2301 auto inputType = RankedTensorType::get(
2302 newInputShape, elementType,
2305 auto outputType = RankedTensorType::get(
2306 newOutputShape, elementType,
2308 newOutputShape, elementType));
2309 auto inputCast = CastOp::create(rewriter, expandOp.getLoc(), inputType,
2311 auto newExpand = ExpandShapeOp::create(
2312 rewriter, expandOp.getLoc(), outputType, inputCast.getResult(),
2313 expandOp.getReassociationIndices(), outputOfr);
2315 newExpand.getResult());
2321void ExpandShapeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2322 MLIRContext *context) {
2324 ComposeReassociativeReshapeOps<ExpandShapeOp, ReshapeOpKind::kExpand>,
2325 ComposeExpandOfCollapseOp<ExpandShapeOp, CollapseShapeOp, CastOp>,
2326 ConvertToStaticExpandShape, FoldReshapeWithConstant<ExpandShapeOp>,
2327 FoldReshapeWithSplat<ExpandShapeOp>,
2328 FoldReshapeWithFromElements<ExpandShapeOp>>(context);
2331void CollapseShapeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2332 MLIRContext *context) {
2334 ComposeReassociativeReshapeOps<CollapseShapeOp, ReshapeOpKind::kCollapse>,
2335 ComposeCollapseOfExpandOp<CollapseShapeOp, ExpandShapeOp, CastOp,
2336 tensor::DimOp, RankedTensorType>,
2337 FoldReshapeWithConstant<CollapseShapeOp>,
2338 FoldReshapeWithSplat<CollapseShapeOp>,
2339 FoldReshapeWithFromElements<CollapseShapeOp>, FoldCollapseOfCastOp>(
2343OpFoldResult ExpandShapeOp::fold(FoldAdaptor adaptor) {
2345 adaptor.getOperands());
2348OpFoldResult CollapseShapeOp::fold(FoldAdaptor adaptor) {
2350 adaptor.getOperands());
2357void ExtractSliceOp::getAsmResultNames(
2359 setNameFn(getResult(),
"extracted_slice");
2366ExtractSliceOp::inferResultType(RankedTensorType sourceTensorType,
2367 ArrayRef<int64_t> staticSizes) {
2371 assert(
static_cast<int64_t
>(staticSizes.size()) ==
2372 sourceTensorType.getRank() &&
2373 "unexpected staticSizes not equal to rank of source");
2374 return RankedTensorType::get(staticSizes, sourceTensorType.getElementType(),
2375 sourceTensorType.getEncoding());
2380ExtractSliceOp::inferResultType(RankedTensorType sourceTensorType,
2381 ArrayRef<OpFoldResult> sizes) {
2382 SmallVector<int64_t> staticSizes;
2385 assert(
static_cast<int64_t
>(staticSizes.size()) ==
2386 sourceTensorType.getRank() &&
2387 "unexpected staticSizes not equal to rank of source");
2388 return RankedTensorType::get(staticSizes, sourceTensorType.getElementType(),
2389 sourceTensorType.getEncoding());
2400RankedTensorType ExtractSliceOp::inferCanonicalRankReducedResultType(
2401 unsigned desiredResultRank, RankedTensorType sourceRankedTensorType,
2402 ArrayRef<int64_t> sizes) {
2404 auto inferredType = llvm::cast<RankedTensorType>(
2405 inferResultType(sourceRankedTensorType, sizes));
2406 int rankDiff = inferredType.getRank() - desiredResultRank;
2408 auto shape = inferredType.getShape();
2409 llvm::SmallBitVector dimsToProject =
2411 SmallVector<int64_t> projectedShape;
2413 for (
unsigned pos = 0, e = shape.size(); pos < e; ++pos)
2414 if (!dimsToProject.test(pos))
2415 projectedShape.push_back(shape[pos]);
2417 RankedTensorType::get(projectedShape, inferredType.getElementType(),
2418 inferredType.getEncoding());
2420 return inferredType;
2423RankedTensorType ExtractSliceOp::inferCanonicalRankReducedResultType(
2424 unsigned desiredResultRank, RankedTensorType sourceRankedTensorType,
2425 ArrayRef<OpFoldResult> sizes) {
2426 SmallVector<int64_t> staticSizes;
2427 SmallVector<Value> dynamicSizes;
2429 return ExtractSliceOp::inferCanonicalRankReducedResultType(
2430 desiredResultRank, sourceRankedTensorType, staticSizes);
2435void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result,
2436 RankedTensorType resultType, Value source,
2437 ArrayRef<OpFoldResult> offsets,
2438 ArrayRef<OpFoldResult> sizes,
2439 ArrayRef<OpFoldResult> strides,
2440 ArrayRef<NamedAttribute> attrs) {
2441 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
2442 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
2446 auto sourceRankedTensorType = llvm::cast<RankedTensorType>(source.
getType());
2449 resultType = llvm::cast<RankedTensorType>(
2450 ExtractSliceOp::inferResultType(sourceRankedTensorType, staticSizes));
2452 result.addAttributes(attrs);
2453 build(
b,
result, resultType, source, dynamicOffsets, dynamicSizes,
2454 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
2455 b.getDenseI64ArrayAttr(staticSizes),
2456 b.getDenseI64ArrayAttr(staticStrides));
2461void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2462 ArrayRef<OpFoldResult> offsets,
2463 ArrayRef<OpFoldResult> sizes,
2464 ArrayRef<OpFoldResult> strides,
2465 ArrayRef<NamedAttribute> attrs) {
2466 build(
b,
result, RankedTensorType(), source, offsets, sizes, strides, attrs);
2471void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2472 ArrayRef<Range> ranges,
2473 ArrayRef<NamedAttribute> attrs) {
2475 build(
b,
result, RankedTensorType(), source, offsets, sizes, strides, attrs);
2480void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result,
2481 RankedTensorType resultType, Value source,
2483 ValueRange strides, ArrayRef<NamedAttribute> attrs) {
2484 SmallVector<OpFoldResult> offsetValues = llvm::map_to_vector<4>(
2485 offsets, [](Value v) -> OpFoldResult {
return v; });
2486 SmallVector<OpFoldResult> sizeValues =
2487 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
2488 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
2489 strides, [](Value v) -> OpFoldResult {
return v; });
2490 build(
b,
result, resultType, source, offsetValues, sizeValues, strideValues);
2494void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2496 ValueRange strides, ArrayRef<NamedAttribute> attrs) {
2497 build(
b,
result, RankedTensorType(), source, offsets, sizes, strides, attrs);
2502 RankedTensorType expectedType) {
2507 return op->
emitError(
"expected rank to be smaller or equal to ")
2508 <<
"the other rank. ";
2510 return op->
emitError(
"expected type to be ")
2511 << expectedType <<
" or a rank-reduced version. (size mismatch) ";
2513 return op->
emitError(
"expected element type to be ")
2514 << expectedType.getElementType();
2516 llvm_unreachable(
"unexpected extract_slice op verification result");
2522void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result,
2523 RankedTensorType resultType, Value source,
2524 ArrayRef<OpFoldResult> sizes,
2525 ArrayRef<NamedAttribute> attrs) {
2526 Attribute zeroIdxAttr =
b.getIndexAttr(0);
2527 Attribute oneIdxAttr =
b.getIndexAttr(1);
2528 SmallVector<OpFoldResult> readStrides(sizes.size(), oneIdxAttr);
2529 SmallVector<OpFoldResult> readOffsets(sizes.size(), zeroIdxAttr);
2530 build(
b,
result, resultType, source, readOffsets, sizes, readStrides, attrs);
2534LogicalResult ExtractSliceOp::verify() {
2535 RankedTensorType sourceType = getSourceType();
2538 RankedTensorType expectedType =
2539 ExtractSliceOp::inferResultType(sourceType,
getMixedSizes());
2547 sourceType.getShape(), getStaticOffsets(), getStaticSizes(),
2548 getStaticStrides(),
true);
2550 return getOperation()->emitError(boundsResult.
errorMessage);
2555llvm::SmallBitVector ExtractSliceOp::getDroppedDims() {
2560ExtractSliceOp::rankReduceIfNeeded(OpBuilder &
b, Location loc, Value value,
2561 ArrayRef<int64_t> desiredShape) {
2562 auto sourceTensorType = llvm::dyn_cast<RankedTensorType>(value.
getType());
2563 assert(sourceTensorType &&
"not a ranked tensor type");
2564 auto sourceShape = sourceTensorType.getShape();
2565 if (sourceShape.equals(desiredShape))
2567 auto maybeRankReductionMask =
2569 if (!maybeRankReductionMask)
2573 RankedTensorType::Builder(sourceTensorType).setShape(desiredShape));
2576LogicalResult ExtractSliceOp::reifyResultShapes(
2578 reifiedReturnShapes.resize(1);
2579 reifiedReturnShapes[0].reserve(
getType().getRank());
2582 for (
const auto &size :
enumerate(mixedSizes)) {
2583 if (droppedDims.test(size.index()))
2585 reifiedReturnShapes[0].push_back(size.value());
2606class ExtractSliceOpCastFolder final :
public OpRewritePattern<ExtractSliceOp> {
2608 using OpRewritePattern<ExtractSliceOp>::OpRewritePattern;
2610 LogicalResult matchAndRewrite(ExtractSliceOp sliceOp,
2611 PatternRewriter &rewriter)
const override {
2613 if (llvm::any_of(sliceOp.getOperands(), [](Value operand) {
2614 return matchPattern(operand, matchConstantIndex());
2618 auto castOp = sliceOp.getSource().getDefiningOp<CastOp>();
2627 cast<RankedTensorType>(castOp.getSource().getType()).getShape(),
2628 sliceOp.getStaticOffsets(), sliceOp.getStaticSizes(),
2629 sliceOp.getStaticStrides());
2634 Location loc = sliceOp.getLoc();
2635 Value newResult = ExtractSliceOp::create(
2636 rewriter, loc, sliceOp.getType(), castOp.getSource(),
2637 sliceOp.getOffsets(), sliceOp.getSizes(), sliceOp.getStrides(),
2638 sliceOp.getStaticOffsets(), sliceOp.getStaticSizes(),
2639 sliceOp.getStaticStrides());
2648template <
typename IterTy,
typename ElemTy>
2649static void sliceElements(IterTy values, ArrayRef<int64_t> counts,
2650 ArrayRef<int64_t> offsets, ArrayRef<int64_t> sizes,
2651 ArrayRef<int64_t> strides,
2652 llvm::SmallVectorImpl<ElemTy> *outValues) {
2653 assert(offsets.size() == sizes.size());
2654 assert(offsets.size() == strides.size());
2655 if (offsets.empty())
2658 int64_t offset = offsets.front();
2659 int64_t size = sizes.front();
2660 int64_t stride = strides.front();
2661 if (offsets.size() == 1) {
2662 for (int64_t i = 0; i < size; ++i, offset += stride)
2663 outValues->push_back(*(values + offset));
2668 for (int64_t i = 0; i < size; ++i, offset += stride) {
2669 auto begin = values + offset * counts.front();
2670 sliceElements<IterTy, ElemTy>(begin, counts.drop_front(),
2671 offsets.drop_front(), sizes.drop_front(),
2672 strides.drop_front(), outValues);
2679class ConstantOpExtractSliceFolder final
2680 :
public OpRewritePattern<ExtractSliceOp> {
2682 using OpRewritePattern<ExtractSliceOp>::OpRewritePattern;
2684 ConstantOpExtractSliceFolder(MLIRContext *context,
2686 : OpRewritePattern<ExtractSliceOp>(context),
2687 controlFn(std::move(controlFn)) {}
2689 LogicalResult matchAndRewrite(ExtractSliceOp op,
2690 PatternRewriter &rewriter)
const override {
2691 DenseElementsAttr attr;
2700 auto sourceType = llvm::cast<ShapedType>(op.getSource().getType());
2701 auto resultType = llvm::cast<ShapedType>(op.getResult().getType());
2702 if (!sourceType.hasStaticShape() || !resultType.hasStaticShape())
2709 int64_t count = sourceType.getNumElements();
2714 auto offsets = op.getStaticOffsets();
2715 if (llvm::is_contained(offsets, ShapedType::kDynamic))
2717 auto sizes = op.getStaticSizes();
2718 if (llvm::is_contained(sizes, ShapedType::kDynamic))
2720 auto strides = op.getStaticStrides();
2721 if (llvm::is_contained(strides, ShapedType::kDynamic))
2725 SmallVector<int64_t> counts;
2726 ArrayRef<int64_t> shape = sourceType.getShape();
2727 counts.reserve(shape.size());
2728 for (int64_t v : shape) {
2730 counts.push_back(count);
2734 SmallVector<Attribute> outValues;
2735 outValues.reserve(resultType.getNumElements());
2736 sliceElements(attr.
value_begin<Attribute>(), counts, offsets, sizes,
2737 strides, &outValues);
2754 patterns.
add<ConstantOpExtractSliceFolder>(patterns.
getContext(), controlFn);
2764 RankedTensorType nonReducedType =
2765 ExtractSliceOp::inferResultType(op.getSourceType(), mixedSizes);
2769 llvm::SmallBitVector droppedDims = op.getDroppedDims();
2770 if (droppedDims.none())
2771 return nonReducedType;
2775 for (
auto i : llvm::seq<int64_t>(mixedSizes.size()))
2776 if (!droppedDims.test(i))
2777 targetShape.push_back(nonReducedType.getDimSize(i));
2779 return RankedTensorType::get(targetShape, nonReducedType.getElementType(),
2780 nonReducedType.getEncoding());
2787 ExtractSliceOp newOp) {
2790 replacement = tensor::CastOp::create(rewriter, op.getLoc(), op.getType(),
2796void ExtractSliceOp::getCanonicalizationPatterns(RewritePatternSet &results,
2797 MLIRContext *context) {
2799 OpWithOffsetSizesAndStridesConstantArgumentFolder<
2800 ExtractSliceOp, SliceReturnTypeCanonicalizer, SliceCanonicalizer>,
2801 ExtractSliceOpCastFolder>(context);
2807 ShapedType shapedType) {
2814 auto shape = shapedType.getShape();
2815 for (
auto it : llvm::zip(op.getMixedSizes(),
shape))
2829 auto insertOp = extractOp.getSource().getDefiningOp<InsertSliceOp>();
2832 if (insertOp && insertOp.getSource().getType() == extractOp.getType() &&
2833 insertOp.isSameAs(extractOp, isSame))
2834 return insertOp.getSource();
2839OpFoldResult ExtractSliceOp::fold(FoldAdaptor adaptor) {
2840 if (OpFoldResult reshapedSource = reshapeConstantSource(
2841 llvm::dyn_cast_if_present<SplatElementsAttr>(adaptor.getSource()),
2843 return reshapedSource;
2844 if (getSourceType() ==
getType() &&
2846 return this->getSource();
2850 return OpFoldResult();
2855 auto rankedTensorType = llvm::cast<RankedTensorType>(
tensor.getType());
2856 unsigned rank = rankedTensorType.getRank();
2860 return b.createOrFold<tensor::ExtractSliceOp>(loc, targetType,
tensor,
2861 offsets, sizes, strides);
2868void InsertSliceOp::getAsmResultNames(
2870 setNameFn(getResult(),
"inserted_slice");
2884 result.addAttributes(attrs);
2885 build(
b,
result, dest.
getType(), source, dest, dynamicOffsets, dynamicSizes,
2886 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
2887 b.getDenseI64ArrayAttr(staticSizes),
2888 b.getDenseI64ArrayAttr(staticStrides));
2893void InsertSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2894 Value dest, ArrayRef<Range> ranges,
2895 ArrayRef<NamedAttribute> attrs) {
2897 build(
b,
result, source, dest, offsets, sizes, strides, attrs);
2901void InsertSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2903 ValueRange strides, ArrayRef<NamedAttribute> attrs) {
2904 SmallVector<OpFoldResult> offsetValues = llvm::map_to_vector<4>(
2905 offsets, [](Value v) -> OpFoldResult {
return v; });
2906 SmallVector<OpFoldResult> sizeValues =
2907 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
2908 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
2909 strides, [](Value v) -> OpFoldResult {
return v; });
2910 build(
b,
result, source, dest, offsetValues, sizeValues, strideValues);
2916 RankedTensorType srcType, RankedTensorType dstType,
2921 RankedTensorType expected =
2922 ExtractSliceOp::inferResultType(dstType, staticSizes);
2924 *expectedType = expected;
2929LogicalResult InsertSliceOp::verify() {
2931 RankedTensorType expectedType;
2934 getStaticSizes(), getStaticStrides(), &expectedType);
2941 getDestType().
getShape(), getStaticOffsets(), getStaticSizes(),
2942 getStaticStrides(),
true);
2944 return getOperation()->emitError(boundsResult.
errorMessage);
2967 auto prevInsertOp = insertOp.getDest().getDefiningOp<InsertSliceOp>();
2970 if (!prevInsertOp ||
2971 prevInsertOp.getSource().getType() != insertOp.getSource().getType() ||
2972 !prevInsertOp.isSameAs(insertOp, isSame))
2975 insertOp.getDestMutable().assign(prevInsertOp.getDest());
2987 auto extractOp = insertOp.getSource().
getDefiningOp<ExtractSliceOp>();
2990 if (!extractOp || extractOp.getSource() != insertOp.getDest() ||
2991 !extractOp.isSameAs(insertOp, isSame))
2994 return extractOp.getSource();
2997OpFoldResult InsertSliceOp::fold(FoldAdaptor) {
2998 if (getSourceType().hasStaticShape() &&
getType().hasStaticShape() &&
2999 getSourceType() ==
getType() &&
3001 return this->getSource();
3008 return OpFoldResult();
3011LogicalResult InsertSliceOp::reifyResultShapes(
3013 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
3022template <
typename InsertOpTy>
3023class InsertSliceOpConstantArgumentFolder final
3024 :
public OpRewritePattern<InsertOpTy> {
3026 using OpRewritePattern<InsertOpTy>::OpRewritePattern;
3028 LogicalResult matchAndRewrite(InsertOpTy insertSliceOp,
3029 PatternRewriter &rewriter)
const override {
3030 SmallVector<OpFoldResult> mixedOffsets(insertSliceOp.getMixedOffsets());
3031 SmallVector<OpFoldResult> mixedSizes(insertSliceOp.getMixedSizes());
3032 SmallVector<OpFoldResult> mixedStrides(insertSliceOp.getMixedStrides());
3041 SliceBoundsVerificationResult sliceResult =
3043 mixedOffsets, mixedSizes, mixedStrides);
3055 auto sourceTypeBase = ExtractSliceOp::inferCanonicalRankReducedResultType(
3056 insertSliceOp.getSourceType().getRank(), insertSliceOp.getDestType(),
3058 auto sourceType = RankedTensorType::get(
3059 sourceTypeBase.getShape(), sourceTypeBase.getElementType(),
3061 sourceTypeBase.getShape(),
3062 sourceTypeBase.getElementType()));
3063 Value toInsert = insertSliceOp.getSource();
3064 if (sourceType != insertSliceOp.getSourceType()) {
3065 OpBuilder::InsertionGuard g(rewriter);
3069 if (isa<InParallelOpInterface>(insertSliceOp->getParentOp()))
3071 toInsert = tensor::CastOp::create(rewriter, insertSliceOp.getLoc(),
3072 sourceType, toInsert);
3075 insertSliceOp, toInsert, insertSliceOp.getDest(), mixedOffsets,
3076 mixedSizes, mixedStrides);
3101template <
typename InsertOpTy>
3102struct InsertSliceOpCastFolder final :
public OpRewritePattern<InsertOpTy> {
3103 using OpRewritePattern<InsertOpTy>::OpRewritePattern;
3105 LogicalResult matchAndRewrite(InsertOpTy insertSliceOp,
3106 PatternRewriter &rewriter)
const override {
3107 if (llvm::any_of(insertSliceOp.getOperands(), [](Value operand) {
3108 return matchPattern(operand, matchConstantIndex());
3112 auto getSourceOfCastOp = [](Value v) -> std::optional<Value> {
3115 return std::nullopt;
3116 return castOp.getSource();
3118 std::optional<Value> sourceCastSource =
3119 getSourceOfCastOp(insertSliceOp.getSource());
3120 std::optional<Value> destCastSource =
3121 getSourceOfCastOp(insertSliceOp.getDest());
3122 if (!sourceCastSource && !destCastSource)
3126 (sourceCastSource ? *sourceCastSource : insertSliceOp.getSource());
3127 auto dst = (destCastSource ? *destCastSource : insertSliceOp.getDest());
3128 auto srcType = llvm::dyn_cast<RankedTensorType>(src.
getType());
3129 auto dstType = llvm::dyn_cast<RankedTensorType>(dst.getType());
3130 if (!srcType || !dstType)
3136 SmallVector<int64_t> staticSizes(insertSliceOp.getStaticSizes());
3138 staticSizes, srcType.getShape(),
true);
3139 if (!rankReductionMask.has_value())
3146 SmallVector<OpFoldResult> mixedSizes(insertSliceOp.getMixedSizes());
3147 int64_t rankReducedIdx = 0;
3148 for (
auto [idx, size] :
enumerate(staticSizes)) {
3149 if (!rankReductionMask.value().contains(idx) &&
3150 !srcType.isDynamicDim(rankReducedIdx)) {
3152 rewriter.
getContext(), srcType.getDimSize(rankReducedIdx));
3153 size = srcType.getDimSize(rankReducedIdx++);
3159 staticSizes, insertSliceOp.getStaticStrides()) !=
3160 SliceVerificationResult::Success)
3162 SliceBoundsVerificationResult sliceResult =
3164 mixedSizes, insertSliceOp.getMixedStrides());
3169 InsertOpTy::create(rewriter, insertSliceOp.getLoc(), src, dst,
3170 insertSliceOp.getMixedOffsets(), mixedSizes,
3171 insertSliceOp.getMixedStrides());
3174 bool isParallelInsert =
3175 std::is_same<InsertOpTy, ParallelInsertSliceOp>::value;
3176 if (!isParallelInsert && dst.getType() != insertSliceOp.getDestType()) {
3177 replacement = tensor::CastOp::create(rewriter, insertSliceOp.getLoc(),
3178 insertSliceOp.getDestType(),
3207template <
typename InsertOpTy>
3208struct InsertSliceOpSourceCastInserter final
3209 :
public OpRewritePattern<InsertOpTy> {
3210 using OpRewritePattern<InsertOpTy>::OpRewritePattern;
3212 LogicalResult matchAndRewrite(InsertOpTy insertSliceOp,
3213 PatternRewriter &rewriter)
const override {
3214 RankedTensorType srcType = insertSliceOp.getSourceType();
3215 if (srcType.getRank() != insertSliceOp.getDestType().getRank())
3217 SmallVector<int64_t> newSrcShape(srcType.getShape());
3218 for (int64_t i = 0; i < srcType.getRank(); ++i) {
3219 if (std::optional<int64_t> constInt =
3224 newSrcShape[i] = *constInt;
3230 RankedTensorType newSrcType = RankedTensorType::get(
3231 newSrcShape, srcType.getElementType(), srcType.getEncoding());
3232 if (srcType == newSrcType ||
3234 !tensor::CastOp::areCastCompatible(srcType, newSrcType))
3242 OpBuilder::InsertionGuard g(rewriter);
3246 if (isa<ParallelCombiningOpInterface>(insertSliceOp->getParentOp()))
3248 Value cast = tensor::CastOp::create(rewriter, insertSliceOp.getLoc(),
3249 newSrcType, insertSliceOp.getSource());
3251 insertSliceOp, cast, insertSliceOp.getDest(),
3252 insertSliceOp.getMixedOffsets(), insertSliceOp.getMixedSizes(),
3253 insertSliceOp.getMixedStrides());
3259llvm::SmallBitVector InsertSliceOp::getDroppedDims() {
3263void InsertSliceOp::getCanonicalizationPatterns(RewritePatternSet &results,
3264 MLIRContext *context) {
3265 results.
add<InsertSliceOpConstantArgumentFolder<InsertSliceOp>,
3266 InsertSliceOpCastFolder<InsertSliceOp>,
3267 InsertSliceOpSourceCastInserter<InsertSliceOp>>(context);
3274 auto rankedTensorType = llvm::cast<RankedTensorType>(dest.
getType());
3275 unsigned rank = rankedTensorType.getRank();
3279 return b.createOrFold<tensor::InsertSliceOp>(loc,
tensor, dest, offsets,
3288 setNameFn(getResult(),
"padded");
3291LogicalResult PadOp::verify() {
3292 auto sourceType = llvm::cast<RankedTensorType>(getSource().
getType());
3293 auto resultType = llvm::cast<RankedTensorType>(getResult().
getType());
3295 PadOp::inferResultType(sourceType, getStaticLow(), getStaticHigh());
3296 if (!expectedType) {
3297 return emitError(
"failed to infer expectedType from sourceType ")
3298 << sourceType <<
", specified resultType is " << resultType;
3300 if (resultType.getRank() != expectedType.getRank()) {
3302 << resultType <<
" does not match the inferred type "
3305 for (
int i = 0, e = sourceType.getRank(); i < e; ++i) {
3306 if (resultType.getDimSize(i) == expectedType.getDimSize(i))
3308 if (expectedType.isDynamicDim(i))
3311 << resultType <<
" does not match the inferred type "
3318LogicalResult PadOp::verifyRegions() {
3319 auto ®ion = getRegion();
3320 unsigned rank = llvm::cast<RankedTensorType>(getResult().
getType()).getRank();
3321 Block &block = region.front();
3323 return emitError(
"expected the block to have ") << rank <<
" arguments";
3327 if (!en.value().isIndex())
3329 << (en.index() + 1) <<
" to be an index";
3334 if (yieldOp.getValue().getType() !=
3336 return emitOpError(
"expected yield type to match shape element type");
3341RankedTensorType PadOp::inferResultType(RankedTensorType sourceType,
3342 ArrayRef<int64_t> staticLow,
3343 ArrayRef<int64_t> staticHigh,
3344 ArrayRef<int64_t> resultShape) {
3345 unsigned rank = sourceType.getRank();
3346 if (staticLow.size() != rank)
3347 return RankedTensorType();
3348 if (staticHigh.size() != rank)
3349 return RankedTensorType();
3350 if (!resultShape.empty() && resultShape.size() != rank)
3351 return RankedTensorType();
3353 SmallVector<int64_t, 4> inferredShape;
3354 for (
auto i : llvm::seq<unsigned>(0, rank)) {
3355 if (sourceType.isDynamicDim(i) || staticLow[i] == ShapedType::kDynamic ||
3356 staticHigh[i] == ShapedType::kDynamic) {
3357 inferredShape.push_back(resultShape.empty() ? ShapedType::kDynamic
3360 int64_t size = sourceType.getDimSize(i) + staticLow[i] + staticHigh[i];
3361 assert((resultShape.empty() || size == resultShape[i] ||
3362 resultShape[i] == ShapedType::kDynamic) &&
3363 "mismatch between inferred shape and result shape");
3364 inferredShape.push_back(size);
3368 Type elementType = sourceType.getElementType();
3369 return RankedTensorType::get(
3370 inferredShape, elementType,
3374void PadOp::build(OpBuilder &
b, OperationState &
result, Type resultType,
3375 Value source, ArrayRef<int64_t> staticLow,
3377 bool nofold, ArrayRef<NamedAttribute> attrs) {
3378 auto sourceType = llvm::cast<RankedTensorType>(source.
getType());
3380 resultType = inferResultType(sourceType, staticLow, staticHigh);
3381 result.addAttributes(attrs);
3382 build(
b,
result, resultType, source, low, high,
3383 b.getDenseI64ArrayAttr(staticLow),
b.getDenseI64ArrayAttr(staticHigh),
3384 nofold ?
b.getUnitAttr() : UnitAttr());
3387void PadOp::build(OpBuilder &
b, OperationState &
result, Type resultType,
3389 ArrayRef<NamedAttribute> attrs) {
3390 auto sourceType = llvm::cast<RankedTensorType>(source.
getType());
3391 unsigned rank = sourceType.getRank();
3392 SmallVector<int64_t, 4> staticVector(rank, ShapedType::kDynamic);
3393 build(
b,
result, resultType, source, staticVector, staticVector, low, high,
3397void PadOp::build(OpBuilder &
b, OperationState &
result, Type resultType,
3398 Value source, ArrayRef<OpFoldResult> low,
3399 ArrayRef<OpFoldResult> high,
bool nofold,
3400 ArrayRef<NamedAttribute> attrs) {
3401 auto sourceType = llvm::cast<RankedTensorType>(source.
getType());
3402 SmallVector<Value, 4> dynamicLow, dynamicHigh;
3403 SmallVector<int64_t, 4> staticLow, staticHigh;
3411 resultType = PadOp::inferResultType(sourceType, staticLow, staticHigh);
3413 assert(llvm::isa<RankedTensorType>(resultType));
3414 result.addAttributes(attrs);
3415 build(
b,
result, resultType, source, dynamicLow, dynamicHigh,
3416 b.getDenseI64ArrayAttr(staticLow),
b.getDenseI64ArrayAttr(staticHigh),
3417 nofold ?
b.getUnitAttr() : UnitAttr());
3420void PadOp::build(OpBuilder &
b, OperationState &
result, Type resultType,
3421 Value source, ArrayRef<OpFoldResult> low,
3422 ArrayRef<OpFoldResult> high, Value constantPadValue,
3423 bool nofold, ArrayRef<NamedAttribute> attrs) {
3424 build(
b,
result, resultType, source, low, high, nofold, attrs);
3427 Region *region =
result.regions[0].get();
3428 int sourceRank = llvm::cast<RankedTensorType>(source.
getType()).getRank();
3429 Repeated<Type> blockArgTypes(sourceRank,
b.getIndexType());
3430 SmallVector<Location> blockArgLocs(sourceRank,
result.location);
3434 OpBuilder::InsertionGuard guard(
b);
3435 b.createBlock(region, region->
end(), blockArgTypes, blockArgLocs);
3436 tensor::YieldOp::create(
b,
result.location, constantPadValue);
3439llvm::SmallBitVector PadOp::getPaddedDims() {
3440 llvm::SmallBitVector paddedDims(getSourceType().getRank());
3441 auto extractPaddedDims = [&](ArrayRef<OpFoldResult> paddingWidths) {
3442 for (
const auto &en :
enumerate(paddingWidths))
3444 paddedDims.set(en.index());
3446 extractPaddedDims(getMixedLowPad());
3447 extractPaddedDims(getMixedHighPad());
3454struct FoldStaticZeroPadding :
public OpRewritePattern<PadOp> {
3455 using OpRewritePattern<PadOp>::OpRewritePattern;
3457 LogicalResult matchAndRewrite(PadOp padTensorOp,
3458 PatternRewriter &rewriter)
const override {
3459 if (!padTensorOp.hasZeroLowPad() || !padTensorOp.hasZeroHighPad())
3461 if (padTensorOp.getNofold())
3464 padTensorOp, padTensorOp.getResult().
getType(),
3465 padTensorOp.getSource());
3471struct FoldSourceTensorCast :
public OpRewritePattern<PadOp> {
3472 using OpRewritePattern<PadOp>::OpRewritePattern;
3474 LogicalResult matchAndRewrite(PadOp padTensorOp,
3475 PatternRewriter &rewriter)
const override {
3476 auto castOp = padTensorOp.getSource().getDefiningOp<tensor::CastOp>();
3480 auto newResultType = PadOp::inferResultType(
3481 llvm::cast<RankedTensorType>(castOp.getSource().getType()),
3482 padTensorOp.getStaticLow(), padTensorOp.getStaticHigh(),
3483 padTensorOp.getResultType().getShape());
3485 if (newResultType == padTensorOp.getResultType()) {
3487 padTensorOp.getSourceMutable().assign(castOp.getSource());
3490 auto newOp = PadOp::create(
3491 rewriter, padTensorOp->getLoc(), newResultType,
3492 padTensorOp.getSource(), padTensorOp.getStaticLow(),
3493 padTensorOp.getStaticHigh(), padTensorOp.getLow(),
3494 padTensorOp.getHigh(), padTensorOp.getNofold(),
3497 padTensorOp.getRegion().cloneInto(&newOp.getRegion(), mapper);
3500 padTensorOp, padTensorOp.getResultType(), newOp);
3508struct FoldTargetTensorCast :
public OpRewritePattern<PadOp> {
3509 using OpRewritePattern<PadOp>::OpRewritePattern;
3511 LogicalResult matchAndRewrite(PadOp padTensorOp,
3512 PatternRewriter &rewriter)
const override {
3513 if (!padTensorOp.getResult().hasOneUse())
3516 dyn_cast<tensor::CastOp>(*padTensorOp->getUsers().begin());
3520 tensorCastOp.getDest().getType()))
3523 auto replacementOp = PadOp::create(
3524 rewriter, padTensorOp.getLoc(), tensorCastOp.getDest().getType(),
3525 padTensorOp.getSource(), padTensorOp.getStaticLow(),
3526 padTensorOp.getStaticHigh(), padTensorOp.getLow(),
3527 padTensorOp.getHigh(), padTensorOp.getNofold(),
3529 replacementOp.getRegion().takeBody(padTensorOp.getRegion());
3531 rewriter.
replaceOp(padTensorOp, replacementOp.getResult());
3532 rewriter.
replaceOp(tensorCastOp, replacementOp.getResult());
3572struct FoldOrthogonalPaddings :
public OpRewritePattern<PadOp> {
3573 using OpRewritePattern<PadOp>::OpRewritePattern;
3575 LogicalResult matchAndRewrite(PadOp padOp,
3576 PatternRewriter &rewriter)
const override {
3577 auto innerSliceOp = padOp.getSource().getDefiningOp<ExtractSliceOp>();
3580 auto outerPadOp = innerSliceOp.getSource().getDefiningOp<PadOp>();
3581 if (!outerPadOp || outerPadOp.getNofold())
3583 auto outerSliceOp = outerPadOp.getSource().getDefiningOp<ExtractSliceOp>();
3588 int64_t rank = padOp.getSourceType().getRank();
3589 if (outerSliceOp.getSourceType().getRank() != rank) {
3591 "cannot fold rank-reducing chain");
3595 if (!innerSliceOp.hasUnitStride() || !outerSliceOp.hasUnitStride()) {
3597 padOp,
"cannot fold non-unit stride ExtractSliceOps");
3601 if (!padOp.hasZeroLowPad() || !outerPadOp.hasZeroLowPad()) {
3603 "cannot fold PadOps with low padding");
3607 Attribute innerAttr, outerAttr;
3608 Value innerValue = padOp.getConstantPaddingValue();
3609 Value outerValue = outerPadOp.getConstantPaddingValue();
3610 if (!innerValue || !outerValue ||
3613 innerAttr != outerAttr) {
3615 padOp,
"cannot fold PadOps with different padding values");
3619 llvm::SmallBitVector innerDims = padOp.getPaddedDims();
3620 llvm::SmallBitVector outerDims = outerPadOp.getPaddedDims();
3621 if (innerDims.anyCommon(outerDims)) {
3623 padOp,
"cannot fold PadOps with common padding dimensions");
3631 SmallVector<OpFoldResult> newOffsets(rank, rewriter.
getIndexAttr(0));
3633 OpFoldResult innerOffset = innerSliceOp.getMixedOffsets()[en.index()];
3634 OpFoldResult outerOffset = outerSliceOp.getMixedOffsets()[en.index()];
3635 if (!innerDims.test(en.index()) &&
3637 en.value() = outerOffset;
3640 if (!outerDims.test(en.index()) &&
3642 en.value() = innerOffset;
3646 padOp,
"cannot find zero-offset and zero-padding pair");
3654 SmallVector<OpFoldResult> newSizes = innerSliceOp.getMixedSizes();
3656 if (!outerDims.test(en.index()))
3658 OpFoldResult sliceSize = innerSliceOp.getMixedSizes()[en.index()];
3659 int64_t sourceSize = innerSliceOp.getSourceType().getShape()[en.index()];
3660 assert(ShapedType::isStatic(sourceSize) &&
3661 "expected padded dimension to have a static size");
3664 padOp,
"cannot fold since the inner ExtractSliceOp size does not "
3665 "match the size of the outer padding");
3667 en.value() = outerSliceOp.getMixedSizes()[en.index()];
3671 SmallVector<OpFoldResult> newHighPad(rank, rewriter.
getIndexAttr(0));
3673 if (innerDims.test(en.index()))
3674 newHighPad[en.index()] = padOp.getMixedHighPad()[en.index()];
3675 if (outerDims.test(en.index()))
3676 newHighPad[en.index()] = outerPadOp.getMixedHighPad()[en.index()];
3681 auto newSliceOp = ExtractSliceOp::create(
3682 rewriter, padOp.getLoc(), outerSliceOp.getSource(), newOffsets,
3683 newSizes, innerSliceOp.getMixedStrides());
3684 auto newPadOp = PadOp::create(
3685 rewriter, padOp.getLoc(), padOp.getResultType(), newSliceOp.getResult(),
3686 padOp.getMixedLowPad(), newHighPad, padOp.getNofold(),
3689 newPadOp.getRegion().begin());
3690 rewriter.
replaceOp(padOp, newPadOp.getResult());
3695struct FoldStaticPadding :
public OpRewritePattern<PadOp> {
3696 using OpRewritePattern<PadOp>::OpRewritePattern;
3698 LogicalResult matchAndRewrite(PadOp padTensorOp,
3699 PatternRewriter &rewriter)
const override {
3700 Value input = padTensorOp.getSource();
3701 if (!llvm::isa<RankedTensorType>(input.
getType()))
3703 auto inputDims = llvm::cast<RankedTensorType>(input.
getType()).getShape();
3704 auto inputRank = inputDims.size();
3706 auto oldResultType =
3707 dyn_cast<RankedTensorType>(padTensorOp.getResult().getType());
3711 auto outputDims = oldResultType.getShape();
3714 SmallVector<int64_t> constOperandsLow;
3715 SmallVector<Value> newLows;
3716 for (
auto operand : padTensorOp.getLow()) {
3719 constOperandsLow.push_back(ShapedType::kDynamic);
3720 newLows.push_back(operand);
3723 constOperandsLow.push_back(intOp.getExtValue());
3725 SmallVector<int64_t> constOperandsHigh;
3726 SmallVector<Value> newHighs;
3727 for (
auto operand : padTensorOp.getHigh()) {
3730 constOperandsHigh.push_back(ShapedType::kDynamic);
3731 newHighs.push_back(operand);
3734 constOperandsHigh.push_back(intOp.getExtValue());
3737 SmallVector<int64_t> constLow(padTensorOp.getStaticLow());
3738 SmallVector<int64_t> constHigh(padTensorOp.getStaticHigh());
3741 if (inputDims.size() != outputDims.size() ||
3742 inputDims.size() != constLow.size() ||
3743 inputDims.size() != constHigh.size())
3748 for (
size_t i = 0; i < inputRank; i++) {
3749 if (constLow[i] == ShapedType::kDynamic)
3750 constLow[i] = constOperandsLow[lowCount++];
3751 if (constHigh[i] == ShapedType::kDynamic)
3752 constHigh[i] = constOperandsHigh[highCount++];
3755 auto staticLow = ArrayRef<int64_t>(constLow);
3756 auto staticHigh = ArrayRef<int64_t>(constHigh);
3759 SmallVector<int64_t> newOutDims;
3760 for (
size_t i = 0; i < inputRank; i++) {
3761 if (outputDims[i] == ShapedType::kDynamic) {
3762 newOutDims.push_back(
3763 (staticLow[i] == ShapedType::kDynamic ||
3764 staticHigh[i] == ShapedType::kDynamic ||
3765 inputDims[i] == ShapedType::kDynamic
3766 ? ShapedType::kDynamic
3767 : inputDims[i] + staticLow[i] + staticHigh[i]));
3769 newOutDims.push_back(outputDims[i]);
3773 if (SmallVector<int64_t>(outputDims) == newOutDims ||
3774 llvm::all_of(newOutDims,
3775 [&](int64_t x) {
return x == ShapedType::kDynamic; }))
3778 Type elementType = padTensorOp.getType().getElementType();
3779 auto newResultType = RankedTensorType::get(
3780 newOutDims, elementType,
3783 auto newOp = PadOp::create(
3784 rewriter, padTensorOp->getLoc(), newResultType, input, staticLow,
3785 staticHigh, newLows, newHighs, padTensorOp.getNofold(),
3789 padTensorOp.getRegion().cloneInto(&newOp.getRegion(), mapper);
3817struct FoldConsecutiveConstantPadding :
public OpRewritePattern<tensor::PadOp> {
3818 using OpRewritePattern<tensor::PadOp>::OpRewritePattern;
3820 LogicalResult matchAndRewrite(tensor::PadOp padOp,
3821 PatternRewriter &rewriter)
const override {
3822 if (padOp.getNofold()) {
3826 auto producerPad = padOp.getSource().getDefiningOp<tensor::PadOp>();
3827 if (!producerPad || producerPad.getNofold()) {
3829 padOp,
"producer is not a foldable tensor.pad op");
3833 Value consumerPadValue = padOp.getConstantPaddingValue();
3834 Value producerPadValue = producerPad.getConstantPaddingValue();
3835 if (!consumerPadValue || !producerPadValue ||
3836 consumerPadValue != producerPadValue) {
3839 "cannot fold PadOps with different or non-constant padding values");
3842 Location loc = padOp.getLoc();
3847 auto addPaddings = [&](ArrayRef<OpFoldResult> consumerPaddings,
3848 ArrayRef<OpFoldResult> producerPaddings) {
3849 SmallVector<OpFoldResult> sumPaddings;
3850 for (
auto [consumerIndex, producerIndex] :
3851 llvm::zip_equal(consumerPaddings, producerPaddings)) {
3853 rewriter, loc, d0 + d1, {consumerIndex, producerIndex}));
3858 SmallVector<OpFoldResult> newHighPad =
3859 addPaddings(padOp.getMixedHighPad(), producerPad.getMixedHighPad());
3860 SmallVector<OpFoldResult> newLowPad =
3861 addPaddings(padOp.getMixedLowPad(), producerPad.getMixedLowPad());
3863 auto newPadOp = tensor::PadOp::create(
3864 rewriter, padOp.getLoc(), padOp.getResultType(),
3865 producerPad.getSource(), newLowPad, newHighPad, padOp.getNofold(),
3868 newPadOp.getRegion().begin());
3869 rewriter.
replaceOp(padOp, newPadOp.getResult());
3877PadOp::reifyResultShapes(OpBuilder &
b,
3879 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
3880 SmallVector<OpFoldResult> lp = getMixedLowPad();
3881 SmallVector<OpFoldResult> hp = getMixedHighPad();
3882 for (int64_t i = 0; i < getResultType().getRank(); ++i) {
3883 if (!
getType().isDynamicDim(i)) {
3884 reifiedReturnShapes[0][i] =
b.getIndexAttr(
getType().getDimSize(i));
3887 Location loc = getLoc();
3888 Value dim =
b.createOrFold<tensor::DimOp>(
3891 AffineExpr d0, d1, d2;
3894 b, loc, {d0 + d1 + d2}, {dim, lp[i], hp[i]});
3899void PadOp::getCanonicalizationPatterns(RewritePatternSet &results,
3900 MLIRContext *context) {
3901 results.
add<FoldStaticZeroPadding, FoldSourceTensorCast, FoldTargetTensorCast,
3902 FoldOrthogonalPaddings, FoldStaticPadding,
3903 FoldConsecutiveConstantPadding>(context);
3915Value PadOp::getConstantPaddingValue() {
3916 auto yieldOp = dyn_cast<YieldOp>(getRegion().front().getTerminator());
3919 Value padValue = yieldOp.getValue();
3930OpFoldResult PadOp::fold(FoldAdaptor) {
3931 if (getResultType().hasStaticShape() && getResultType() == getSourceType() &&
3941OpResult ParallelInsertSliceOp::getTiedOpResult() {
3942 InParallelOpInterface parallelCombiningParent = getParallelCombiningParent();
3943 for (
const auto &it :
3944 llvm::enumerate(parallelCombiningParent.getYieldingOps())) {
3945 Operation &nextOp = it.value();
3946 if (&nextOp == getOperation())
3947 return parallelCombiningParent.getParentResult(it.index());
3949 llvm_unreachable(
"ParallelInsertSliceOp no tied OpResult found");
3953void ParallelInsertSliceOp::build(OpBuilder &
b, OperationState &
result,
3954 Value source, Value dest,
3955 ArrayRef<OpFoldResult> offsets,
3956 ArrayRef<OpFoldResult> sizes,
3957 ArrayRef<OpFoldResult> strides,
3958 ArrayRef<NamedAttribute> attrs) {
3959 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
3960 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
3964 result.addAttributes(attrs);
3965 build(
b,
result, {}, source, dest, dynamicOffsets, dynamicSizes,
3966 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
3967 b.getDenseI64ArrayAttr(staticSizes),
3968 b.getDenseI64ArrayAttr(staticStrides));
3973void ParallelInsertSliceOp::build(OpBuilder &
b, OperationState &
result,
3974 Value source, Value dest,
3975 ArrayRef<Range> ranges,
3976 ArrayRef<NamedAttribute> attrs) {
3978 build(
b,
result, source, dest, offsets, sizes, strides, attrs);
3982void ParallelInsertSliceOp::build(OpBuilder &
b, OperationState &
result,
3983 Value source, Value dest,
ValueRange offsets,
3985 ArrayRef<NamedAttribute> attrs) {
3986 SmallVector<OpFoldResult> offsetValues = llvm::map_to_vector<4>(
3987 offsets, [](Value v) -> OpFoldResult {
return v; });
3988 SmallVector<OpFoldResult> sizeValues =
3989 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
3990 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
3991 strides, [](Value v) -> OpFoldResult {
return v; });
3992 build(
b,
result, source, dest, offsetValues, sizeValues, strideValues);
3997void InsertSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
3998 Value dest, ArrayRef<OpFoldResult> sizes,
3999 ArrayRef<NamedAttribute> attrs) {
4000 Attribute zeroIdxAttr =
b.getIndexAttr(0);
4001 Attribute oneIdxAttr =
b.getIndexAttr(1);
4002 SmallVector<OpFoldResult> writeStrides(sizes.size(), oneIdxAttr);
4003 SmallVector<OpFoldResult> writeOffsets(sizes.size(), zeroIdxAttr);
4004 build(
b,
result, source, dest, writeOffsets, sizes, writeStrides, attrs);
4007LogicalResult ParallelInsertSliceOp::verify() {
4008 if (!isa<InParallelOpInterface>(getOperation()->getParentOp()))
4009 return this->
emitError(
"expected InParallelOpInterface parent, got:")
4010 << *(getOperation()->getParentOp());
4013 RankedTensorType expectedType;
4016 getStaticSizes(), getStaticStrides(), &expectedType);
4023 getDestType().
getShape(), getStaticOffsets(), getStaticSizes(),
4024 getStaticStrides(),
true);
4026 return getOperation()->emitError(boundsResult.
errorMessage);
4031void ParallelInsertSliceOp::getCanonicalizationPatterns(
4032 RewritePatternSet &results, MLIRContext *context) {
4033 results.
add<InsertSliceOpConstantArgumentFolder<ParallelInsertSliceOp>,
4034 InsertSliceOpCastFolder<ParallelInsertSliceOp>,
4035 InsertSliceOpSourceCastInserter<ParallelInsertSliceOp>>(context);
4038llvm::SmallBitVector ParallelInsertSliceOp::getDroppedDims() {
4043MutableOperandRange ParallelInsertSliceOp::getUpdatedDestinations() {
4044 return getDestMutable();
4047Operation *ParallelInsertSliceOp::getIteratingParent() {
4049 if (
auto combiningOp =
4050 dyn_cast<InParallelOpInterface>(getOperation()->getParentOp()))
4051 return combiningOp->getParentOp();
4059void ScatterOp::getAsmResultNames(
4061 setNameFn(getResult(),
"scatter");
4064LogicalResult ScatterOp::verify() {
4065 int64_t destRank = getDestType().getRank();
4066 ArrayRef<int64_t> scatterDims = getScatterDims();
4068 getIndicesType().
getShape(), destRank,
4069 "scatter",
"dest")))
4073 return emitOpError(
"requires 'unique' attribute to be set");
4080 RankedTensorType expectedSourceType = GatherOp::inferResultType(
4081 getDestType(), getIndicesType(), scatterDims,
false);
4082 RankedTensorType expectedRankReducedSourceType = GatherOp::inferResultType(
4083 getDestType(), getIndicesType(), scatterDims,
true);
4084 if (getSourceType() != expectedSourceType &&
4085 getSourceType() != expectedRankReducedSourceType) {
4089 << expectedSourceType <<
" or its rank-reduced variant "
4090 << expectedRankReducedSourceType <<
" (got: " << getSourceType()
4101void SplatOp::build(OpBuilder &builder, OperationState &
result, Value element,
4102 Type aggregateType,
ValueRange dynamicSizes) {
4103 build(builder,
result, aggregateType, element, dynamicSizes);
4106void SplatOp::build(OpBuilder &builder, OperationState &
result, Value element,
4107 ArrayRef<int64_t> staticShape,
ValueRange dynamicSizes) {
4108 auto aggregateType = RankedTensorType::get(staticShape, element.
getType());
4109 build(builder,
result, aggregateType, element, dynamicSizes);
4112void SplatOp::build(OpBuilder &builder, OperationState &
result, Value element,
4113 ArrayRef<OpFoldResult> sizes) {
4114 SmallVector<int64_t> staticShape;
4115 SmallVector<Value> dynamicSizes;
4117 build(builder,
result, element, staticShape, dynamicSizes);
4120void SplatOp::getAsmResultNames(
4122 setNameFn(getResult(),
"splat");
4125LogicalResult SplatOp::verify() {
4131SplatOp::reifyResultShapes(OpBuilder &builder,
4133 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
4135 for (int64_t i = 0; i <
getType().getRank(); ++i) {
4136 if (
getType().isDynamicDim(i)) {
4145OpFoldResult SplatOp::fold(FoldAdaptor adaptor) {
4146 auto constOperand = adaptor.getInput();
4147 if (!isa_and_nonnull<IntegerAttr, FloatAttr>(constOperand))
4151 if (!
getType().hasStaticShape())
4166 if (isa<InsertSliceOp>(op.getOperation()) ||
4167 isa<LoopLikeOpInterface>(op.getOperation()))
4200 isa<linalg::RelayoutOpInterface>(*op))
4208 auto newOp =
clone(rewriter, op, newResultTypes, newOperands);
4211 replacements.reserve(newOp->getNumResults());
4212 for (
auto [oldResult, newResult] :
4213 llvm::zip(op->getResults(), newOp->getResults())) {
4214 if (newResult.getType() != oldResult.getType()) {
4215 replacements.push_back(tensor::CastOp::create(
4216 rewriter, op->getLoc(), oldResult.
getType(), newResult));
4218 replacements.push_back(newResult);
4231void TensorDialect::getCanonicalizationPatterns(
4232 RewritePatternSet &results)
const {
4240#define GET_OP_CLASSES
4241#include "mlir/Dialect/Tensor/IR/TensorOps.cpp.inc"
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
std::string join(const Ts &...args)
Helper function to concatenate arguments into a std::string.
static Type getElementType(Type type)
Determine the element type of type.
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static void getDynamicSizes(RankedTensorType tp, ValueRange sizes, SmallVectorImpl< Value > &dynSizes)
Collects the dynamic dimension sizes for tp with the assumption that sizes are the dimension sizes fo...
static LogicalResult emit(SolverOp solver, const SMTEmissionOptions &options, mlir::raw_indented_ostream &stream)
Emit the SMT operations in the given 'solver' to the 'stream'.
static TensorType joinShapes(TensorType one, TensorType two)
Compute a TensorType that has the joined shape knowledge of the two given TensorTypes.
static Value foldExtractAfterInsert(ExtractOp extractOp)
If we have an ExtractOp consuming an InsertOp with the same indices, we can return the InsertOp's sca...
static LogicalResult verifyGatherOrScatterDims(Operation *op, ArrayRef< int64_t > dims, ArrayRef< int64_t > indices, int64_t rank, StringRef gatherOrScatter, StringRef sourceOrDest)
static LogicalResult produceSliceErrorMsg(SliceVerificationResult result, Operation *op, RankedTensorType expectedType)
static bool foldTensorCastPrecondition(DestinationStyleOpInterface op)
static LogicalResult foldInsertAfterInsertSlice(InsertSliceOp insertOp)
If we have two consecutive InsertSliceOp writing to the same slice, we can mutate the second InsertSl...
static Attribute propagateEncoding(Attribute encoding, ArrayRef< int64_t > shape, Type elementType)
Implements the VerifiableTensorEncoding contract documented in TensorEncoding.td for patterns that re...
static LogicalResult foldIdentityOffsetSizeAndStrideOpInterface(OffsetSizeAndStrideOpInterface op, ShapedType shapedType)
static Value foldExtractAfterInsertSlice(ExtractSliceOp extractOp)
If we have an ExtractSliceOp consuming an InsertSliceOp with the same slice, we can return the Insert...
static SliceVerificationResult verifyInsertSliceOp(RankedTensorType srcType, RankedTensorType dstType, ArrayRef< int64_t > staticOffsets, ArrayRef< int64_t > staticSizes, ArrayRef< int64_t > staticStrides, RankedTensorType *expectedType=nullptr)
Rank-reducing type verification for both InsertSliceOp and ParallelInsertSliceOp.
static RankedTensorType foldDynamicToStaticDimSizes(RankedTensorType type, ValueRange dynamicSizes, SmallVector< Value > &foldedDynamicSizes)
Given a ranked tensor type and a range of values that defines its dynamic dimension sizes,...
static llvm::SmallBitVector getDroppedDims(ArrayRef< int64_t > reducedShape, ArrayRef< OpFoldResult > mixedSizes)
Compute the dropped dimensions of a rank-reducing tensor.extract_slice op or rank-extending tensor....
static Value foldInsertAfterExtractSlice(InsertSliceOp insertOp)
Folds round-trip extract/insert slice op pairs.
static LogicalResult verifyTensorReshapeOp(TensorReshapeOp op, RankedTensorType expandedType, RankedTensorType collapsedType)
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
Base type for affine expression.
Attributes are known-constant values of operations.
MLIRContext * getContext() const
Return the context this attribute belongs to.
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
unsigned getNumArguments()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgListType getArguments()
iterator_range< iterator > without_terminator()
Return an iterator range over the operation within this block excluding the terminator operation at t...
This class is a general helper class for creating context-global objects like types,...
IntegerAttr getIndexAttr(int64_t value)
AffineExpr getAffineSymbolExpr(unsigned position)
Ty getType(Args &&...args)
Get or construct an instance of the type Ty with provided arguments.
AffineExpr getAffineDimExpr(unsigned position)
AffineMap getConstantAffineMap(int64_t val)
Returns a single constant result affine map with 0 dimensions and 0 symbols.
MLIRContext * getContext() const
auto value_begin() const
Get an iterator of the given type to the start of the held element values.
static DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Construct a dense elements attribute from a raw buffer representing the data for this attribute.
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
ArrayRef< char > getRawData() const
Return the raw storage data held by this attribute.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
auto lookupOrDefault(T from) const
Lookup a mapped value within the map.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
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.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
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...
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents a single result from folding an operation.
This class represents an operand of an operation.
This is a value defined by a result of an operation.
unsigned getResultNumber() const
Returns the number of this result.
Operation is the basic unit of execution within MLIR.
MutableArrayRef< OpOperand > getOpOperands()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
result_range getResults()
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
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.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
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,...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
void inlineRegionBefore(Region ®ion, Region &parent, Region::iterator before)
Move the blocks that belong to "region" before the given position in another region "parent".
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
bool hasRank() const
Returns if this type is ranked, i.e. it has a known number of dimensions.
Type getElementType() const
Returns the element type of this tensor type.
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
This class provides an abstraction over the different types of ranges over Values.
type_range getType() const
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Block * getParentBlock()
Return the Block in which this Value is defined.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
Speculatability
This enum is returned from the getSpeculatability method in the ConditionallySpeculatable op interfac...
constexpr auto Speculatable
constexpr auto NotSpeculatable
OpFoldResult makeComposedFoldedAffineApply(OpBuilder &b, Location loc, AffineMap map, ArrayRef< OpFoldResult > operands, bool composeAffineMin=false)
Constructs an AffineApplyOp that applies map to operands after composing the map with the maps of any...
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
ConstantIntRanges inferShapedDimOpInterface(ShapedDimOpInterface op, const IntegerValueRange &maybeDim)
Returns the integer range for the result of a ShapedDimOpInterface given the optional inferred ranges...
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
DynamicAPInt getIndex(const ConeV &cone)
Get the index of a cone, i.e., the volume of the parallelepiped spanned by its generators,...
Value constantIndex(OpBuilder &builder, Location loc, int64_t i)
Generates a constant of index type.
LogicalResult foldTensorCast(Operation *op)
Performs folding of any operand of op if it comes from a tensor::CastOp that can be folded.
bool hasFoldableTensorCastOperand(Operation *op)
Return true if any of the operands of op is a CastOp that can be folded into its consumer,...
void populateFoldConstantExtractSlicePatterns(RewritePatternSet &patterns, const ControlConstantExtractSliceFusionFn &controlFn=[](ExtractSliceOp op) { return false;})
Patterns to fold the extract slice op with its constant operand.
bool canFoldIntoProducerOp(CastOp castOp)
Determines whether the tensor::CastOp casts to a more static version of the source tensor.
SmallVector< Value > getUpdatedOperandsAfterCastOpFolding(DestinationStyleOpInterface op, SmallVector< Type > &newResTy)
Assuming that op contains at least one operand that is a foldable CastOp (i.e.
bool canFoldIntoConsumerOp(CastOp castOp)
Determines whether tensor::CastOp casts to a more dynamic version of the source tensor.
Value createCanonicalRankReducingInsertSliceOp(OpBuilder &b, Location loc, Value tensor, Value dest)
Create a rank-reducing InsertSliceOp @[0 .
Value createCanonicalRankReducingExtractSliceOp(OpBuilder &b, Location loc, Value tensor, RankedTensorType targetType)
Create a rank-reducing ExtractSliceOp @[0 .
bool isSameTypeWithoutEncoding(Type tp1, Type tp2)
Tests if types are the same when ignoring encoding on ranked tensors.
OpFoldResult getMixedSize(OpBuilder &builder, Location loc, Value value, int64_t dim)
Return the dimension of the given tensor value.
void populateFoldCollapseExtractPatterns(RewritePatternSet &patterns)
Patterns to fold extracts of a collapse_shaped tensor to an extract of the source tensor.
FailureOr< Value > getOrCreateDestination(OpBuilder &b, Location loc, OpResult opResult)
This is a helper function for DestinationStyleOpInterface.
bool preservesStaticInformation(Type source, Type target)
Returns true if target is a ranked tensor type that preserves static information available in the sou...
SmallVector< OpFoldResult > getMixedSizes(OpBuilder &builder, Location loc, Value value)
Return the dimensions of the given tensor value.
LogicalResult getOrCreateDestinations(OpBuilder &b, Location loc, Operation *op, SmallVector< Value > &result)
This is a helper function for DestinationStyleOpInterface.
std::function< bool(ExtractSliceOp)> ControlConstantExtractSliceFusionFn
Function to control the folding of constant and extract slice.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
SmallVector< OpFoldResult > getMixedValues(ArrayRef< int64_t > staticValues, ValueRange dynamicValues, MLIRContext *context)
Return a vector of OpFoldResults with the same size a staticValues, but all elements for which Shaped...
detail::constant_int_value_binder m_ConstantInt(IntegerAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor integer (splat) and writes the integer value to bin...
OpFoldResult getAsIndexOpFoldResult(MLIRContext *ctx, int64_t val)
Convert int64_t to integer attributes of index type and return them as OpFoldResult.
std::tuple< SmallVector< OpFoldResult >, SmallVector< OpFoldResult >, SmallVector< OpFoldResult > > getOffsetsSizesAndStrides(ArrayRef< Range > ranges)
Given an array of Range values, return a tuple of (offset vector, sizes vector, and strides vector) f...
SliceVerificationResult
Enum that captures information related to verifier error conditions on slice insert/extract type of o...
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
LogicalResult reifyResultShapes(OpBuilder &b, Operation *op, ReifiedRankedShapedTypeDims &reifiedReturnShapes)
Reify the shape of the result of an operation (typically in terms of the shape of its operands).
LogicalResult foldDynamicStrideList(SmallVectorImpl< OpFoldResult > &strides)
Returns "success" when any of the elements in strides is a constant value.
llvm::function_ref< void(Value, const IntegerValueRange &)> SetIntLatticeFn
Similar to SetIntRangeFn, but operating on IntegerValueRange lattice values.
SliceBoundsVerificationResult verifyInBoundsSlice(ArrayRef< int64_t > shape, ArrayRef< int64_t > staticOffsets, ArrayRef< int64_t > staticSizes, ArrayRef< int64_t > staticStrides, bool generateErrorMessage=false)
Verify that the offsets/sizes/strides-style access into the given shape is in-bounds.
LogicalResult verifyDynamicDimensionCount(Operation *op, ShapedType type, ValueRange dynamicSizes)
Verify that the number of dynamic size operands matches the number of dynamic dimensions in the shape...
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
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...
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
SmallVector< AffineMap, 4 > getSymbolLessAffineMaps(ArrayRef< ReassociationExprs > reassociation)
Constructs affine maps out of Array<Array<AffineExpr>>.
OpFoldResult foldReshapeOp(ReshapeOpTy reshapeOp, ArrayRef< Attribute > operands)
bool hasValidSizesOffsets(SmallVector< int64_t > sizesOrOffsets)
Helper function to check whether the passed in sizes or offsets are valid.
bool wouldOpBeTriviallyDead(Operation *op)
Return true if the given operation would be dead if unused, and has no side effects on memory that wo...
SmallVector< SmallVector< OpFoldResult > > ReifiedRankedShapedTypeDims
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
bool isZeroInteger(OpFoldResult v)
Return "true" if v is an integer value/attribute with constant value 0.
void dispatchIndexOpFoldResults(ArrayRef< OpFoldResult > ofrs, SmallVectorImpl< Value > &dynamicVec, SmallVectorImpl< int64_t > &staticVec)
Helper function to dispatch multiple OpFoldResults according to the behavior of dispatchIndexOpFoldRe...
SmallVector< SmallVector< AffineExpr, 2 >, 2 > convertReassociationIndicesToExprs(MLIRContext *context, ArrayRef< ReassociationIndices > reassociationIndices)
Convert reassociation indices to affine expressions.
bool isReassociationValid(ArrayRef< AffineMap > reassociation, int *invalidIndex=nullptr)
Return true if the reassociation specification is valid, false otherwise.
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
std::optional< SmallVector< OpFoldResult > > inferExpandShapeOutputShape(OpBuilder &b, Location loc, ShapedType expandedType, ArrayRef< ReassociationIndices > reassociation, ArrayRef< OpFoldResult > inputShape)
Infer the output shape for a {memref|tensor}.expand_shape when it is possible to do so.
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
OpFoldResult getAsOpFoldResult(Value val)
Given a value, try to extract a constant Attribute.
llvm::SmallBitVector getPositionsOfShapeOne(unsigned rank, ArrayRef< int64_t > shape)
std::optional< llvm::SmallDenseSet< unsigned > > computeRankReductionMask(ArrayRef< int64_t > originalShape, ArrayRef< int64_t > reducedShape, bool matchDynamic=false)
Given an originalShape and a reducedShape assumed to be a subset of originalShape with some 1 entries...
LogicalResult verifyCompatibleShape(ArrayRef< int64_t > shape1, ArrayRef< int64_t > shape2)
Returns success if the given two shapes are compatible.
SmallVector< int64_t, 2 > ReassociationIndices
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
SliceVerificationResult isRankReducedType(ShapedType originalType, ShapedType candidateReducedType)
Check if originalType can be rank reduced to candidateReducedType type by dropping some dimensions wi...
ArrayAttr getReassociationIndicesAttribute(Builder &b, ArrayRef< ReassociationIndices > reassociation)
Wraps a list of reassociations in an ArrayAttr.
llvm::function_ref< Fn > function_ref
SmallVector< NamedAttribute > getPrunedAttributeList(Operation *op, ArrayRef< StringRef > elidedAttrs)
LogicalResult foldDynamicOffsetSizeList(SmallVectorImpl< OpFoldResult > &offsetsOrSizes)
Returns "success" when any of the elements in offsetsOrSizes is a constant value.
std::pair< SmallVector< int64_t >, SmallVector< Value > > decomposeMixedValues(ArrayRef< OpFoldResult > mixedValues)
Decompose a vector of mixed static or dynamic values into the corresponding pair of arrays.
Folds a tensor.cast op into a consuming DestinationStyleOpInterface op if the tensor....
LogicalResult matchAndRewrite(DestinationStyleOpInterface op, PatternRewriter &rewriter) const override
A canonicalizer wrapper to replace ExtractSliceOps.
void operator()(PatternRewriter &rewriter, ExtractSliceOp op, ExtractSliceOp newOp)
Return the canonical type of the result of an extract_slice op.
RankedTensorType operator()(ExtractSliceOp op, ArrayRef< OpFoldResult > mixedOffsets, ArrayRef< OpFoldResult > mixedSizes, ArrayRef< OpFoldResult > mixedStrides)
OpInterfaceRewritePattern(MLIRContext *context, PatternBenefit benefit=1)
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.
Idiomatic saturated operations on values like offsets, sizes, and strides.
static SaturatedInteger wrap(int64_t v)
FailureOr< SaturatedInteger > desaturate(SaturatedInteger other)
bool isValid
If set to "true", the slice bounds verification was successful.
std::string errorMessage
An error message that can be printed during op verification.