36#include "llvm/ADT/DenseSet.h"
37#include "llvm/ADT/Repeated.h"
38#include "llvm/ADT/STLExtras.h"
39#include "llvm/ADT/SmallBitVector.h"
40#include "llvm/ADT/SmallVectorExtras.h"
41#include "llvm/ADT/StringRef.h"
42#include "llvm/Support/Casting.h"
43#include "llvm/Support/MathExtras.h"
56 auto verifiable = dyn_cast_or_null<VerifiableTensorEncoding>(encoding);
64 return succeeded(verifiable.verifyEncoding(
shape, elementType,
emit))
74 if (
auto op = arith::ConstantOp::materialize(builder, value, type, loc))
76 if (complex::ConstantOp::isBuildableWith(value, type))
77 return complex::ConstantOp::create(builder, loc, type,
78 llvm::cast<ArrayAttr>(value));
84 auto tensorType = llvm::cast<RankedTensorType>(value.
getType());
85 if (tensorType.isDynamicDim(dim))
86 return builder.
createOrFold<tensor::DimOp>(loc, value, dim);
93 auto tensorType = llvm::cast<RankedTensorType>(value.
getType());
95 for (
int64_t i = 0; i < tensorType.getRank(); ++i)
102 auto tensorType = llvm::dyn_cast<TensorType>(opResult.
getType());
103 assert(tensorType &&
"expected tensor type");
107 auto destOp = opResult.
getDefiningOp<DestinationStyleOpInterface>();
109 return destOp.getTiedOpOperand(opResult)->get();
117 if (!tensorType.hasStaticShape()) {
125 for (
int64_t sz : tensorType.getShape())
126 mixedSizes.push_back(
b.getIndexAttr(sz));
131 if (
auto rankedTensorType = dyn_cast<RankedTensorType>(tensorType))
132 encoding = rankedTensorType.getEncoding();
133 Value emptyTensor = tensor::EmptyOp::create(
134 b, loc, mixedSizes, tensorType.getElementType(), encoding);
142 if (llvm::isa<TensorType>(opResult.getType())) {
144 if (failed(destination))
146 result.push_back(*destination);
153 if (
auto rtp1 = llvm::dyn_cast<RankedTensorType>(tp1)) {
154 if (
auto rtp2 = llvm::dyn_cast<RankedTensorType>(tp2))
155 return rtp1.getShape() == rtp2.getShape() &&
156 rtp1.getElementType() == rtp2.getElementType();
166 llvm::SmallBitVector droppedDims(mixedSizes.size());
167 int64_t shapePos = reducedShape.size() - 1;
169 for (
const auto &size : enumerate(llvm::reverse(mixedSizes))) {
170 size_t idx = mixedSizes.size() - size.index() - 1;
172 bool isStaticUnitSize =
173 isa<Attribute>(size.value()) &&
174 llvm::cast<IntegerAttr>(cast<Attribute>(size.value())).getInt() == 1;
179 assert(isStaticUnitSize &&
"expected unit dim");
180 droppedDims.set(idx);
185 if (!isStaticUnitSize) {
191 if (reducedShape[shapePos] == 1) {
197 droppedDims.set(idx);
200 assert(shapePos < 0 &&
"dimension mismatch");
207static RankedTensorType
211 assert(type.getNumDynamicDims() == dynamicSizes.size() &&
212 "incorrect number of dynamic sizes");
216 for (
int64_t i = 0, e = type.getRank(); i < e; ++i) {
217 if (type.isDynamicDim(i)) {
218 Value dynamicSize = dynamicSizes[ctr++];
220 if (cst.has_value()) {
222 if (cst.value() < 0) {
223 foldedDynamicSizes.push_back(dynamicSize);
226 staticShape[i] = *cst;
228 foldedDynamicSizes.push_back(dynamicSize);
233 return RankedTensorType::get(staticShape, type.getElementType(),
242 if (inputs.size() != 1 || outputs.size() != 1)
244 Type a = inputs.front(),
b = outputs.front();
245 auto aT = dyn_cast<TensorType>(a);
246 auto bT = dyn_cast<TensorType>(
b);
250 if (aT.getElementTypeBitWidth() != bT.getElementTypeBitWidth())
261 using OpRewritePattern<BitcastOp>::OpRewritePattern;
263 LogicalResult matchAndRewrite(BitcastOp tensorBitcast,
264 PatternRewriter &rewriter)
const final {
265 auto tensorBitcastOperand =
266 tensorBitcast.getOperand().getDefiningOp<BitcastOp>();
267 if (!tensorBitcastOperand)
270 auto resultType = cast<TensorType>(tensorBitcast.getType());
271 rewriter.replaceOpWithNewOp<BitcastOp>(tensorBitcast, resultType,
272 tensorBitcastOperand.getOperand());
281 results.
add<ChainedTensorBitcast>(context);
289 setNameFn(getResult(),
"cast");
295 auto sourceType = llvm::dyn_cast<RankedTensorType>(source);
296 auto targetType = llvm::dyn_cast<RankedTensorType>(
target);
299 if (!sourceType || !targetType)
303 if (sourceType.getElementType() != targetType.getElementType())
307 if (sourceType.getRank() != targetType.getRank())
311 if (sourceType.getEncoding() != targetType.getEncoding())
315 for (
auto t : llvm::zip(sourceType.getShape(), targetType.getShape())) {
316 if (ShapedType::isStatic(std::get<0>(t)) &&
317 ShapedType::isDynamic(std::get<1>(t)))
353 castOp.getSource().getType());
386 if (llvm::isa<BlockArgument>(opOperand.get()))
388 auto castOp = opOperand.get().getDefiningOp<tensor::CastOp>();
389 return castOp && canFoldIntoConsumerOp(castOp);
396 newOperands.reserve(op->getNumOperands());
402 for (
OpOperand &opOperand : op->getOpOperands()) {
403 auto tensorCastOp = opOperand.get().getDefiningOp<tensor::CastOp>();
405 newOperands.push_back(fold ? tensorCastOp.getOperand() : opOperand.get());
406 if (op.isDpsInit(&opOperand) &&
407 !llvm::isa<MemRefType>(newOperands.back().getType()))
408 newResTy[dpsInitIdx++] = newOperands.back().getType();
418 auto castOp = operand.get().getDefiningOp<tensor::CastOp>();
420 operand.set(castOp.getOperand());
428 if (inputs.size() != 1 || outputs.size() != 1)
430 Type a = inputs.front(),
b = outputs.front();
431 auto aT = llvm::dyn_cast<TensorType>(a);
432 auto bT = llvm::dyn_cast<TensorType>(
b);
436 if (aT.getElementType() != bT.getElementType())
453 if (rank != two.getRank())
458 for (
int64_t i = 0; i < rank; ++i) {
459 if (one.isDynamicDim(i)) {
460 join.push_back(two.getDimSize(i));
463 if (two.isDynamicDim(i)) {
464 join.push_back(one.getDimSize(i));
467 if (one.getDimSize(i) != two.getDimSize(i))
469 join.push_back(one.getDimSize(i));
479 using OpRewritePattern<CastOp>::OpRewritePattern;
481 LogicalResult matchAndRewrite(CastOp tensorCast,
482 PatternRewriter &rewriter)
const final {
483 auto tensorCastOperand = tensorCast.getOperand().getDefiningOp<CastOp>();
485 if (!tensorCastOperand)
489 llvm::cast<TensorType>(tensorCastOperand.getOperand().getType());
490 auto intermediateType = llvm::cast<TensorType>(tensorCastOperand.getType());
491 auto resultType = llvm::cast<TensorType>(tensorCast.getType());
505 auto newJoin =
joinShapes(sourceType, resultType);
506 if (firstJoin != newJoin)
509 rewriter.replaceOpWithNewOp<CastOp>(tensorCast, resultType,
510 tensorCastOperand.getOperand());
528 using OpRewritePattern<CastOp>::OpRewritePattern;
530 LogicalResult matchAndRewrite(CastOp tensorCast,
531 PatternRewriter &rewriter)
const final {
532 auto extractOperand =
533 tensorCast.getOperand().getDefiningOp<ExtractSliceOp>();
536 auto rankedResultType =
537 llvm::dyn_cast<RankedTensorType>(tensorCast.getType());
538 if (!rankedResultType)
542 rankedResultType.getShape() ==
543 llvm::cast<RankedTensorType>(tensorCast.getSource().getType())
547 SmallVector<OpFoldResult, 4> sizes = extractOperand.getMixedSizes();
549 extractOperand.getStaticSizes(), extractOperand.getType().getShape());
551 for (
size_t i = 0, e = sizes.size(); i < e; i++) {
552 if (dimMask && dimMask->count(i))
554 int64_t dim = rankedResultType.getShape()[dimIndex++];
555 if (ShapedType::isDynamic(dim))
557 sizes[i] = rewriter.getIndexAttr(dim);
560 rewriter.replaceOpWithNewOp<ExtractSliceOp>(
561 tensorCast, rankedResultType, extractOperand.getSource(),
562 extractOperand.getMixedOffsets(), sizes,
563 extractOperand.getMixedStrides());
572 results.
add<ChainedTensorCast, TensorCastExtractSlice>(context);
579RankedTensorType ConcatOp::inferResultType(
int64_t dim,
TypeRange inputTypes) {
580 assert(!inputTypes.empty() &&
"cannot concatenate 0 tensors");
582 llvm::map_to_vector<4>(inputTypes, llvm::CastTo<RankedTensorType>);
583 int64_t concatRank = tensorTypes[0].getRank();
586 assert(dim >= 0 && dim < concatRank &&
"Invalid concatenation dim");
589 for (
int64_t i = 0, e = concatRank; i < e; ++i) {
593 for (
auto tensorType : tensorTypes)
598 for (
auto tensorType : tensorTypes)
601 sizes[dim] = concatSize.asInteger();
602 return RankedTensorType::get(sizes, tensorTypes[0].
getElementType());
607 FailureOr<RankedTensorType> resultType =
608 inferResultType(dim, inputs.
getTypes());
609 assert(succeeded(resultType) &&
"failed to infer concatenation result type");
610 build(builder,
result, *resultType, dim, inputs);
613LogicalResult ConcatOp::verify() {
614 if (getInputs().size() < 1)
615 return emitOpError(
"requires at least one input");
618 for (
auto input : getInputs())
619 inputTypes.push_back(cast<RankedTensorType>(input.getType()));
621 RankedTensorType resultType = getResultType();
622 int64_t resultRank = getRank();
623 if (llvm::any_of(inputTypes, [resultRank](RankedTensorType type) {
624 return type.getRank() != resultRank;
626 return emitOpError(
"rank of concatenated inputs must match result rank");
628 Type resultElementType = resultType.getElementType();
629 if (llvm::any_of(inputTypes, [&](RankedTensorType type) {
630 return type.getElementType() != resultElementType;
632 return emitOpError(
"inputs and result element type must match");
635 if (dim >= resultRank)
636 return emitOpError(
"concatenation dim must be less than the tensor rank");
639 for (
int64_t i = 0, e = resultRank; i < e; ++i) {
643 for (
auto tensorType : inputTypes) {
644 FailureOr<SaturatedInteger> maybeSize =
647 return emitOpError(
"static concatenation size mismatch along ")
648 <<
"non-concatenated dimension " << i;
654 for (
auto tensorType : inputTypes)
657 sizes[dim] = concatSize.asInteger();
658 auto inferredResultType =
661 for (
auto [inferredSize, actualSize] :
662 llvm::zip_equal(inferredResultType.getShape(), resultType.getShape())) {
663 bool hasDynamic = ShapedType::isDynamic(inferredSize) ||
664 ShapedType::isDynamic(actualSize);
665 if (!hasDynamic && inferredSize != actualSize)
666 return emitOpError(
"result type ")
667 << resultType <<
"does not match inferred shape "
668 << inferredResultType <<
" static sizes";
674FailureOr<SmallVector<Value>> ConcatOp::decomposeOperation(
OpBuilder &builder) {
675 size_t numInputs = getInputs().size();
676 uint64_t concatDim = getDim();
679 inputShapes.reserve(numInputs);
681 concatOffsets.reserve(numInputs);
688 for (
auto [
index, input] : llvm::enumerate(getInputs())) {
692 outputShape = inputShape;
693 concatOffsets.push_back(zero);
695 concatOffsets.push_back(outputShape[concatDim]);
697 builder, loc, addExpr,
698 {outputShape[concatDim], inputShape[concatDim]});
700 inputShapes.emplace_back(std::move(inputShape));
710 for (
auto [
index, input] : llvm::enumerate(getInputs())) {
711 offsets[concatDim] = concatOffsets[
index];
712 auto insertSlice = tensor::InsertSliceOp::create(
723ConcatOp::reifyResultShapes(
OpBuilder &builder,
727 RankedTensorType inferredResultType = inferResultType(dim, inputs.
getTypes());
729 Value init = inputs[0];
737 for (
int64_t i = 0; i < rank; ++i) {
740 if (!
getType().isDynamicDim(i)) {
742 }
else if (!inferredResultType.isDynamicDim(i)) {
745 builder.
getIndexAttr(inferredResultType.getDimSize(i)));
747 reifiedReturnShapes[0][i] =
748 tensor::DimOp::create(builder, init.
getLoc(), init, i).getResult();
752 if (
getType().isDynamicDim(dim)) {
757 for (
auto [idx, input] : llvm::enumerate(inputs.drop_front())) {
760 builder.
createOrFold<tensor::DimOp>(input.getLoc(), input, dim));
768 reifiedReturnShapes[0][dim] =
774void ConcatOp::getAsmResultNames(
776 setNameFn(getResult(),
"concat");
781 if (inputs.size() == 1 && inputs[0].
getType() == getResultType())
789 using OpRewritePattern<ConcatOp>::OpRewritePattern;
791 LogicalResult matchAndRewrite(ConcatOp concatOp,
792 PatternRewriter &rewriter)
const override {
793 if (concatOp.getInputs().size() != 1)
796 concatOp.getInputs()[0]);
821 using OpRewritePattern<ConcatOp>::OpRewritePattern;
823 LogicalResult matchAndRewrite(ConcatOp concatOp,
824 PatternRewriter &rewriter)
const override {
825 int64_t dim = concatOp.getDim();
826 RankedTensorType inferredResultType =
827 ConcatOp::inferResultType(dim, concatOp->getOperandTypes());
830 LogicalResult matched = failure();
833 SmallVector<int64_t> inferredOperandShape(inferredResultType.getShape());
834 for (
auto [operandIdx, operandType] :
835 llvm::enumerate(concatOp->getOperandTypes())) {
837 inferredOperandShape[dim] =
838 cast<RankedTensorType>(operandType).getDimSize(dim);
839 auto inferredOperandType = RankedTensorType::get(
840 inferredOperandShape, inferredResultType.getElementType());
848 CastOp::create(rewriter, concatOp->getLoc(), inferredOperandType,
849 concatOp.getOperand(operandIdx));
851 concatOp->setOperand(operandIdx, castOp->getResult(0));
875 using OpRewritePattern<ConcatOp>::OpRewritePattern;
877 LogicalResult matchAndRewrite(ConcatOp concatOp,
878 PatternRewriter &rewriter)
const override {
879 int64_t dim = concatOp.getDim();
880 RankedTensorType inferredResultType =
881 ConcatOp::inferResultType(dim, concatOp->getOperandTypes());
885 concatOp.getResultType())) {
890 ConcatOp::create(rewriter, concatOp->getLoc(), inferredResultType, dim,
891 concatOp->getOperands());
903 .
add<SingleInputConcatOp, InferConcatOperandTypes, InferConcatResultType>(
912 setNameFn(getResult(),
"dim");
917 auto loc =
result.location;
919 build(builder,
result, source, indexValue);
922std::optional<int64_t> DimOp::getConstantIndex() {
931 auto rankedSourceType = dyn_cast<RankedTensorType>(getSource().
getType());
932 if (!rankedSourceType)
935 if (rankedSourceType.getRank() <= constantIndex)
943 setResultRange(getResult(),
949 std::optional<int64_t>
index = getConstantIndex();
954 auto tensorType = llvm::dyn_cast<RankedTensorType>(getSource().
getType());
961 if (indexVal < 0 || indexVal >= tensorType.getRank())
965 if (!tensorType.isDynamicDim(indexVal)) {
967 return builder.
getIndexAttr(tensorType.getShape()[indexVal]);
970 Operation *definingOp = getSource().getDefiningOp();
973 if (
auto fromElements = dyn_cast_or_null<tensor::GenerateOp>(definingOp)) {
975 llvm::cast<RankedTensorType>(fromElements.getResult().getType());
978 assert(ShapedType::isDynamic(resultType.getShape()[indexVal]));
981 auto dynExtents = fromElements.getDynamicExtents().begin();
982 for (
auto dim : resultType.getShape().take_front(indexVal))
983 if (ShapedType::isDynamic(dim))
986 return Value{*dynExtents};
990 if (
auto sliceOp = dyn_cast_or_null<tensor::ExtractSliceOp>(definingOp)) {
993 if (sliceOp.getType().getRank() == sliceOp.getSourceType().getRank() &&
994 sliceOp.isDynamicSize(indexVal)) {
995 return {sliceOp.getDynamicSize(indexVal)};
1009 using OpRewritePattern<DimOp>::OpRewritePattern;
1011 LogicalResult matchAndRewrite(DimOp dimOp,
1012 PatternRewriter &rewriter)
const override {
1013 auto castOp = dimOp.getSource().getDefiningOp<CastOp>();
1016 Value newSource = castOp.getOperand();
1025 using OpRewritePattern<DimOp>::OpRewritePattern;
1027 LogicalResult matchAndRewrite(DimOp dimOp,
1028 PatternRewriter &rewriter)
const override {
1029 auto source = dimOp.getSource();
1030 auto destOp = source.getDefiningOp<DestinationStyleOpInterface>();
1034 auto resultIndex = cast<OpResult>(source).getResultNumber();
1035 auto *initOperand = destOp.getDpsInitOperand(resultIndex);
1038 dimOp, [&]() { dimOp.getSourceMutable().assign(initOperand->get()); });
1046 using OpRewritePattern<DimOp>::OpRewritePattern;
1048 LogicalResult matchAndRewrite(DimOp dim,
1049 PatternRewriter &rewriter)
const override {
1050 auto reshape = dim.getSource().getDefiningOp<ReshapeOp>();
1058 Location loc = dim.getLoc();
1060 ExtractOp::create(rewriter, loc, reshape.getShape(), dim.getIndex());
1061 if (extract.
getType() != dim.getType())
1063 arith::IndexCastOp::create(rewriter, loc, dim.getType(), extract);
1072 results.
add<DimOfCastOp, DimOfDestStyleOp, DimOfReshapeOp>(context);
1082 assert(none_of(staticShape, ShapedType::isDynamic) &&
1083 "expected only static sizes");
1087void EmptyOp::build(OpBuilder &builder, OperationState &
result,
1088 ArrayRef<int64_t> staticShape, Type elementType,
1089 ValueRange dynamicSizes, Attribute encoding) {
1090 auto tensorType = RankedTensorType::get(staticShape, elementType, encoding);
1091 build(builder,
result, tensorType, dynamicSizes);
1094void EmptyOp::build(OpBuilder &builder, OperationState &
result,
1095 ArrayRef<OpFoldResult> sizes, Type elementType,
1096 Attribute encoding) {
1097 SmallVector<int64_t> staticShape;
1098 SmallVector<Value> dynamicSizes;
1100 build(builder,
result, staticShape, elementType, dynamicSizes, encoding);
1103LogicalResult EmptyOp::verify() {
1109EmptyOp::reifyResultShapes(OpBuilder &builder,
1111 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
1113 for (int64_t i = 0; i <
getType().getRank(); ++i) {
1114 if (
getType().isDynamicDim(i)) {
1123Value EmptyOp::getDynamicSize(
unsigned idx) {
1124 assert(
getType().isDynamicDim(idx) &&
"expected dynamic dim");
1126 for (int64_t i = 0; i < static_cast<int64_t>(idx); ++i)
1127 if (
getType().isDynamicDim(i))
1132SmallVector<OpFoldResult> EmptyOp::getMixedSizes() {
1133 SmallVector<OpFoldResult>
result;
1137 if (ShapedType::isDynamic(dim)) {
1140 result.push_back(
b.getIndexAttr(dim));
1158struct ReplaceEmptyTensorStaticShapeDims : OpRewritePattern<EmptyOp> {
1159 using OpRewritePattern<EmptyOp>::OpRewritePattern;
1161 LogicalResult matchAndRewrite(EmptyOp op,
1162 PatternRewriter &rewriter)
const override {
1163 SmallVector<Value> foldedDynamicSizes;
1165 op.getType(), op.getDynamicSizes(), foldedDynamicSizes);
1168 if (foldedTensorType == op.getType())
1171 auto newOp = EmptyOp::create(rewriter, op.getLoc(), foldedTensorType,
1172 foldedDynamicSizes);
1178struct FoldEmptyTensorWithDimOp :
public OpRewritePattern<DimOp> {
1179 using OpRewritePattern<DimOp>::OpRewritePattern;
1181 LogicalResult matchAndRewrite(tensor::DimOp dimOp,
1182 PatternRewriter &rewriter)
const override {
1183 std::optional<int64_t> maybeConstantIndex = dimOp.getConstantIndex();
1184 auto emptyTensorOp = dimOp.getSource().getDefiningOp<EmptyOp>();
1185 if (!emptyTensorOp || !maybeConstantIndex)
1187 auto emptyTensorType = emptyTensorOp.getType();
1188 if (*maybeConstantIndex < 0 ||
1189 *maybeConstantIndex >= emptyTensorType.getRank() ||
1190 !emptyTensorType.isDynamicDim(*maybeConstantIndex))
1193 emptyTensorOp.getDynamicSize(*maybeConstantIndex));
1213struct FoldEmptyTensorWithCastOp :
public OpRewritePattern<CastOp> {
1214 using OpRewritePattern<CastOp>::OpRewritePattern;
1216 LogicalResult matchAndRewrite(CastOp castOp,
1217 PatternRewriter &rewriter)
const override {
1220 auto producer = castOp.getSource().getDefiningOp<EmptyOp>();
1225 llvm::cast<RankedTensorType>(castOp->getResult(0).getType());
1226 ArrayRef<int64_t> resultShape = resultType.getShape();
1227 SmallVector<OpFoldResult> currMixedSizes = producer.getMixedSizes();
1228 SmallVector<OpFoldResult> newMixedSizes;
1229 newMixedSizes.reserve(currMixedSizes.size());
1230 assert(resultShape.size() == currMixedSizes.size() &&
1231 "mismatch in result shape and sizes of empty op");
1232 for (
auto [newDim, currDim] : llvm::zip(resultShape, currMixedSizes)) {
1235 if (
auto attr = llvm::dyn_cast_if_present<Attribute>(currDim)) {
1236 if (ShapedType::isDynamic(newDim) ||
1237 newDim != llvm::cast<IntegerAttr>(attr).getInt()) {
1242 producer,
"mismatch in static value of shape of empty tensor "
1243 "result and cast result");
1245 newMixedSizes.push_back(attr);
1251 if (ShapedType::isStatic(newDim)) {
1252 newMixedSizes.push_back(rewriter.
getIndexAttr(newDim));
1258 newMixedSizes.push_back(currDim);
1262 resultType.getElementType(),
1263 resultType.getEncoding());
1270void EmptyOp::getCanonicalizationPatterns(RewritePatternSet &results,
1271 MLIRContext *context) {
1272 results.
add<FoldEmptyTensorWithCastOp, FoldEmptyTensorWithDimOp,
1273 ReplaceEmptyTensorStaticShapeDims>(context);
1290struct ExtractFromTensorCast :
public OpRewritePattern<tensor::ExtractOp> {
1291 using OpRewritePattern<tensor::ExtractOp>::OpRewritePattern;
1293 LogicalResult matchAndRewrite(tensor::ExtractOp extract,
1294 PatternRewriter &rewriter)
const final {
1295 auto tensorCast = extract.getTensor().getDefiningOp<tensor::CastOp>();
1298 if (!llvm::isa<RankedTensorType>(tensorCast.getSource().getType()))
1301 extract, tensorCast.getSource(), extract.getIndices());
1316struct ExtractFromCollapseShape :
public OpRewritePattern<tensor::ExtractOp> {
1317 using OpRewritePattern<tensor::ExtractOp>::OpRewritePattern;
1319 LogicalResult matchAndRewrite(tensor::ExtractOp extractOp,
1320 PatternRewriter &rewriter)
const final {
1322 extractOp.getTensor().getDefiningOp<tensor::CollapseShapeOp>();
1325 if (!collapseOp.getSrcType().hasStaticShape())
1328 auto sourceSizes = collapseOp.getSrcType().getShape();
1330 SmallVector<Value>
indices(extractOp.getIndices().begin(),
1331 extractOp.getIndices().end());
1332 SmallVector<Value> sourceIndices;
1333 for (
auto [index, group] :
1334 llvm::zip(
indices, collapseOp.getReassociationIndices())) {
1335 assert(!group.empty() &&
"association indices groups cannot be empty");
1336 auto groupSize = group.size();
1338 if (groupSize == 1) {
1339 sourceIndices.push_back(index);
1343 SmallVector<int64_t> basis =
1344 llvm::map_to_vector(group, [&](int64_t d) {
return sourceSizes[d]; });
1345 auto delinearize = affine::AffineDelinearizeIndexOp::create(
1346 rewriter, extractOp.getLoc(), index, basis,
true);
1347 llvm::append_range(sourceIndices,
delinearize.getResults());
1349 if (collapseOp.getReassociationIndices().empty()) {
1352 cast<RankedTensorType>(collapseOp.getSrcType()).getRank();
1354 rewriter, extractOp.getLoc(), zeroAffineMap,
1355 ArrayRef<OpFoldResult>{});
1356 for (int64_t i = 0; i < srcRank; i++) {
1357 sourceIndices.push_back(
1363 extractOp, collapseOp.getSrc(), sourceIndices);
1379struct ExtractFromTensorGenerate :
public OpRewritePattern<tensor::ExtractOp> {
1380 using OpRewritePattern<tensor::ExtractOp>::OpRewritePattern;
1382 LogicalResult matchAndRewrite(tensor::ExtractOp extract,
1383 PatternRewriter &rewriter)
const final {
1384 auto tensorFromElements = extract.getTensor().getDefiningOp<GenerateOp>();
1389 Block *body = &tensorFromElements.getBody().front();
1392 rewriter.
clone(op, mapping);
1403void ExtractOp::getAsmResultNames(
1405 setNameFn(getResult(),
"extracted");
1408LogicalResult ExtractOp::verify() {
1410 auto tensorType = llvm::cast<RankedTensorType>(getTensor().
getType());
1411 if (tensorType.getRank() !=
static_cast<int64_t
>(
getIndices().size()))
1412 return emitOpError(
"incorrect number of indices for extract_element");
1421 auto insertOp = extractOp.getTensor().
getDefiningOp<InsertOp>();
1426 if (insertOp && insertOp.getScalar().getType() == extractOp.getType() &&
1427 llvm::equal(insertOp.getIndices(), extractOp.getIndices(), isSame))
1428 return insertOp.getScalar();
1433OpFoldResult ExtractOp::fold(FoldAdaptor adaptor) {
1434 if (Attribute tensor = adaptor.getTensor()) {
1437 if (
auto splatTensor = llvm::dyn_cast<SplatElementsAttr>(tensor))
1438 return splatTensor.getSplatValue<Attribute>();
1441 if (isa<DenseResourceElementsAttr>(tensor))
1449 SmallVector<uint64_t, 8>
indices;
1450 for (Attribute indice : adaptor.getIndices()) {
1451 if (!indice || !llvm::isa<IntegerAttr>(indice))
1453 indices.push_back(llvm::cast<IntegerAttr>(indice).getInt());
1457 if (
auto fromElementsOp = getTensor().getDefiningOp<FromElementsOp>()) {
1458 auto tensorType = llvm::cast<RankedTensorType>(fromElementsOp.getType());
1459 auto rank = tensorType.getRank();
1460 assert(
static_cast<int64_t
>(
indices.size()) == tensorType.getRank() &&
1464 for (
int i = rank - 1; i >= 0; --i) {
1465 flatIndex +=
indices[i] * stride;
1466 stride *= tensorType.getDimSize(i);
1470 if (
static_cast<int>(fromElementsOp.getElements().size()) <= flatIndex ||
1473 return fromElementsOp.getElements()[flatIndex];
1477 if (Attribute tensor = adaptor.getTensor()) {
1478 auto elementsAttr = llvm::dyn_cast<ElementsAttr>(tensor);
1479 if (elementsAttr && elementsAttr.isValidIndex(
indices))
1480 return elementsAttr.getValues<Attribute>()[
indices];
1486void ExtractOp::getCanonicalizationPatterns(RewritePatternSet &results,
1487 MLIRContext *context) {
1488 results.
add<ExtractFromTensorCast, ExtractFromTensorGenerate>(context);
1493 patterns.
add<ExtractFromCollapseShape>(patterns.
getContext());
1500void FromElementsOp::getAsmResultNames(
1502 setNameFn(getResult(),
"from_elements");
1507 assert(!elements.empty() &&
"expected at least one element");
1508 Type resultType = RankedTensorType::get(
1509 {
static_cast<int64_t>(elements.size())}, elements.front().
getType());
1510 build(builder,
result, resultType, elements);
1513OpFoldResult FromElementsOp::fold(FoldAdaptor adaptor) {
1518 Type eltType =
getType().getElementType();
1521 if (!llvm::is_contained(adaptor.getElements(),
nullptr))
1544struct ExtractElementFromIndexCast
1545 :
public OpRewritePattern<tensor::ExtractOp> {
1546 using OpRewritePattern<tensor::ExtractOp>::OpRewritePattern;
1548 LogicalResult matchAndRewrite(tensor::ExtractOp extract,
1549 PatternRewriter &rewriter)
const final {
1550 Location loc = extract.getLoc();
1551 auto indexCast = extract.getTensor().getDefiningOp<arith::IndexCastOp>();
1557 auto newExtract = tensor::ExtractOp::create(
1558 rewriter, loc, elementTy, indexCast.getIn(), extract.getIndices());
1569void FromElementsOp::getCanonicalizationPatterns(RewritePatternSet &results,
1570 MLIRContext *context) {
1571 results.
add<ExtractElementFromIndexCast>(context);
1578void GatherOp::getAsmResultNames(
1580 setNameFn(getResult(),
"gather");
1595RankedTensorType GatherOp::inferResultType(RankedTensorType sourceType,
1596 RankedTensorType indicesType,
1597 ArrayRef<int64_t> gatherDims,
1599 SmallVector<int64_t> resultShape(indicesType.getShape().drop_back());
1600 resultShape.reserve(resultShape.size() + sourceType.getRank());
1601 for (int64_t idx : llvm::seq<int64_t>(0, sourceType.getRank())) {
1602 if (llvm::binary_search(gatherDims, idx)) {
1604 resultShape.push_back(1);
1607 resultShape.push_back(sourceType.getDimSize(idx));
1609 return RankedTensorType::Builder(sourceType).setShape(resultShape);
1615 StringRef gatherOrScatter, StringRef sourceOrDest) {
1617 return op->
emitOpError(gatherOrScatter) <<
"_dims must be non-empty";
1619 int64_t numGatherDims = dims.size();
1620 if (numGatherDims > rank)
1622 <<
"_dims overflow " << sourceOrDest <<
" rank";
1625 <<
"_dims length must match the size of last dimension of indices";
1629 <<
"_dims value must be non-negative";
1632 <<
"_dims value must be smaller than " << sourceOrDest <<
" rank";
1634 for (
int64_t i = 1; i < numGatherDims; ++i) {
1635 if (dims[i - 1] >= dims[i])
1637 <<
"_dims values must be strictly increasing";
1642LogicalResult GatherOp::verify() {
1643 int64_t sourceRank = getSourceType().getRank();
1644 ArrayRef<int64_t> gatherDims = getGatherDims();
1646 getIndicesType().
getShape(), sourceRank,
1647 "gather",
"source")))
1650 RankedTensorType expectedResultType = GatherOp::inferResultType(
1651 getSourceType(), getIndicesType(), gatherDims,
false);
1652 RankedTensorType expectedRankReducedResultType = GatherOp::inferResultType(
1653 getSourceType(), getIndicesType(), gatherDims,
true);
1654 if (getResultType() != expectedResultType &&
1655 getResultType() != expectedRankReducedResultType) {
1656 return emitOpError(
"result type "
1659 << expectedResultType <<
" or its rank-reduced variant "
1660 << expectedRankReducedResultType <<
" (got: " << getResultType()
1667OpFoldResult GatherOp::fold(FoldAdaptor adaptor) {
1668 if (OpFoldResult reshapedSource = reshapeConstantSource(
1669 llvm::dyn_cast_if_present<DenseElementsAttr>(adaptor.getSource()),
1671 return reshapedSource;
1679void InsertOp::getAsmResultNames(
1681 setNameFn(getResult(),
"inserted");
1684LogicalResult InsertOp::verify() {
1686 auto destType = llvm::cast<RankedTensorType>(getDest().
getType());
1687 if (destType.getRank() !=
static_cast<int64_t
>(
getIndices().size()))
1688 return emitOpError(
"incorrect number of indices");
1692OpFoldResult InsertOp::fold(FoldAdaptor adaptor) {
1693 Attribute scalar = adaptor.getScalar();
1694 Attribute dest = adaptor.getDest();
1696 if (
auto splatDest = llvm::dyn_cast<SplatElementsAttr>(dest))
1697 if (scalar == splatDest.getSplatValue<Attribute>())
1706void GenerateOp::getAsmResultNames(
1708 setNameFn(getResult(),
"generated");
1711LogicalResult GenerateOp::reifyResultShapes(
1713 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
1715 for (
auto dim : llvm::seq<int64_t>(0,
getType().getRank())) {
1716 if (
getType().isDynamicDim(dim)) {
1717 reifiedReturnShapes[0][dim] = getOperand(idx++);
1719 reifiedReturnShapes[0][dim] =
1726LogicalResult GenerateOp::verify() {
1729 RankedTensorType resultType = llvm::cast<RankedTensorType>(
getType());
1736LogicalResult GenerateOp::verifyRegions() {
1737 RankedTensorType resultTy = llvm::cast<RankedTensorType>(
getType());
1739 if (!llvm::all_of(getBody().getArgumentTypes(),
1740 [](Type ty) {
return ty.
isIndex(); }))
1741 return emitError(
"all body arguments must be index");
1742 if (getBody().getNumArguments() != resultTy.getRank())
1743 return emitError(
"must have one body argument per input dimension");
1746 auto yieldOp = cast<YieldOp>(getBody().getBlocks().front().getTerminator());
1748 if (yieldOp.getValue().getType() != resultTy.getElementType())
1750 "body must be terminated with a `yield` operation of the tensor "
1756void GenerateOp::build(
1757 OpBuilder &
b, OperationState &
result, Type resultTy,
1760 build(
b,
result, resultTy, dynamicExtents);
1763 OpBuilder::InsertionGuard guard(
b);
1764 Region *bodyRegion =
result.regions.front().get();
1765 auto rank = llvm::cast<RankedTensorType>(resultTy).getRank();
1766 SmallVector<Type, 2> argumentTypes(rank,
b.getIndexType());
1767 SmallVector<Location, 2> argumentLocs(rank,
result.location);
1769 b.createBlock(bodyRegion, bodyRegion->
end(), argumentTypes, argumentLocs);
1779struct StaticTensorGenerate :
public OpRewritePattern<GenerateOp> {
1780 using OpRewritePattern<GenerateOp>::OpRewritePattern;
1782 LogicalResult matchAndRewrite(GenerateOp generateOp,
1783 PatternRewriter &rewriter)
const final {
1784 SmallVector<Value> foldedDynamicSizes;
1786 generateOp.getType(), generateOp.getDynamicExtents(),
1787 foldedDynamicSizes);
1790 if (foldedTensorType == generateOp.getType())
1793 auto loc = generateOp.getLoc();
1795 GenerateOp::create(rewriter, loc, foldedTensorType, foldedDynamicSizes);
1797 newOp.getBody().begin());
1799 generateOp.getType(), newOp);
1805void GenerateOp::getCanonicalizationPatterns(RewritePatternSet &results,
1806 MLIRContext *context) {
1807 results.
add<StaticTensorGenerate>(context);
1814void RankOp::getAsmResultNames(
function_ref<
void(Value, StringRef)> setNameFn) {
1815 setNameFn(getResult(),
"rank");
1818OpFoldResult RankOp::fold(FoldAdaptor adaptor) {
1820 auto type = getOperand().getType();
1821 auto shapedType = llvm::dyn_cast<ShapedType>(type);
1822 if (shapedType && shapedType.hasRank())
1823 return IntegerAttr::get(IndexType::get(
getContext()), shapedType.getRank());
1824 return IntegerAttr();
1831void ReshapeOp::getAsmResultNames(
1833 setNameFn(getResult(),
"reshape");
1838 for (
auto dim : type.getShape())
1843LogicalResult ReshapeOp::verify() {
1844 TensorType operandType = llvm::cast<TensorType>(getSource().
getType());
1845 TensorType resultType = llvm::cast<TensorType>(getResult().
getType());
1848 return emitOpError(
"element types of source and destination tensor "
1849 "types should be the same");
1853 auto resultRankedType = llvm::dyn_cast<RankedTensorType>(resultType);
1854 auto operandRankedType = llvm::dyn_cast<RankedTensorType>(operandType);
1856 if (resultRankedType) {
1857 if (operandRankedType && resultRankedType.hasStaticShape() &&
1858 operandRankedType.hasStaticShape()) {
1860 return emitOpError(
"source and destination tensor should have the "
1861 "same number of elements");
1863 if (ShapedType::isDynamic(shapeSize))
1864 return emitOpError(
"cannot use shape operand with dynamic length to "
1865 "reshape to statically-ranked tensor type");
1866 if (shapeSize != resultRankedType.getRank())
1868 "length of shape operand differs from the result's tensor rank");
1873OpFoldResult ReshapeOp::fold(FoldAdaptor adaptor) {
1874 if (OpFoldResult reshapedSource = reshapeConstantSource(
1875 llvm::dyn_cast_if_present<DenseElementsAttr>(adaptor.getSource()),
1877 return reshapedSource;
1882 if (
auto reshapeOpProducer = getSource().getDefiningOp<ReshapeOp>()) {
1883 getSourceMutable().assign(reshapeOpProducer.getSource());
1887 auto source = getSource();
1888 auto sourceTy = dyn_cast<RankedTensorType>(source.getType());
1889 auto resultTy = dyn_cast<RankedTensorType>(
getType());
1890 if (!sourceTy || !resultTy || sourceTy != resultTy)
1895 if (sourceTy.getRank() <= 1)
1898 if (
auto fromElements =
getShape().getDefiningOp<tensor::FromElementsOp>()) {
1899 auto elements = fromElements.getElements();
1901 sourceTy.getRank() ==
static_cast<int64_t
>(elements.size());
1902 for (
int id = 0, s = elements.size();
id < s && dynamicNoop; ++
id) {
1903 auto element = elements[id];
1906 dynamicNoop &= cst.value() == sourceTy.getDimSize(
id);
1910 if (
auto dimOp = element.getDefiningOp<tensor::DimOp>()) {
1911 dynamicNoop &= dimOp.getSource() == source;
1915 cst.has_value() && cst.value() ==
static_cast<int64_t
>(id);
1919 dynamicNoop =
false;
1934void CollapseShapeOp::getAsmResultNames(
1936 setNameFn(getResult(),
"collapsed");
1939void ExpandShapeOp::getAsmResultNames(
1941 setNameFn(getResult(),
"expanded");
1944int64_t ExpandShapeOp::getCorrespondingSourceDim(int64_t resultDim) {
1945 assert(resultDim >= 0 && resultDim < getResultType().getRank() &&
1946 "invalid resultDim");
1947 for (
const auto &it : llvm::enumerate(getReassociationIndices()))
1948 if (llvm::is_contained(it.value(), resultDim))
1950 llvm_unreachable(
"could not find reassociation group");
1953FailureOr<SmallVector<OpFoldResult>>
1954ExpandShapeOp::inferOutputShape(OpBuilder &
b, Location loc,
1955 RankedTensorType expandedType,
1956 ArrayRef<ReassociationIndices> reassociation,
1957 ArrayRef<OpFoldResult> inputShape) {
1958 std::optional<SmallVector<OpFoldResult>> outputShape =
1963 return *outputShape;
1966SmallVector<OpFoldResult> ExpandShapeOp::getMixedOutputShape() {
1970void ExpandShapeOp::build(OpBuilder &builder, OperationState &
result,
1971 Type resultType, Value src,
1972 ArrayRef<ReassociationIndices> reassociation,
1973 ArrayRef<OpFoldResult> outputShape) {
1974 auto [staticOutputShape, dynamicOutputShape] =
1976 build(builder,
result, cast<RankedTensorType>(resultType), src,
1978 dynamicOutputShape, staticOutputShape);
1981void ExpandShapeOp::build(OpBuilder &builder, OperationState &
result,
1982 Type resultType, Value src,
1983 ArrayRef<ReassociationIndices> reassociation) {
1984 SmallVector<OpFoldResult> inputShape =
1986 auto tensorResultTy = cast<RankedTensorType>(resultType);
1987 FailureOr<SmallVector<OpFoldResult>> outputShape = inferOutputShape(
1988 builder,
result.location, tensorResultTy, reassociation, inputShape);
1989 SmallVector<OpFoldResult> outputShapeOrEmpty;
1990 if (succeeded(outputShape)) {
1991 outputShapeOrEmpty = *outputShape;
1993 build(builder,
result, tensorResultTy, src, reassociation,
1994 outputShapeOrEmpty);
1997SmallVector<AffineMap, 4> CollapseShapeOp::getReassociationMaps() {
2000SmallVector<ReassociationExprs, 4> CollapseShapeOp::getReassociationExprs() {
2002 getReassociationIndices());
2005SmallVector<AffineMap, 4> ExpandShapeOp::getReassociationMaps() {
2008SmallVector<ReassociationExprs, 4> ExpandShapeOp::getReassociationExprs() {
2010 getReassociationIndices());
2013RankedTensorType CollapseShapeOp::inferCollapsedType(
2014 RankedTensorType type, ArrayRef<ReassociationIndices> reassociation) {
2015 return inferCollapsedType(
2017 type.getContext(), reassociation)));
2023CollapseShapeOp::inferCollapsedType(RankedTensorType type,
2024 ArrayRef<AffineMap> reassociation) {
2025 auto shape = type.getShape();
2026 SmallVector<int64_t, 4> newShape;
2027 newShape.reserve(reassociation.size());
2032 unsigned currentDim = 0;
2033 for (AffineMap m : reassociation) {
2034 unsigned dim = m.getNumResults();
2035 auto band = shape.slice(currentDim, dim);
2037 if (llvm::is_contained(band, ShapedType::kDynamic))
2038 size = ShapedType::kDynamic;
2040 for (
unsigned d = 0; d < dim; ++d)
2041 size *= shape[currentDim + d];
2042 newShape.push_back(size);
2046 return RankedTensorType::get(newShape, type.getElementType());
2049void CollapseShapeOp::build(OpBuilder &
b, OperationState &
result, Value src,
2050 ArrayRef<ReassociationIndices> reassociation,
2051 ArrayRef<NamedAttribute> attrs) {
2052 auto srcType = llvm::cast<RankedTensorType>(src.
getType());
2053 RankedTensorType collapsedType = inferCollapsedType(srcType, reassociation);
2055 RankedTensorType::get(collapsedType.getShape(), srcType.getElementType(),
2056 srcType.getEncoding());
2057 buildPropertiesAndDiscardableAttributes(
result, attrs);
2058 result.getOrAddProperties<Properties>().reassociation =
2061 result.addTypes(resultType);
2064template <
typename TensorReshapeOp,
bool isExpansion = std::is_same<
2065 TensorReshapeOp, ExpandShapeOp>::value>
2067 RankedTensorType expandedType,
2068 RankedTensorType collapsedType) {
2070 verifyReshapeLikeTypes(op, expandedType, collapsedType, isExpansion)))
2074 if (expandedType.hasStaticShape() && collapsedType.hasStaticShape()) {
2075 std::optional<int64_t> expandedNumElements =
2076 ShapedType::tryGetNumElements(expandedType.getShape());
2077 std::optional<int64_t> collapsedNumElements =
2078 ShapedType::tryGetNumElements(collapsedType.getShape());
2079 if (!expandedNumElements || !collapsedNumElements)
2080 return op.emitOpError(
"number of elements exceeds the int64 range");
2081 if (*expandedNumElements != *collapsedNumElements)
2082 return op.emitOpError(
"number of elements must be preserved: ")
2083 << *expandedNumElements <<
" != " << *collapsedNumElements;
2086 auto maps = op.getReassociationMaps();
2087 RankedTensorType expectedType =
2088 CollapseShapeOp::inferCollapsedType(expandedType, maps);
2090 return op.emitOpError(
"expected collapsed type to be ")
2091 << expectedType <<
", but got " << collapsedType;
2095LogicalResult ExpandShapeOp::verify() {
2099 RankedTensorType srcType = getSrc().getType();
2100 RankedTensorType resultType = getResult().getType();
2102 if ((int64_t)getStaticOutputShape().size() != resultType.getRank())
2103 return emitOpError(
"expected number of static shape dims to be equal to "
2104 "the output rank (")
2105 << resultType.getRank() <<
") but found "
2106 << getStaticOutputShape().size() <<
" inputs instead";
2108 if ((int64_t)getOutputShape().size() !=
2109 llvm::count(getStaticOutputShape(), ShapedType::kDynamic))
2110 return emitOpError(
"mismatch in dynamic dims in output_shape and "
2111 "static_output_shape: static_output_shape has ")
2112 << llvm::count(getStaticOutputShape(), ShapedType::kDynamic)
2113 <<
" dynamic dims while output_shape has " << getOutputShape().size()
2124 ArrayRef<int64_t> resShape = getResult().getType().getShape();
2125 for (
auto [pos, shape] : llvm::enumerate(resShape))
2126 if (ShapedType::isStatic(shape) && shape != staticOutputShapes[pos])
2127 return emitOpError(
"invalid output shape provided at pos ") << pos;
2132LogicalResult CollapseShapeOp::verify() {
2133 CollapseShapeOp op = *
this;
2137 RankedTensorType srcType = op.getSrc().getType();
2138 RankedTensorType resultType = op.getResult().getType();
2146template <
typename TensorReshapeOp>
2147struct FoldReshapeWithConstant : OpRewritePattern<TensorReshapeOp> {
2148 using OpRewritePattern<TensorReshapeOp>::OpRewritePattern;
2149 LogicalResult matchAndRewrite(TensorReshapeOp reshapeOp,
2150 PatternRewriter &rewriter)
const override {
2151 DenseElementsAttr attr;
2158 if (!reshapeOp.getResultType().hasStaticShape())
2161 reshapeOp.getResultType(), attr.
getRawData());
2168template <
typename TensorReshapeOp>
2169class FoldReshapeWithSplat :
public OpRewritePattern<TensorReshapeOp> {
2171 using OpRewritePattern<TensorReshapeOp>::OpRewritePattern;
2173 LogicalResult matchAndRewrite(TensorReshapeOp reshapeOp,
2174 PatternRewriter &rewriter)
const override {
2175 auto splatOp = reshapeOp.getSrc().template getDefiningOp<tensor::SplatOp>();
2176 if (!splatOp || !splatOp.getAggregate().getType().hasStaticShape())
2180 reshapeOp, reshapeOp.getResultType(), splatOp.getInput());
2187template <
typename TensorReshapeOp>
2188struct FoldReshapeWithFromElements : OpRewritePattern<TensorReshapeOp> {
2189 using OpRewritePattern<TensorReshapeOp>::OpRewritePattern;
2190 LogicalResult matchAndRewrite(TensorReshapeOp reshapeOp,
2191 PatternRewriter &rewriter)
const override {
2193 reshapeOp.getSrc().template getDefiningOp<FromElementsOp>();
2197 auto shapedTy = llvm::cast<ShapedType>(reshapeOp.getType());
2199 if (!shapedTy.hasStaticShape())
2203 fromElements.getElements());
2209struct FoldCollapseOfCastOp :
public OpRewritePattern<CollapseShapeOp> {
2210 using OpRewritePattern<CollapseShapeOp>::OpRewritePattern;
2212 LogicalResult matchAndRewrite(CollapseShapeOp collapseShapeOp,
2213 PatternRewriter &rewriter)
const override {
2214 auto castOp = collapseShapeOp.getSrc().getDefiningOp<tensor::CastOp>();
2218 RankedTensorType srcType =
2219 llvm::cast<RankedTensorType>(castOp.getSource().getType());
2220 RankedTensorType newResultType = CollapseShapeOp::inferCollapsedType(
2221 srcType, collapseShapeOp.getReassociationMaps());
2223 if (newResultType == collapseShapeOp.getResultType()) {
2225 collapseShapeOp.getSrcMutable().assign(castOp.getSource());
2228 auto newOp = CollapseShapeOp::create(rewriter, collapseShapeOp.getLoc(),
2229 newResultType, castOp.getSource(),
2230 collapseShapeOp.getReassociation());
2232 collapseShapeOp, collapseShapeOp.getResultType(), newOp);
2242struct ConvertToStaticExpandShape :
public OpRewritePattern<ExpandShapeOp> {
2243 using OpRewritePattern<ExpandShapeOp>::OpRewritePattern;
2245 LogicalResult matchAndRewrite(ExpandShapeOp expandOp,
2246 PatternRewriter &rewriter)
const override {
2247 auto castOp = expandOp.getSrc().getDefiningOp<CastOp>();
2251 ArrayRef<int64_t> castSrcShape = castOp.getSource().getType().getShape();
2252 SmallVector<ReassociationIndices, 4> reassoc =
2253 expandOp.getReassociationIndices();
2255 SmallVector<int64_t> newOutputShape(expandOp.getResultType().getShape());
2256 SmallVector<Value> dynamicOutputShape;
2257 auto outputIt = expandOp.getOutputShape().begin();
2259 for (
const auto &[inputDim, innerReassoc] : llvm::enumerate(reassoc)) {
2260 for (uint64_t outDim : innerReassoc) {
2261 if (ShapedType::isStatic(newOutputShape[outDim]))
2268 Value val = *outputIt;
2270 if (ShapedType::isDynamic(castSrcShape[inputDim])) {
2271 dynamicOutputShape.push_back(val);
2277 int64_t dim = cst.getSExtValue();
2280 newOutputShape[outDim] = dim;
2282 dynamicOutputShape.push_back(val);
2288 if (expandOp.getOutputShape().size() == dynamicOutputShape.size())
2292 SmallVector<int64_t> newInputShape(expandOp.getSrcType().getRank(), 1l);
2293 for (
auto inDim : llvm::seq<int>(0, newInputShape.size())) {
2294 for (
auto outDim : reassoc[inDim]) {
2295 auto ofr = newOutputShape[outDim];
2296 if (ShapedType::isDynamic(ofr)) {
2297 newInputShape[inDim] = ShapedType::kDynamic;
2300 newInputShape[inDim] *= ofr;
2304 SmallVector<OpFoldResult> outputOfr =
2309 Type elementType = expandOp.getSrcType().getElementType();
2310 auto inputType = RankedTensorType::get(
2311 newInputShape, elementType,
2314 auto outputType = RankedTensorType::get(
2315 newOutputShape, elementType,
2317 newOutputShape, elementType));
2318 auto inputCast = CastOp::create(rewriter, expandOp.getLoc(), inputType,
2320 auto newExpand = ExpandShapeOp::create(
2321 rewriter, expandOp.getLoc(), outputType, inputCast.getResult(),
2322 expandOp.getReassociationIndices(), outputOfr);
2324 newExpand.getResult());
2330void ExpandShapeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2331 MLIRContext *context) {
2333 ComposeReassociativeReshapeOps<ExpandShapeOp, ReshapeOpKind::kExpand>,
2334 ComposeExpandOfCollapseOp<ExpandShapeOp, CollapseShapeOp, CastOp>,
2335 ConvertToStaticExpandShape, FoldReshapeWithConstant<ExpandShapeOp>,
2336 FoldReshapeWithSplat<ExpandShapeOp>,
2337 FoldReshapeWithFromElements<ExpandShapeOp>>(context);
2340void CollapseShapeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2341 MLIRContext *context) {
2343 ComposeReassociativeReshapeOps<CollapseShapeOp, ReshapeOpKind::kCollapse>,
2344 ComposeCollapseOfExpandOp<CollapseShapeOp, ExpandShapeOp, CastOp,
2345 tensor::DimOp, RankedTensorType>,
2346 FoldReshapeWithConstant<CollapseShapeOp>,
2347 FoldReshapeWithSplat<CollapseShapeOp>,
2348 FoldReshapeWithFromElements<CollapseShapeOp>, FoldCollapseOfCastOp>(
2352OpFoldResult ExpandShapeOp::fold(FoldAdaptor adaptor) {
2354 adaptor.getOperands());
2357OpFoldResult CollapseShapeOp::fold(FoldAdaptor adaptor) {
2359 adaptor.getOperands());
2366void ExtractSliceOp::getAsmResultNames(
2368 setNameFn(getResult(),
"extracted_slice");
2375ExtractSliceOp::inferResultType(RankedTensorType sourceTensorType,
2376 ArrayRef<int64_t> staticSizes) {
2380 assert(
static_cast<int64_t
>(staticSizes.size()) ==
2381 sourceTensorType.getRank() &&
2382 "unexpected staticSizes not equal to rank of source");
2383 return RankedTensorType::get(staticSizes, sourceTensorType.getElementType(),
2384 sourceTensorType.getEncoding());
2388ExtractSliceOp::inferResultType(RankedTensorType sourceTensorType,
2389 ArrayRef<OpFoldResult> sizes) {
2390 SmallVector<int64_t> staticSizes;
2393 assert(
static_cast<int64_t
>(staticSizes.size()) ==
2394 sourceTensorType.getRank() &&
2395 "unexpected staticSizes not equal to rank of source");
2396 return RankedTensorType::get(staticSizes, sourceTensorType.getElementType(),
2397 sourceTensorType.getEncoding());
2403 const llvm::SmallBitVector &droppedDims) {
2404 assert(staticSizes.size() == droppedDims.size() &&
2405 "expected one dropped-dimension bit per size");
2408 resultShape.reserve(staticSizes.size() - droppedDims.count());
2409 for (
auto [idx, size] : llvm::enumerate(staticSizes))
2410 if (!droppedDims.test(idx))
2411 resultShape.push_back(size);
2413 Type elementType = sourceTensorType.getElementType();
2414 return RankedTensorType::get(resultShape, elementType,
2416 resultShape, elementType));
2422 const llvm::SmallBitVector &droppedDims) {
2425 return inferSliceType(sourceTensorType, staticSizes, droppedDims);
2431 RankedTensorType resultType,
Value source,
2441 auto sourceRankedTensorType = llvm::cast<RankedTensorType>(source.
getType());
2444 resultType = llvm::cast<RankedTensorType>(
2445 ExtractSliceOp::inferResultType(sourceRankedTensorType, staticSizes));
2447 result.addAttributes(attrs);
2448 build(
b,
result, resultType, source, dynamicOffsets, dynamicSizes,
2449 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
2450 b.getDenseI64ArrayAttr(staticSizes),
2451 b.getDenseI64ArrayAttr(staticStrides));
2456void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2457 ArrayRef<OpFoldResult> offsets,
2458 ArrayRef<OpFoldResult> sizes,
2459 ArrayRef<OpFoldResult> strides,
2460 ArrayRef<NamedAttribute> attrs) {
2461 build(
b,
result, RankedTensorType(), source, offsets, sizes, strides, attrs);
2466void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2467 ArrayRef<Range> ranges,
2468 ArrayRef<NamedAttribute> attrs) {
2470 build(
b,
result, RankedTensorType(), source, offsets, sizes, strides, attrs);
2475void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result,
2476 RankedTensorType resultType, Value source,
2478 ValueRange strides, ArrayRef<NamedAttribute> attrs) {
2479 SmallVector<OpFoldResult> offsetValues = llvm::map_to_vector<4>(
2480 offsets, [](Value v) -> OpFoldResult {
return v; });
2481 SmallVector<OpFoldResult> sizeValues =
2482 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
2483 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
2484 strides, [](Value v) -> OpFoldResult {
return v; });
2485 build(
b,
result, resultType, source, offsetValues, sizeValues, strideValues);
2489void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2491 ValueRange strides, ArrayRef<NamedAttribute> attrs) {
2492 build(
b,
result, RankedTensorType(), source, offsets, sizes, strides, attrs);
2497 RankedTensorType expectedType) {
2502 return op->
emitError(
"expected rank to be smaller or equal to ")
2503 <<
"the other rank. ";
2505 return op->
emitError(
"expected type to be ")
2506 << expectedType <<
" or a rank-reduced version. (size mismatch) ";
2508 return op->
emitError(
"expected element type to be ")
2509 << expectedType.getElementType();
2511 llvm_unreachable(
"unexpected extract_slice op verification result");
2517void ExtractSliceOp::build(OpBuilder &
b, OperationState &
result,
2518 RankedTensorType resultType, Value source,
2519 ArrayRef<OpFoldResult> sizes,
2520 ArrayRef<NamedAttribute> attrs) {
2521 Attribute zeroIdxAttr =
b.getIndexAttr(0);
2522 Attribute oneIdxAttr =
b.getIndexAttr(1);
2523 SmallVector<OpFoldResult> readStrides(sizes.size(), oneIdxAttr);
2524 SmallVector<OpFoldResult> readOffsets(sizes.size(), zeroIdxAttr);
2525 build(
b,
result, resultType, source, readOffsets, sizes, readStrides, attrs);
2529LogicalResult ExtractSliceOp::verify() {
2530 RankedTensorType sourceType = getSourceType();
2533 RankedTensorType expectedType =
2534 ExtractSliceOp::inferResultType(sourceType,
getMixedSizes());
2542 sourceType.getShape(), getStaticOffsets(), getStaticSizes(),
2543 getStaticStrides(),
true);
2545 return getOperation()->emitError(boundsResult.
errorMessage);
2550llvm::SmallBitVector ExtractSliceOp::getDroppedDims() {
2555ExtractSliceOp::rankReduceIfNeeded(OpBuilder &
b, Location loc, Value value,
2556 ArrayRef<int64_t> desiredShape) {
2557 auto sourceTensorType = llvm::dyn_cast<RankedTensorType>(value.
getType());
2558 assert(sourceTensorType &&
"not a ranked tensor type");
2559 auto sourceShape = sourceTensorType.getShape();
2560 if (sourceShape.equals(desiredShape))
2562 auto maybeRankReductionMask =
2564 if (!maybeRankReductionMask)
2568 RankedTensorType::Builder(sourceTensorType).setShape(desiredShape));
2571LogicalResult ExtractSliceOp::reifyResultShapes(
2573 reifiedReturnShapes.resize(1);
2574 reifiedReturnShapes[0].reserve(
getType().getRank());
2577 for (
const auto &size :
enumerate(mixedSizes)) {
2578 if (droppedDims.test(size.index()))
2580 reifiedReturnShapes[0].push_back(size.value());
2601class ExtractSliceOpCastFolder final :
public OpRewritePattern<ExtractSliceOp> {
2603 using OpRewritePattern<ExtractSliceOp>::OpRewritePattern;
2605 LogicalResult matchAndRewrite(ExtractSliceOp sliceOp,
2606 PatternRewriter &rewriter)
const override {
2608 if (llvm::any_of(sliceOp.getOperands(), [](Value operand) {
2609 return matchPattern(operand, matchConstantIndex());
2613 auto castOp = sliceOp.getSource().getDefiningOp<CastOp>();
2622 cast<RankedTensorType>(castOp.getSource().getType()).getShape(),
2623 sliceOp.getStaticOffsets(), sliceOp.getStaticSizes(),
2624 sliceOp.getStaticStrides());
2629 Location loc = sliceOp.getLoc();
2630 Value newResult = ExtractSliceOp::create(
2631 rewriter, loc, sliceOp.getType(), castOp.getSource(),
2632 sliceOp.getOffsets(), sliceOp.getSizes(), sliceOp.getStrides(),
2633 sliceOp.getStaticOffsets(), sliceOp.getStaticSizes(),
2634 sliceOp.getStaticStrides());
2643template <
typename IterTy,
typename ElemTy>
2644static void sliceElements(IterTy values, ArrayRef<int64_t> counts,
2645 ArrayRef<int64_t> offsets, ArrayRef<int64_t> sizes,
2646 ArrayRef<int64_t> strides,
2647 llvm::SmallVectorImpl<ElemTy> *outValues) {
2648 assert(offsets.size() == sizes.size());
2649 assert(offsets.size() == strides.size());
2650 if (offsets.empty())
2653 int64_t offset = offsets.front();
2654 int64_t size = sizes.front();
2655 int64_t stride = strides.front();
2656 if (offsets.size() == 1) {
2657 for (int64_t i = 0; i < size; ++i, offset += stride)
2658 outValues->push_back(*(values + offset));
2663 for (int64_t i = 0; i < size; ++i, offset += stride) {
2664 auto begin = values + offset * counts.front();
2665 sliceElements<IterTy, ElemTy>(begin, counts.drop_front(),
2666 offsets.drop_front(), sizes.drop_front(),
2667 strides.drop_front(), outValues);
2674class ConstantOpExtractSliceFolder final
2675 :
public OpRewritePattern<ExtractSliceOp> {
2677 using OpRewritePattern<ExtractSliceOp>::OpRewritePattern;
2679 ConstantOpExtractSliceFolder(MLIRContext *context,
2681 : OpRewritePattern<ExtractSliceOp>(context),
2682 controlFn(std::move(controlFn)) {}
2684 LogicalResult matchAndRewrite(ExtractSliceOp op,
2685 PatternRewriter &rewriter)
const override {
2686 DenseElementsAttr attr;
2695 auto sourceType = llvm::cast<ShapedType>(op.getSource().getType());
2696 auto resultType = llvm::cast<ShapedType>(op.getResult().getType());
2697 if (!sourceType.hasStaticShape() || !resultType.hasStaticShape())
2704 int64_t count = sourceType.getNumElements();
2709 auto offsets = op.getStaticOffsets();
2710 if (llvm::is_contained(offsets, ShapedType::kDynamic))
2712 auto sizes = op.getStaticSizes();
2713 if (llvm::is_contained(sizes, ShapedType::kDynamic))
2715 auto strides = op.getStaticStrides();
2716 if (llvm::is_contained(strides, ShapedType::kDynamic))
2720 SmallVector<int64_t> counts;
2721 ArrayRef<int64_t> shape = sourceType.getShape();
2722 counts.reserve(shape.size());
2723 for (int64_t v : shape) {
2725 counts.push_back(count);
2729 SmallVector<Attribute> outValues;
2730 outValues.reserve(resultType.getNumElements());
2731 sliceElements(attr.
value_begin<Attribute>(), counts, offsets, sizes,
2732 strides, &outValues);
2749 patterns.
add<ConstantOpExtractSliceFolder>(patterns.
getContext(), controlFn);
2761 return inferSliceType(op.getSourceType(), mixedSizes, op.getDroppedDims());
2768 ExtractSliceOp newOp) {
2771 replacement = tensor::CastOp::create(rewriter, op.getLoc(), op.getType(),
2777void ExtractSliceOp::getCanonicalizationPatterns(RewritePatternSet &results,
2778 MLIRContext *context) {
2780 OpWithOffsetSizesAndStridesConstantArgumentFolder<
2781 ExtractSliceOp, SliceReturnTypeCanonicalizer, SliceCanonicalizer>,
2782 ExtractSliceOpCastFolder>(context);
2788 ShapedType shapedType) {
2795 auto shape = shapedType.getShape();
2796 for (
auto it : llvm::zip(op.getMixedSizes(),
shape))
2810 auto insertOp = extractOp.getSource().getDefiningOp<InsertSliceOp>();
2813 if (insertOp && insertOp.getSource().getType() == extractOp.getType() &&
2814 insertOp.isSameAs(extractOp, isSame))
2815 return insertOp.getSource();
2820OpFoldResult ExtractSliceOp::fold(FoldAdaptor adaptor) {
2821 if (OpFoldResult reshapedSource = reshapeConstantSource(
2822 llvm::dyn_cast_if_present<SplatElementsAttr>(adaptor.getSource()),
2824 return reshapedSource;
2825 if (getSourceType() ==
getType() &&
2827 return this->getSource();
2831 return OpFoldResult();
2836 auto rankedTensorType = llvm::cast<RankedTensorType>(
tensor.getType());
2837 unsigned rank = rankedTensorType.getRank();
2841 return b.createOrFold<tensor::ExtractSliceOp>(loc, targetType,
tensor,
2842 offsets, sizes, strides);
2849void InsertSliceOp::getAsmResultNames(
2851 setNameFn(getResult(),
"inserted_slice");
2865 result.addAttributes(attrs);
2866 build(
b,
result, dest.
getType(), source, dest, dynamicOffsets, dynamicSizes,
2867 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
2868 b.getDenseI64ArrayAttr(staticSizes),
2869 b.getDenseI64ArrayAttr(staticStrides));
2874void InsertSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2875 Value dest, ArrayRef<Range> ranges,
2876 ArrayRef<NamedAttribute> attrs) {
2878 build(
b,
result, source, dest, offsets, sizes, strides, attrs);
2882void InsertSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
2884 ValueRange strides, ArrayRef<NamedAttribute> attrs) {
2885 SmallVector<OpFoldResult> offsetValues = llvm::map_to_vector<4>(
2886 offsets, [](Value v) -> OpFoldResult {
return v; });
2887 SmallVector<OpFoldResult> sizeValues =
2888 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
2889 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
2890 strides, [](Value v) -> OpFoldResult {
return v; });
2891 build(
b,
result, source, dest, offsetValues, sizeValues, strideValues);
2897 RankedTensorType srcType, RankedTensorType dstType,
2902 RankedTensorType expected =
2903 ExtractSliceOp::inferResultType(dstType, staticSizes);
2905 *expectedType = expected;
2910LogicalResult InsertSliceOp::verify() {
2912 RankedTensorType expectedType;
2915 getStaticSizes(), getStaticStrides(), &expectedType);
2922 getDestType().
getShape(), getStaticOffsets(), getStaticSizes(),
2923 getStaticStrides(),
true);
2925 return getOperation()->emitError(boundsResult.
errorMessage);
2948 auto prevInsertOp = insertOp.getDest().getDefiningOp<InsertSliceOp>();
2951 if (!prevInsertOp ||
2952 prevInsertOp.getSource().getType() != insertOp.getSource().getType() ||
2953 !prevInsertOp.isSameAs(insertOp, isSame))
2956 insertOp.getDestMutable().assign(prevInsertOp.getDest());
2968 auto extractOp = insertOp.getSource().
getDefiningOp<ExtractSliceOp>();
2971 if (!extractOp || extractOp.getSource() != insertOp.getDest() ||
2972 !extractOp.isSameAs(insertOp, isSame))
2975 return extractOp.getSource();
2978OpFoldResult InsertSliceOp::fold(FoldAdaptor) {
2979 if (getSourceType().hasStaticShape() &&
getType().hasStaticShape() &&
2980 getSourceType() ==
getType() &&
2982 return this->getSource();
2989 return OpFoldResult();
2992LogicalResult InsertSliceOp::reifyResultShapes(
2994 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
3003template <
typename InsertOpTy>
3004class InsertSliceOpConstantArgumentFolder final
3005 :
public OpRewritePattern<InsertOpTy> {
3007 using OpRewritePattern<InsertOpTy>::OpRewritePattern;
3009 LogicalResult matchAndRewrite(InsertOpTy insertSliceOp,
3010 PatternRewriter &rewriter)
const override {
3011 SmallVector<OpFoldResult> mixedOffsets(insertSliceOp.getMixedOffsets());
3012 SmallVector<OpFoldResult> mixedSizes(insertSliceOp.getMixedSizes());
3013 SmallVector<OpFoldResult> mixedStrides(insertSliceOp.getMixedStrides());
3022 SliceBoundsVerificationResult sliceResult =
3024 mixedOffsets, mixedSizes, mixedStrides);
3028 auto sourceType =
inferSliceType(insertSliceOp.getSourceType(), mixedSizes,
3029 insertSliceOp.getDroppedDims());
3030 Value toInsert = insertSliceOp.getSource();
3031 if (sourceType != insertSliceOp.getSourceType()) {
3032 OpBuilder::InsertionGuard g(rewriter);
3036 if (isa<InParallelOpInterface>(insertSliceOp->getParentOp()))
3038 toInsert = tensor::CastOp::create(rewriter, insertSliceOp.getLoc(),
3039 sourceType, toInsert);
3042 insertSliceOp, toInsert, insertSliceOp.getDest(), mixedOffsets,
3043 mixedSizes, mixedStrides);
3068template <
typename InsertOpTy>
3069struct InsertSliceOpCastFolder final :
public OpRewritePattern<InsertOpTy> {
3070 using OpRewritePattern<InsertOpTy>::OpRewritePattern;
3072 LogicalResult matchAndRewrite(InsertOpTy insertSliceOp,
3073 PatternRewriter &rewriter)
const override {
3074 if (llvm::any_of(insertSliceOp.getOperands(), [](Value operand) {
3075 return matchPattern(operand, matchConstantIndex());
3079 auto getSourceOfCastOp = [](Value v) -> std::optional<Value> {
3082 return std::nullopt;
3083 return castOp.getSource();
3085 std::optional<Value> sourceCastSource =
3086 getSourceOfCastOp(insertSliceOp.getSource());
3087 std::optional<Value> destCastSource =
3088 getSourceOfCastOp(insertSliceOp.getDest());
3089 if (!sourceCastSource && !destCastSource)
3093 (sourceCastSource ? *sourceCastSource : insertSliceOp.getSource());
3094 auto dst = (destCastSource ? *destCastSource : insertSliceOp.getDest());
3095 auto srcType = llvm::dyn_cast<RankedTensorType>(src.
getType());
3096 auto dstType = llvm::dyn_cast<RankedTensorType>(dst.getType());
3097 if (!srcType || !dstType)
3103 SmallVector<int64_t> staticSizes(insertSliceOp.getStaticSizes());
3105 staticSizes, srcType.getShape(),
true);
3106 if (!rankReductionMask.has_value())
3113 SmallVector<OpFoldResult> mixedSizes(insertSliceOp.getMixedSizes());
3114 int64_t rankReducedIdx = 0;
3115 for (
auto [idx, size] :
enumerate(staticSizes)) {
3116 if (!rankReductionMask.value().contains(idx) &&
3117 !srcType.isDynamicDim(rankReducedIdx)) {
3119 rewriter.
getContext(), srcType.getDimSize(rankReducedIdx));
3120 size = srcType.getDimSize(rankReducedIdx++);
3126 staticSizes, insertSliceOp.getStaticStrides()) !=
3127 SliceVerificationResult::Success)
3129 SliceBoundsVerificationResult sliceResult =
3131 mixedSizes, insertSliceOp.getMixedStrides());
3136 InsertOpTy::create(rewriter, insertSliceOp.getLoc(), src, dst,
3137 insertSliceOp.getMixedOffsets(), mixedSizes,
3138 insertSliceOp.getMixedStrides());
3141 bool isParallelInsert =
3142 std::is_same<InsertOpTy, ParallelInsertSliceOp>::value;
3143 if (!isParallelInsert && dst.getType() != insertSliceOp.getDestType()) {
3144 replacement = tensor::CastOp::create(rewriter, insertSliceOp.getLoc(),
3145 insertSliceOp.getDestType(),
3174template <
typename InsertOpTy>
3175struct InsertSliceOpSourceCastInserter final
3176 :
public OpRewritePattern<InsertOpTy> {
3177 using OpRewritePattern<InsertOpTy>::OpRewritePattern;
3179 LogicalResult matchAndRewrite(InsertOpTy insertSliceOp,
3180 PatternRewriter &rewriter)
const override {
3181 RankedTensorType srcType = insertSliceOp.getSourceType();
3182 if (srcType.getRank() != insertSliceOp.getDestType().getRank())
3184 SmallVector<int64_t> newSrcShape(srcType.getShape());
3185 for (int64_t i = 0; i < srcType.getRank(); ++i) {
3186 if (std::optional<int64_t> constInt =
3191 newSrcShape[i] = *constInt;
3197 RankedTensorType newSrcType = RankedTensorType::get(
3198 newSrcShape, srcType.getElementType(), srcType.getEncoding());
3199 if (srcType == newSrcType ||
3201 !tensor::CastOp::areCastCompatible(srcType, newSrcType))
3209 OpBuilder::InsertionGuard g(rewriter);
3213 if (isa<ParallelCombiningOpInterface>(insertSliceOp->getParentOp()))
3215 Value cast = tensor::CastOp::create(rewriter, insertSliceOp.getLoc(),
3216 newSrcType, insertSliceOp.getSource());
3218 insertSliceOp, cast, insertSliceOp.getDest(),
3219 insertSliceOp.getMixedOffsets(), insertSliceOp.getMixedSizes(),
3220 insertSliceOp.getMixedStrides());
3226llvm::SmallBitVector InsertSliceOp::getDroppedDims() {
3230void InsertSliceOp::getCanonicalizationPatterns(RewritePatternSet &results,
3231 MLIRContext *context) {
3232 results.
add<InsertSliceOpConstantArgumentFolder<InsertSliceOp>,
3233 InsertSliceOpCastFolder<InsertSliceOp>,
3234 InsertSliceOpSourceCastInserter<InsertSliceOp>>(context);
3241 auto rankedTensorType = llvm::cast<RankedTensorType>(dest.
getType());
3242 unsigned rank = rankedTensorType.getRank();
3246 return b.createOrFold<tensor::InsertSliceOp>(loc,
tensor, dest, offsets,
3255 setNameFn(getResult(),
"padded");
3258LogicalResult PadOp::verify() {
3260 for (int64_t size : padding)
3261 if (!ShapedType::isDynamic(size) && size < 0)
3262 return emitOpError(
"padding must be non-negative, got ") << size;
3264 auto sourceType = llvm::cast<RankedTensorType>(getSource().
getType());
3265 auto resultType = llvm::cast<RankedTensorType>(getResult().
getType());
3267 PadOp::inferResultType(sourceType, getStaticLow(), getStaticHigh());
3268 if (!expectedType) {
3269 return emitError(
"failed to infer expectedType from sourceType ")
3270 << sourceType <<
", specified resultType is " << resultType;
3272 if (resultType.getRank() != expectedType.getRank()) {
3274 << resultType <<
" does not match the inferred type "
3277 for (
int i = 0, e = sourceType.getRank(); i < e; ++i) {
3278 if (resultType.getDimSize(i) == expectedType.getDimSize(i))
3280 if (expectedType.isDynamicDim(i))
3283 << resultType <<
" does not match the inferred type "
3290LogicalResult PadOp::verifyRegions() {
3291 auto ®ion = getRegion();
3292 unsigned rank = llvm::cast<RankedTensorType>(getResult().
getType()).getRank();
3293 Block &block = region.front();
3295 return emitError(
"expected the block to have ") << rank <<
" arguments";
3299 if (!en.value().isIndex())
3300 return emitOpError(
"expected block argument ")
3301 << (en.index() + 1) <<
" to be an index";
3306 if (yieldOp.getValue().getType() !=
3308 return emitOpError(
"expected yield type to match shape element type");
3313RankedTensorType PadOp::inferResultType(RankedTensorType sourceType,
3314 ArrayRef<int64_t> staticLow,
3315 ArrayRef<int64_t> staticHigh,
3316 ArrayRef<int64_t> resultShape) {
3317 unsigned rank = sourceType.getRank();
3318 if (staticLow.size() != rank)
3319 return RankedTensorType();
3320 if (staticHigh.size() != rank)
3321 return RankedTensorType();
3322 if (!resultShape.empty() && resultShape.size() != rank)
3323 return RankedTensorType();
3325 SmallVector<int64_t, 4> inferredShape;
3326 for (
auto i : llvm::seq<unsigned>(0, rank)) {
3327 if (sourceType.isDynamicDim(i) || staticLow[i] == ShapedType::kDynamic ||
3328 staticHigh[i] == ShapedType::kDynamic) {
3329 inferredShape.push_back(resultShape.empty() ? ShapedType::kDynamic
3332 int64_t size = sourceType.getDimSize(i) + staticLow[i] + staticHigh[i];
3333 assert((resultShape.empty() || size == resultShape[i] ||
3334 resultShape[i] == ShapedType::kDynamic) &&
3335 "mismatch between inferred shape and result shape");
3336 inferredShape.push_back(size);
3340 Type elementType = sourceType.getElementType();
3341 return RankedTensorType::get(
3342 inferredShape, elementType,
3346void PadOp::build(OpBuilder &
b, OperationState &
result, Type resultType,
3347 Value source, ArrayRef<int64_t> staticLow,
3349 bool nofold, ArrayRef<NamedAttribute> attrs) {
3350 auto sourceType = llvm::cast<RankedTensorType>(source.
getType());
3352 resultType = inferResultType(sourceType, staticLow, staticHigh);
3353 result.addAttributes(attrs);
3354 build(
b,
result, resultType, source, low, high,
3355 b.getDenseI64ArrayAttr(staticLow),
b.getDenseI64ArrayAttr(staticHigh),
3356 nofold ?
b.getUnitAttr() : UnitAttr());
3359void PadOp::build(OpBuilder &
b, OperationState &
result, Type resultType,
3361 ArrayRef<NamedAttribute> attrs) {
3362 auto sourceType = llvm::cast<RankedTensorType>(source.
getType());
3363 unsigned rank = sourceType.getRank();
3364 SmallVector<int64_t, 4> staticVector(rank, ShapedType::kDynamic);
3365 build(
b,
result, resultType, source, staticVector, staticVector, low, high,
3369void PadOp::build(OpBuilder &
b, OperationState &
result, Type resultType,
3370 Value source, ArrayRef<OpFoldResult> low,
3371 ArrayRef<OpFoldResult> high,
bool nofold,
3372 ArrayRef<NamedAttribute> attrs) {
3373 auto sourceType = llvm::cast<RankedTensorType>(source.
getType());
3374 SmallVector<Value, 4> dynamicLow, dynamicHigh;
3375 SmallVector<int64_t, 4> staticLow, staticHigh;
3383 resultType = PadOp::inferResultType(sourceType, staticLow, staticHigh);
3385 assert(llvm::isa<RankedTensorType>(resultType));
3386 result.addAttributes(attrs);
3387 build(
b,
result, resultType, source, dynamicLow, dynamicHigh,
3388 b.getDenseI64ArrayAttr(staticLow),
b.getDenseI64ArrayAttr(staticHigh),
3389 nofold ?
b.getUnitAttr() : UnitAttr());
3392void PadOp::build(OpBuilder &
b, OperationState &
result, Type resultType,
3393 Value source, ArrayRef<OpFoldResult> low,
3394 ArrayRef<OpFoldResult> high, Value constantPadValue,
3395 bool nofold, ArrayRef<NamedAttribute> attrs) {
3396 build(
b,
result, resultType, source, low, high, nofold, attrs);
3399 Region *region =
result.regions[0].get();
3400 int sourceRank = llvm::cast<RankedTensorType>(source.
getType()).getRank();
3401 Repeated<Type> blockArgTypes(sourceRank,
b.getIndexType());
3402 SmallVector<Location> blockArgLocs(sourceRank,
result.location);
3406 OpBuilder::InsertionGuard guard(
b);
3407 b.createBlock(region, region->
end(), blockArgTypes, blockArgLocs);
3408 tensor::YieldOp::create(
b,
result.location, constantPadValue);
3411llvm::SmallBitVector PadOp::getPaddedDims() {
3412 llvm::SmallBitVector paddedDims(getSourceType().getRank());
3413 auto extractPaddedDims = [&](ArrayRef<OpFoldResult> paddingWidths) {
3414 for (
const auto &en :
enumerate(paddingWidths))
3416 paddedDims.set(en.index());
3418 extractPaddedDims(getMixedLowPad());
3419 extractPaddedDims(getMixedHighPad());
3426struct FoldStaticZeroPadding :
public OpRewritePattern<PadOp> {
3427 using OpRewritePattern<PadOp>::OpRewritePattern;
3429 LogicalResult matchAndRewrite(PadOp padTensorOp,
3430 PatternRewriter &rewriter)
const override {
3431 if (!padTensorOp.hasZeroLowPad() || !padTensorOp.hasZeroHighPad())
3433 if (padTensorOp.getNofold())
3436 padTensorOp, padTensorOp.getResult().
getType(),
3437 padTensorOp.getSource());
3443struct FoldSourceTensorCast :
public OpRewritePattern<PadOp> {
3444 using OpRewritePattern<PadOp>::OpRewritePattern;
3446 LogicalResult matchAndRewrite(PadOp padTensorOp,
3447 PatternRewriter &rewriter)
const override {
3448 auto castOp = padTensorOp.getSource().getDefiningOp<tensor::CastOp>();
3452 auto newResultType = PadOp::inferResultType(
3453 llvm::cast<RankedTensorType>(castOp.getSource().getType()),
3454 padTensorOp.getStaticLow(), padTensorOp.getStaticHigh(),
3455 padTensorOp.getResultType().getShape());
3457 if (newResultType == padTensorOp.getResultType()) {
3459 padTensorOp.getSourceMutable().assign(castOp.getSource());
3462 auto newOp = PadOp::create(
3463 rewriter, padTensorOp->getLoc(), newResultType,
3464 padTensorOp.getSource(), padTensorOp.getStaticLow(),
3465 padTensorOp.getStaticHigh(), padTensorOp.getLow(),
3466 padTensorOp.getHigh(), padTensorOp.getNofold(),
3469 padTensorOp.getRegion().cloneInto(&newOp.getRegion(), mapper);
3472 padTensorOp, padTensorOp.getResultType(), newOp);
3480struct FoldTargetTensorCast :
public OpRewritePattern<PadOp> {
3481 using OpRewritePattern<PadOp>::OpRewritePattern;
3483 LogicalResult matchAndRewrite(PadOp padTensorOp,
3484 PatternRewriter &rewriter)
const override {
3485 if (!padTensorOp.getResult().hasOneUse())
3488 dyn_cast<tensor::CastOp>(*padTensorOp->getUsers().begin());
3492 tensorCastOp.getDest().getType()))
3495 auto replacementOp = PadOp::create(
3496 rewriter, padTensorOp.getLoc(), tensorCastOp.getDest().getType(),
3497 padTensorOp.getSource(), padTensorOp.getStaticLow(),
3498 padTensorOp.getStaticHigh(), padTensorOp.getLow(),
3499 padTensorOp.getHigh(), padTensorOp.getNofold(),
3501 replacementOp.getRegion().takeBody(padTensorOp.getRegion());
3503 rewriter.
replaceOp(padTensorOp, replacementOp.getResult());
3504 rewriter.
replaceOp(tensorCastOp, replacementOp.getResult());
3544struct FoldOrthogonalPaddings :
public OpRewritePattern<PadOp> {
3545 using OpRewritePattern<PadOp>::OpRewritePattern;
3547 LogicalResult matchAndRewrite(PadOp padOp,
3548 PatternRewriter &rewriter)
const override {
3549 auto innerSliceOp = padOp.getSource().getDefiningOp<ExtractSliceOp>();
3552 auto outerPadOp = innerSliceOp.getSource().getDefiningOp<PadOp>();
3553 if (!outerPadOp || outerPadOp.getNofold())
3555 auto outerSliceOp = outerPadOp.getSource().getDefiningOp<ExtractSliceOp>();
3560 int64_t rank = padOp.getSourceType().getRank();
3561 if (outerSliceOp.getSourceType().getRank() != rank) {
3563 "cannot fold rank-reducing chain");
3567 if (!innerSliceOp.hasUnitStride() || !outerSliceOp.hasUnitStride()) {
3569 padOp,
"cannot fold non-unit stride ExtractSliceOps");
3573 if (!padOp.hasZeroLowPad() || !outerPadOp.hasZeroLowPad()) {
3575 "cannot fold PadOps with low padding");
3579 Attribute innerAttr, outerAttr;
3580 Value innerValue = padOp.getConstantPaddingValue();
3581 Value outerValue = outerPadOp.getConstantPaddingValue();
3582 if (!innerValue || !outerValue ||
3585 innerAttr != outerAttr) {
3587 padOp,
"cannot fold PadOps with different padding values");
3591 llvm::SmallBitVector innerDims = padOp.getPaddedDims();
3592 llvm::SmallBitVector outerDims = outerPadOp.getPaddedDims();
3593 if (innerDims.anyCommon(outerDims)) {
3595 padOp,
"cannot fold PadOps with common padding dimensions");
3603 SmallVector<OpFoldResult> newOffsets(rank, rewriter.
getIndexAttr(0));
3605 OpFoldResult innerOffset = innerSliceOp.getMixedOffsets()[en.index()];
3606 OpFoldResult outerOffset = outerSliceOp.getMixedOffsets()[en.index()];
3607 if (!innerDims.test(en.index()) &&
3609 en.value() = outerOffset;
3612 if (!outerDims.test(en.index()) &&
3614 en.value() = innerOffset;
3618 padOp,
"cannot find zero-offset and zero-padding pair");
3626 SmallVector<OpFoldResult> newSizes = innerSliceOp.getMixedSizes();
3628 if (!outerDims.test(en.index()))
3630 OpFoldResult sliceSize = innerSliceOp.getMixedSizes()[en.index()];
3631 int64_t sourceSize = innerSliceOp.getSourceType().getShape()[en.index()];
3632 assert(ShapedType::isStatic(sourceSize) &&
3633 "expected padded dimension to have a static size");
3636 padOp,
"cannot fold since the inner ExtractSliceOp size does not "
3637 "match the size of the outer padding");
3639 en.value() = outerSliceOp.getMixedSizes()[en.index()];
3643 SmallVector<OpFoldResult> newHighPad(rank, rewriter.
getIndexAttr(0));
3645 if (innerDims.test(en.index()))
3646 newHighPad[en.index()] = padOp.getMixedHighPad()[en.index()];
3647 if (outerDims.test(en.index()))
3648 newHighPad[en.index()] = outerPadOp.getMixedHighPad()[en.index()];
3653 auto newSliceOp = ExtractSliceOp::create(
3654 rewriter, padOp.getLoc(), outerSliceOp.getSource(), newOffsets,
3655 newSizes, innerSliceOp.getMixedStrides());
3656 auto newPadOp = PadOp::create(
3657 rewriter, padOp.getLoc(), padOp.getResultType(), newSliceOp.getResult(),
3658 padOp.getMixedLowPad(), newHighPad, padOp.getNofold(),
3661 newPadOp.getRegion().begin());
3662 rewriter.
replaceOp(padOp, newPadOp.getResult());
3667struct FoldStaticPadding :
public OpRewritePattern<PadOp> {
3668 using OpRewritePattern<PadOp>::OpRewritePattern;
3670 LogicalResult matchAndRewrite(PadOp padTensorOp,
3671 PatternRewriter &rewriter)
const override {
3672 Value input = padTensorOp.getSource();
3673 if (!llvm::isa<RankedTensorType>(input.
getType()))
3675 auto inputDims = llvm::cast<RankedTensorType>(input.
getType()).getShape();
3676 auto inputRank = inputDims.size();
3678 auto oldResultType =
3679 dyn_cast<RankedTensorType>(padTensorOp.getResult().getType());
3683 auto outputDims = oldResultType.getShape();
3688 SmallVector<int64_t> constOperandsLow;
3689 SmallVector<Value> newLows;
3690 for (
auto operand : padTensorOp.getLow()) {
3693 intOp.getExtValue() < 0) {
3694 constOperandsLow.push_back(ShapedType::kDynamic);
3695 newLows.push_back(operand);
3698 constOperandsLow.push_back(intOp.getExtValue());
3700 SmallVector<int64_t> constOperandsHigh;
3701 SmallVector<Value> newHighs;
3702 for (
auto operand : padTensorOp.getHigh()) {
3705 intOp.getExtValue() < 0) {
3706 constOperandsHigh.push_back(ShapedType::kDynamic);
3707 newHighs.push_back(operand);
3710 constOperandsHigh.push_back(intOp.getExtValue());
3713 SmallVector<int64_t> constLow(padTensorOp.getStaticLow());
3714 SmallVector<int64_t> constHigh(padTensorOp.getStaticHigh());
3717 if (inputDims.size() != outputDims.size() ||
3718 inputDims.size() != constLow.size() ||
3719 inputDims.size() != constHigh.size())
3724 for (
size_t i = 0; i < inputRank; i++) {
3725 if (constLow[i] == ShapedType::kDynamic)
3726 constLow[i] = constOperandsLow[lowCount++];
3727 if (constHigh[i] == ShapedType::kDynamic)
3728 constHigh[i] = constOperandsHigh[highCount++];
3731 auto staticLow = ArrayRef<int64_t>(constLow);
3732 auto staticHigh = ArrayRef<int64_t>(constHigh);
3735 SmallVector<int64_t> newOutDims;
3736 for (
size_t i = 0; i < inputRank; i++) {
3737 if (outputDims[i] == ShapedType::kDynamic) {
3738 newOutDims.push_back(
3739 (staticLow[i] == ShapedType::kDynamic ||
3740 staticHigh[i] == ShapedType::kDynamic ||
3741 inputDims[i] == ShapedType::kDynamic
3742 ? ShapedType::kDynamic
3743 : inputDims[i] + staticLow[i] + staticHigh[i]));
3745 newOutDims.push_back(outputDims[i]);
3749 if (SmallVector<int64_t>(outputDims) == newOutDims ||
3750 llvm::all_of(newOutDims,
3751 [&](int64_t x) {
return x == ShapedType::kDynamic; }))
3754 Type elementType = padTensorOp.getType().getElementType();
3755 auto newResultType = RankedTensorType::get(
3756 newOutDims, elementType,
3759 auto newOp = PadOp::create(
3760 rewriter, padTensorOp->getLoc(), newResultType, input, staticLow,
3761 staticHigh, newLows, newHighs, padTensorOp.getNofold(),
3765 padTensorOp.getRegion().cloneInto(&newOp.getRegion(), mapper);
3793struct FoldConsecutiveConstantPadding :
public OpRewritePattern<tensor::PadOp> {
3794 using OpRewritePattern<tensor::PadOp>::OpRewritePattern;
3796 LogicalResult matchAndRewrite(tensor::PadOp padOp,
3797 PatternRewriter &rewriter)
const override {
3798 if (padOp.getNofold()) {
3802 auto producerPad = padOp.getSource().getDefiningOp<tensor::PadOp>();
3803 if (!producerPad || producerPad.getNofold()) {
3805 padOp,
"producer is not a foldable tensor.pad op");
3809 Value consumerPadValue = padOp.getConstantPaddingValue();
3810 Value producerPadValue = producerPad.getConstantPaddingValue();
3811 if (!consumerPadValue || !producerPadValue ||
3812 consumerPadValue != producerPadValue) {
3815 "cannot fold PadOps with different or non-constant padding values");
3818 Location loc = padOp.getLoc();
3823 auto addPaddings = [&](ArrayRef<OpFoldResult> consumerPaddings,
3824 ArrayRef<OpFoldResult> producerPaddings) {
3825 SmallVector<OpFoldResult> sumPaddings;
3826 for (
auto [consumerIndex, producerIndex] :
3827 llvm::zip_equal(consumerPaddings, producerPaddings)) {
3829 rewriter, loc, d0 + d1, {consumerIndex, producerIndex}));
3834 SmallVector<OpFoldResult> newHighPad =
3835 addPaddings(padOp.getMixedHighPad(), producerPad.getMixedHighPad());
3836 SmallVector<OpFoldResult> newLowPad =
3837 addPaddings(padOp.getMixedLowPad(), producerPad.getMixedLowPad());
3839 auto newPadOp = tensor::PadOp::create(
3840 rewriter, padOp.getLoc(), padOp.getResultType(),
3841 producerPad.getSource(), newLowPad, newHighPad, padOp.getNofold(),
3844 newPadOp.getRegion().begin());
3845 rewriter.
replaceOp(padOp, newPadOp.getResult());
3853PadOp::reifyResultShapes(OpBuilder &
b,
3855 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
3856 SmallVector<OpFoldResult> lp = getMixedLowPad();
3857 SmallVector<OpFoldResult> hp = getMixedHighPad();
3858 for (int64_t i = 0; i < getResultType().getRank(); ++i) {
3859 if (!
getType().isDynamicDim(i)) {
3860 reifiedReturnShapes[0][i] =
b.getIndexAttr(
getType().getDimSize(i));
3863 Location loc = getLoc();
3864 Value dim =
b.createOrFold<tensor::DimOp>(
3867 AffineExpr d0, d1, d2;
3870 b, loc, {d0 + d1 + d2}, {dim, lp[i], hp[i]});
3875void PadOp::getCanonicalizationPatterns(RewritePatternSet &results,
3876 MLIRContext *context) {
3877 results.
add<FoldStaticZeroPadding, FoldSourceTensorCast, FoldTargetTensorCast,
3878 FoldOrthogonalPaddings, FoldStaticPadding,
3879 FoldConsecutiveConstantPadding>(context);
3891Value PadOp::getConstantPaddingValue() {
3892 auto yieldOp = dyn_cast<YieldOp>(getRegion().front().getTerminator());
3895 Value padValue = yieldOp.getValue();
3906OpFoldResult PadOp::fold(FoldAdaptor) {
3907 if (getResultType().hasStaticShape() && getResultType() == getSourceType() &&
3917OpResult ParallelInsertSliceOp::getTiedOpResult() {
3918 InParallelOpInterface parallelCombiningParent = getParallelCombiningParent();
3919 for (
const auto &it :
3920 llvm::enumerate(parallelCombiningParent.getYieldingOps())) {
3921 Operation &nextOp = it.value();
3922 if (&nextOp == getOperation())
3923 return parallelCombiningParent.getParentResult(it.index());
3925 llvm_unreachable(
"ParallelInsertSliceOp no tied OpResult found");
3929void ParallelInsertSliceOp::build(OpBuilder &
b, OperationState &
result,
3930 Value source, Value dest,
3931 ArrayRef<OpFoldResult> offsets,
3932 ArrayRef<OpFoldResult> sizes,
3933 ArrayRef<OpFoldResult> strides,
3934 ArrayRef<NamedAttribute> attrs) {
3935 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
3936 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
3940 result.addAttributes(attrs);
3941 build(
b,
result, {}, source, dest, dynamicOffsets, dynamicSizes,
3942 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
3943 b.getDenseI64ArrayAttr(staticSizes),
3944 b.getDenseI64ArrayAttr(staticStrides));
3949void ParallelInsertSliceOp::build(OpBuilder &
b, OperationState &
result,
3950 Value source, Value dest,
3951 ArrayRef<Range> ranges,
3952 ArrayRef<NamedAttribute> attrs) {
3954 build(
b,
result, source, dest, offsets, sizes, strides, attrs);
3958void ParallelInsertSliceOp::build(OpBuilder &
b, OperationState &
result,
3959 Value source, Value dest,
ValueRange offsets,
3961 ArrayRef<NamedAttribute> attrs) {
3962 SmallVector<OpFoldResult> offsetValues = llvm::map_to_vector<4>(
3963 offsets, [](Value v) -> OpFoldResult {
return v; });
3964 SmallVector<OpFoldResult> sizeValues =
3965 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
3966 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
3967 strides, [](Value v) -> OpFoldResult {
return v; });
3968 build(
b,
result, source, dest, offsetValues, sizeValues, strideValues);
3973void InsertSliceOp::build(OpBuilder &
b, OperationState &
result, Value source,
3974 Value dest, ArrayRef<OpFoldResult> sizes,
3975 ArrayRef<NamedAttribute> attrs) {
3976 Attribute zeroIdxAttr =
b.getIndexAttr(0);
3977 Attribute oneIdxAttr =
b.getIndexAttr(1);
3978 SmallVector<OpFoldResult> writeStrides(sizes.size(), oneIdxAttr);
3979 SmallVector<OpFoldResult> writeOffsets(sizes.size(), zeroIdxAttr);
3980 build(
b,
result, source, dest, writeOffsets, sizes, writeStrides, attrs);
3983LogicalResult ParallelInsertSliceOp::verify() {
3984 if (!isa<InParallelOpInterface>(getOperation()->getParentOp()))
3985 return this->
emitError(
"expected InParallelOpInterface parent, got:")
3986 << *(getOperation()->getParentOp());
3989 RankedTensorType expectedType;
3992 getStaticSizes(), getStaticStrides(), &expectedType);
3999 getDestType().
getShape(), getStaticOffsets(), getStaticSizes(),
4000 getStaticStrides(),
true);
4002 return getOperation()->emitError(boundsResult.
errorMessage);
4007void ParallelInsertSliceOp::getCanonicalizationPatterns(
4008 RewritePatternSet &results, MLIRContext *context) {
4009 results.
add<InsertSliceOpConstantArgumentFolder<ParallelInsertSliceOp>,
4010 InsertSliceOpCastFolder<ParallelInsertSliceOp>,
4011 InsertSliceOpSourceCastInserter<ParallelInsertSliceOp>>(context);
4014llvm::SmallBitVector ParallelInsertSliceOp::getDroppedDims() {
4019MutableOperandRange ParallelInsertSliceOp::getUpdatedDestinations() {
4020 return getDestMutable();
4023Operation *ParallelInsertSliceOp::getIteratingParent() {
4025 if (
auto combiningOp =
4026 dyn_cast<InParallelOpInterface>(getOperation()->getParentOp()))
4027 return combiningOp->getParentOp();
4035void ScatterOp::getAsmResultNames(
4037 setNameFn(getResult(),
"scatter");
4040LogicalResult ScatterOp::verify() {
4041 int64_t destRank = getDestType().getRank();
4042 ArrayRef<int64_t> scatterDims = getScatterDims();
4044 getIndicesType().
getShape(), destRank,
4045 "scatter",
"dest")))
4049 return emitOpError(
"requires 'unique' attribute to be set");
4056 RankedTensorType expectedSourceType = GatherOp::inferResultType(
4057 getDestType(), getIndicesType(), scatterDims,
false);
4058 RankedTensorType expectedRankReducedSourceType = GatherOp::inferResultType(
4059 getDestType(), getIndicesType(), scatterDims,
true);
4060 if (getSourceType() != expectedSourceType &&
4061 getSourceType() != expectedRankReducedSourceType) {
4062 return emitOpError(
"source type "
4065 << expectedSourceType <<
" or its rank-reduced variant "
4066 << expectedRankReducedSourceType <<
" (got: " << getSourceType()
4077void SplatOp::build(OpBuilder &builder, OperationState &
result, Value element,
4078 Type aggregateType,
ValueRange dynamicSizes) {
4079 build(builder,
result, aggregateType, element, dynamicSizes);
4082void SplatOp::build(OpBuilder &builder, OperationState &
result, Value element,
4083 ArrayRef<int64_t> staticShape,
ValueRange dynamicSizes) {
4084 auto aggregateType = RankedTensorType::get(staticShape, element.
getType());
4085 build(builder,
result, aggregateType, element, dynamicSizes);
4088void SplatOp::build(OpBuilder &builder, OperationState &
result, Value element,
4089 ArrayRef<OpFoldResult> sizes) {
4090 SmallVector<int64_t> staticShape;
4091 SmallVector<Value> dynamicSizes;
4093 build(builder,
result, element, staticShape, dynamicSizes);
4096void SplatOp::getAsmResultNames(
4098 setNameFn(getResult(),
"splat");
4101LogicalResult SplatOp::verify() {
4107SplatOp::reifyResultShapes(OpBuilder &builder,
4109 reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(
getType().getRank()));
4111 for (int64_t i = 0; i <
getType().getRank(); ++i) {
4112 if (
getType().isDynamicDim(i)) {
4121OpFoldResult SplatOp::fold(FoldAdaptor adaptor) {
4122 auto constOperand = adaptor.getInput();
4123 if (!isa_and_nonnull<IntegerAttr, FloatAttr>(constOperand))
4127 if (!
getType().hasStaticShape())
4147struct ReplaceSplatStaticShapeDims : OpRewritePattern<SplatOp> {
4148 using OpRewritePattern<SplatOp>::OpRewritePattern;
4150 LogicalResult matchAndRewrite(SplatOp op,
4151 PatternRewriter &rewriter)
const override {
4152 SmallVector<Value> foldedDynamicSizes;
4154 op.getType(), op.getDynamicSizes(), foldedDynamicSizes);
4157 if (foldedTensorType == op.getType())
4160 auto newOp = SplatOp::create(rewriter, op.getLoc(), op.getInput(),
4161 foldedTensorType, foldedDynamicSizes);
4168void SplatOp::getCanonicalizationPatterns(RewritePatternSet &results,
4169 MLIRContext *context) {
4170 results.
add<ReplaceSplatStaticShapeDims>(context);
4180 if (isa<InsertSliceOp>(op.getOperation()) ||
4181 isa<LoopLikeOpInterface>(op.getOperation()))
4214 isa<linalg::RelayoutOpInterface>(*op))
4222 auto newOp =
clone(rewriter, op, newResultTypes, newOperands);
4225 replacements.reserve(newOp->getNumResults());
4226 for (
auto [oldResult, newResult] :
4227 llvm::zip(op->getResults(), newOp->getResults())) {
4228 if (newResult.getType() != oldResult.getType()) {
4229 replacements.push_back(tensor::CastOp::create(
4230 rewriter, op->getLoc(), oldResult.
getType(), newResult));
4232 replacements.push_back(newResult);
4243struct SelectSplatCondition : OpRewritePattern<arith::SelectOp> {
4246 LogicalResult matchAndRewrite(arith::SelectOp select,
4247 PatternRewriter &rewriter)
const override {
4248 auto splat = select.getCondition().getDefiningOp<SplatOp>();
4252 select, [&] { select.getConditionMutable().assign(splat.getInput()); });
4262void TensorDialect::getCanonicalizationPatterns(
4263 RewritePatternSet &results)
const {
4264 results.
add<FoldTensorCastProducerOp, SelectSplatCondition>(
getContext());
4271#define GET_OP_CLASSES
4272#include "mlir/Dialect/Tensor/IR/TensorOps.cpp.inc"
std::string join(const Ts &...args)
Helper function to concatenate arguments into a std::string.
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 Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
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.
static SmallVector< Value > slice(OpBuilder &b, Location loc, Value value, VectorType nativeType)
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.
RankedTensorType inferSliceType(RankedTensorType sourceTensorType, ArrayRef< int64_t > staticSizes, const llvm::SmallBitVector &droppedDims)
Infer a slice type for the given sizes and exact dropped-dimension mask.
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.
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.
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.
LogicalResult verifyReassociationIndicesNotEmpty(ReshapeOpTy op)
Verify that none of the reassociation groups is empty.
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.