#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Arith/Utils/Utils.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/MemRef/Transforms/Passes.h"
#include "mlir/Dialect/MemRef/Transforms/Transforms.h"
#include "mlir/Dialect/Utils/IndexingUtils.h"
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
#include <optional>
namespace mlir {
namespace memref {
#define GEN_PASS_DEF_EXPANDSTRIDEDMETADATA
#include "mlir/Dialect/MemRef/Transforms/Passes.h.inc"
}
}
using namespace mlir;
using namespace mlir::affine;
namespace {
struct StridedMetadata {
Value basePtr;
OpFoldResult offset;
SmallVector<OpFoldResult> sizes;
SmallVector<OpFoldResult> strides;
};
static FailureOr<StridedMetadata>
resolveSubviewStridedMetadata(RewriterBase &rewriter,
memref::SubViewOp subview) {
Location origLoc = subview.getLoc();
Value source = subview.getSource();
auto sourceType = cast<MemRefType>(source.getType());
unsigned sourceRank = sourceType.getRank();
auto newExtractStridedMetadata =
rewriter.create<memref::ExtractStridedMetadataOp>(origLoc, source);
auto [sourceStrides, sourceOffset] = getStridesAndOffset(sourceType);
#ifndef NDEBUG
auto [resultStrides, resultOffset] = getStridesAndOffset(subview.getType());
#endif
SmallVector<OpFoldResult> strides;
SmallVector<OpFoldResult> subStrides = subview.getMixedStrides();
auto origStrides = newExtractStridedMetadata.getStrides();
SmallVector<OpFoldResult> values(2 * sourceRank + 1);
SmallVector<AffineExpr> symbols(2 * sourceRank + 1);
bindSymbolsList(rewriter.getContext(), MutableArrayRef{symbols});
AffineExpr expr = symbols.front();
values[0] = ShapedType::isDynamic(sourceOffset)
? getAsOpFoldResult(newExtractStridedMetadata.getOffset())
: rewriter.getIndexAttr(sourceOffset);
SmallVector<OpFoldResult> subOffsets = subview.getMixedOffsets();
AffineExpr s0 = rewriter.getAffineSymbolExpr(0);
AffineExpr s1 = rewriter.getAffineSymbolExpr(1);
for (unsigned i = 0; i < sourceRank; ++i) {
OpFoldResult origStride =
ShapedType::isDynamic(sourceStrides[i])
? origStrides[i]
: OpFoldResult(rewriter.getIndexAttr(sourceStrides[i]));
strides.push_back(makeComposedFoldedAffineApply(
rewriter, origLoc, s0 * s1, {subStrides[i], origStride}));
unsigned baseIdxForDim = 1 + 2 * i;
unsigned subOffsetForDim = baseIdxForDim;
unsigned origStrideForDim = baseIdxForDim + 1;
expr = expr + symbols[subOffsetForDim] * symbols[origStrideForDim];
values[subOffsetForDim] = subOffsets[i];
values[origStrideForDim] = origStride;
}
OpFoldResult finalOffset =
makeComposedFoldedAffineApply(rewriter, origLoc, expr, values);
#ifndef NDEBUG
std::optional<int64_t> computedOffset = getConstantIntValue(finalOffset);
if (computedOffset && !ShapedType::isDynamic(resultOffset))
assert(*computedOffset == resultOffset &&
"mismatch between computed offset and result type offset");
#endif
auto subType = cast<MemRefType>(subview.getType());
unsigned subRank = subType.getRank();
SmallVector<OpFoldResult> subSizes = subview.getMixedSizes();
llvm::SmallBitVector droppedDims = subview.getDroppedDims();
SmallVector<OpFoldResult> finalSizes;
finalSizes.reserve(subRank);
SmallVector<OpFoldResult> finalStrides;
finalStrides.reserve(subRank);
#ifndef NDEBUG
int64_t j = 0;
#endif
for (unsigned i = 0; i < sourceRank; ++i) {
if (droppedDims.test(i))
continue;
finalSizes.push_back(subSizes[i]);
finalStrides.push_back(strides[i]);
#ifndef NDEBUG
std::optional<int64_t> computedStride = getConstantIntValue(strides[i]);
if (computedStride && !ShapedType::isDynamic(resultStrides[j]))
assert(*computedStride == resultStrides[j] &&
"mismatch between computed stride and result type stride");
++j;
#endif
}
assert(finalSizes.size() == subRank &&
"Should have populated all the values at this point");
return StridedMetadata{newExtractStridedMetadata.getBaseBuffer(), finalOffset,
finalSizes, finalStrides};
}
struct SubviewFolder : public OpRewritePattern<memref::SubViewOp> {
public:
using OpRewritePattern<memref::SubViewOp>::OpRewritePattern;
LogicalResult matchAndRewrite(memref::SubViewOp subview,
PatternRewriter &rewriter) const override {
FailureOr<StridedMetadata> stridedMetadata =
resolveSubviewStridedMetadata(rewriter, subview);
if (failed(stridedMetadata)) {
return rewriter.notifyMatchFailure(subview,
"failed to resolve subview metadata");
}
rewriter.replaceOpWithNewOp<memref::ReinterpretCastOp>(
subview, subview.getType(), stridedMetadata->basePtr,
stridedMetadata->offset, stridedMetadata->sizes,
stridedMetadata->strides);
return success();
}
};
struct ExtractStridedMetadataOpSubviewFolder
: OpRewritePattern<memref::ExtractStridedMetadataOp> {
using OpRewritePattern::OpRewritePattern;
LogicalResult matchAndRewrite(memref::ExtractStridedMetadataOp op,
PatternRewriter &rewriter) const override {
auto subviewOp = op.getSource().getDefiningOp<memref::SubViewOp>();
if (!subviewOp)
return failure();
FailureOr<StridedMetadata> stridedMetadata =
resolveSubviewStridedMetadata(rewriter, subviewOp);
if (failed(stridedMetadata)) {
return rewriter.notifyMatchFailure(
op, "failed to resolve metadata in terms of source subview op");
}
Location loc = subviewOp.getLoc();
SmallVector<Value> results;
results.reserve(subviewOp.getType().getRank() * 2 + 2);
results.push_back(stridedMetadata->basePtr);
results.push_back(getValueOrCreateConstantIndexOp(rewriter, loc,
stridedMetadata->offset));
results.append(
getValueOrCreateConstantIndexOp(rewriter, loc, stridedMetadata->sizes));
results.append(getValueOrCreateConstantIndexOp(rewriter, loc,
stridedMetadata->strides));
rewriter.replaceOp(op, results);
return success();
}
};
static SmallVector<OpFoldResult>
getExpandedSizes(memref::ExpandShapeOp expandShape, OpBuilder &builder,
ArrayRef<OpFoldResult> origSizes, unsigned groupId) {
SmallVector<int64_t, 2> reassocGroup =
expandShape.getReassociationIndices()[groupId];
assert(!reassocGroup.empty() &&
"Reassociation group should have at least one dimension");
unsigned groupSize = reassocGroup.size();
SmallVector<OpFoldResult> expandedSizes(groupSize);
uint64_t productOfAllStaticSizes = 1;
std::optional<unsigned> dynSizeIdx;
MemRefType expandShapeType = expandShape.getResultType();
for (unsigned i = 0; i < groupSize; ++i) {
uint64_t dimSize = expandShapeType.getDimSize(reassocGroup[i]);
if (ShapedType::isDynamic(dimSize)) {
assert(!dynSizeIdx && "There must be at most one dynamic size per group");
dynSizeIdx = i;
continue;
}
productOfAllStaticSizes *= dimSize;
expandedSizes[i] = builder.getIndexAttr(dimSize);
}
if (dynSizeIdx) {
AffineExpr s0 = builder.getAffineSymbolExpr(0);
expandedSizes[*dynSizeIdx] = makeComposedFoldedAffineApply(
builder, expandShape.getLoc(), s0.floorDiv(productOfAllStaticSizes),
origSizes[groupId]);
}
return expandedSizes;
}
SmallVector<OpFoldResult> getExpandedStrides(memref::ExpandShapeOp expandShape,
OpBuilder &builder,
ArrayRef<OpFoldResult> origSizes,
ArrayRef<OpFoldResult> origStrides,
unsigned groupId) {
SmallVector<int64_t, 2> reassocGroup =
expandShape.getReassociationIndices()[groupId];
assert(!reassocGroup.empty() &&
"Reassociation group should have at least one dimension");
unsigned groupSize = reassocGroup.size();
MemRefType expandShapeType = expandShape.getResultType();
std::optional<int64_t> dynSizeIdx;
uint64_t currentStride = 1;
SmallVector<OpFoldResult> expandedStrides(groupSize);
for (int i = groupSize - 1; i >= 0; --i) {
expandedStrides[i] = builder.getIndexAttr(currentStride);
uint64_t dimSize = expandShapeType.getDimSize(reassocGroup[i]);
if (ShapedType::isDynamic(dimSize)) {
assert(!dynSizeIdx && "There must be at most one dynamic size per group");
dynSizeIdx = i;
continue;
}
currentStride *= dimSize;
}
Value source = expandShape.getSrc();
auto sourceType = cast<MemRefType>(source.getType());
auto [strides, offset] = getStridesAndOffset(sourceType);
OpFoldResult origStride = ShapedType::isDynamic(strides[groupId])
? origStrides[groupId]
: builder.getIndexAttr(strides[groupId]);
int64_t doneStrideIdx = 0;
if (dynSizeIdx) {
int64_t productOfAllStaticSizes = currentStride;
assert(ShapedType::isDynamic(sourceType.getDimSize(groupId)) &&
"We shouldn't be able to change dynamicity");
OpFoldResult origSize = origSizes[groupId];
AffineExpr s0 = builder.getAffineSymbolExpr(0);
AffineExpr s1 = builder.getAffineSymbolExpr(1);
for (; doneStrideIdx < *dynSizeIdx; ++doneStrideIdx) {
int64_t baseExpandedStride =
cast<IntegerAttr>(expandedStrides[doneStrideIdx].get<Attribute>())
.getInt();
expandedStrides[doneStrideIdx] = makeComposedFoldedAffineApply(
builder, expandShape.getLoc(),
(s0 * baseExpandedStride).floorDiv(productOfAllStaticSizes) * s1,
{origSize, origStride});
}
}
AffineExpr s0 = builder.getAffineSymbolExpr(0);
for (; doneStrideIdx < groupSize; ++doneStrideIdx) {
int64_t baseExpandedStride =
cast<IntegerAttr>(expandedStrides[doneStrideIdx].get<Attribute>())
.getInt();
expandedStrides[doneStrideIdx] = makeComposedFoldedAffineApply(
builder, expandShape.getLoc(), s0 * baseExpandedStride, {origStride});
}
return expandedStrides;
}
static OpFoldResult
getProductOfValues(ArrayRef<int64_t> indices, OpBuilder &builder, Location loc,
ArrayRef<int64_t> maybeConstants,
ArrayRef<OpFoldResult> values,
llvm::function_ref<bool(int64_t)> isDynamic) {
AffineExpr productOfValues = builder.getAffineConstantExpr(1);
SmallVector<OpFoldResult> inputValues;
unsigned numberOfSymbols = 0;
unsigned groupSize = indices.size();
for (unsigned i = 0; i < groupSize; ++i) {
productOfValues =
productOfValues * builder.getAffineSymbolExpr(numberOfSymbols++);
unsigned srcIdx = indices[i];
int64_t maybeConstant = maybeConstants[srcIdx];
inputValues.push_back(isDynamic(maybeConstant)
? values[srcIdx]
: builder.getIndexAttr(maybeConstant));
}
return makeComposedFoldedAffineApply(builder, loc, productOfValues,
inputValues);
}
static SmallVector<OpFoldResult>
getCollapsedSize(memref::CollapseShapeOp collapseShape, OpBuilder &builder,
ArrayRef<OpFoldResult> origSizes, unsigned groupId) {
SmallVector<OpFoldResult> collapsedSize;
MemRefType collapseShapeType = collapseShape.getResultType();
uint64_t size = collapseShapeType.getDimSize(groupId);
if (!ShapedType::isDynamic(size)) {
collapsedSize.push_back(builder.getIndexAttr(size));
return collapsedSize;
}
Value source = collapseShape.getSrc();
auto sourceType = cast<MemRefType>(source.getType());
SmallVector<int64_t, 2> reassocGroup =
collapseShape.getReassociationIndices()[groupId];
collapsedSize.push_back(getProductOfValues(
reassocGroup, builder, collapseShape.getLoc(), sourceType.getShape(),
origSizes, ShapedType::isDynamic));
return collapsedSize;
}
static SmallVector<OpFoldResult>
getCollapsedStride(memref::CollapseShapeOp collapseShape, OpBuilder &builder,
ArrayRef<OpFoldResult> origSizes,
ArrayRef<OpFoldResult> origStrides, unsigned groupId) {
SmallVector<int64_t, 2> reassocGroup =
collapseShape.getReassociationIndices()[groupId];
assert(!reassocGroup.empty() &&
"Reassociation group should have at least one dimension");
Value source = collapseShape.getSrc();
auto sourceType = cast<MemRefType>(source.getType());
auto [strides, offset] = getStridesAndOffset(sourceType);
SmallVector<OpFoldResult> groupStrides;
ArrayRef<int64_t> srcShape = sourceType.getShape();
for (int64_t currentDim : reassocGroup) {
if (srcShape[currentDim] == 1)
continue;
int64_t currentStride = strides[currentDim];
groupStrides.push_back(ShapedType::isDynamic(currentStride)
? origStrides[currentDim]
: builder.getIndexAttr(currentStride));
}
if (groupStrides.empty()) {
MemRefType collapsedType = collapseShape.getResultType();
auto [collapsedStrides, collapsedOffset] =
getStridesAndOffset(collapsedType);
int64_t finalStride = collapsedStrides[groupId];
if (ShapedType::isDynamic(finalStride)) {
for (int64_t currentDim : reassocGroup) {
assert(srcShape[currentDim] == 1 &&
"We should be dealing with 1x1x...x1");
if (ShapedType::isDynamic(strides[currentDim]))
return {origStrides[currentDim]};
}
llvm_unreachable("We should have found a dynamic stride");
}
return {builder.getIndexAttr(finalStride)};
}
auto minMap = AffineMap::getMultiDimIdentityMap(groupStrides.size(),
builder.getContext());
return {makeComposedFoldedAffineMin(builder, collapseShape.getLoc(), minMap,
groupStrides)};
}
template <typename ReassociativeReshapeLikeOp>
static FailureOr<StridedMetadata> resolveReshapeStridedMetadata(
RewriterBase &rewriter, ReassociativeReshapeLikeOp reshape,
function_ref<SmallVector<OpFoldResult>(
ReassociativeReshapeLikeOp, OpBuilder &,
ArrayRef<OpFoldResult> , unsigned )>
getReshapedSizes,
function_ref<SmallVector<OpFoldResult>(
ReassociativeReshapeLikeOp, OpBuilder &,
ArrayRef<OpFoldResult> ,
ArrayRef<OpFoldResult> , unsigned )>
getReshapedStrides) {
Location origLoc = reshape.getLoc();
Value source = reshape.getSrc();
auto sourceType = cast<MemRefType>(source.getType());
unsigned sourceRank = sourceType.getRank();
auto newExtractStridedMetadata =
rewriter.create<memref::ExtractStridedMetadataOp>(origLoc, source);
auto [strides, offset] = getStridesAndOffset(sourceType);
MemRefType reshapeType = reshape.getResultType();
unsigned reshapeRank = reshapeType.getRank();
OpFoldResult offsetOfr =
ShapedType::isDynamic(offset)
? getAsOpFoldResult(newExtractStridedMetadata.getOffset())
: rewriter.getIndexAttr(offset);
if (sourceRank == 0) {
SmallVector<OpFoldResult> ones(reshapeRank, rewriter.getIndexAttr(1));
return StridedMetadata{newExtractStridedMetadata.getBaseBuffer(), offsetOfr,
ones, ones};
}
SmallVector<OpFoldResult> finalSizes;
finalSizes.reserve(reshapeRank);
SmallVector<OpFoldResult> finalStrides;
finalStrides.reserve(reshapeRank);
SmallVector<OpFoldResult> origSizes =
getAsOpFoldResult(newExtractStridedMetadata.getSizes());
SmallVector<OpFoldResult> origStrides =
getAsOpFoldResult(newExtractStridedMetadata.getStrides());
unsigned idx = 0, endIdx = reshape.getReassociationIndices().size();
for (; idx != endIdx; ++idx) {
SmallVector<OpFoldResult> reshapedSizes =
getReshapedSizes(reshape, rewriter, origSizes, idx);
SmallVector<OpFoldResult> reshapedStrides = getReshapedStrides(
reshape, rewriter, origSizes, origStrides, idx);
unsigned groupSize = reshapedSizes.size();
for (unsigned i = 0; i < groupSize; ++i) {
finalSizes.push_back(reshapedSizes[i]);
finalStrides.push_back(reshapedStrides[i]);
}
}
assert(((isa<memref::ExpandShapeOp>(reshape) && idx == sourceRank) ||
(isa<memref::CollapseShapeOp>(reshape) && idx == reshapeRank)) &&
"We should have visited all the input dimensions");
assert(finalSizes.size() == reshapeRank &&
"We should have populated all the values");
return StridedMetadata{newExtractStridedMetadata.getBaseBuffer(), offsetOfr,
finalSizes, finalStrides};
}
template <typename ReassociativeReshapeLikeOp,
SmallVector<OpFoldResult> (*getReshapedSizes)(
ReassociativeReshapeLikeOp, OpBuilder &,
ArrayRef<OpFoldResult> , unsigned ),
SmallVector<OpFoldResult> (*getReshapedStrides)(
ReassociativeReshapeLikeOp, OpBuilder &,
ArrayRef<OpFoldResult> ,
ArrayRef<OpFoldResult> , unsigned )>
struct ReshapeFolder : public OpRewritePattern<ReassociativeReshapeLikeOp> {
public:
using OpRewritePattern<ReassociativeReshapeLikeOp>::OpRewritePattern;
LogicalResult matchAndRewrite(ReassociativeReshapeLikeOp reshape,
PatternRewriter &rewriter) const override {
FailureOr<StridedMetadata> stridedMetadata =
resolveReshapeStridedMetadata<ReassociativeReshapeLikeOp>(
rewriter, reshape, getReshapedSizes, getReshapedStrides);
if (failed(stridedMetadata)) {
return rewriter.notifyMatchFailure(reshape,
"failed to resolve reshape metadata");
}
rewriter.replaceOpWithNewOp<memref::ReinterpretCastOp>(
reshape, reshape.getType(), stridedMetadata->basePtr,
stridedMetadata->offset, stridedMetadata->sizes,
stridedMetadata->strides);
return success();
}
};
struct ExtractStridedMetadataOpCollapseShapeFolder
: OpRewritePattern<memref::ExtractStridedMetadataOp> {
using OpRewritePattern::OpRewritePattern;
LogicalResult matchAndRewrite(memref::ExtractStridedMetadataOp op,
PatternRewriter &rewriter) const override {
auto collapseShapeOp =
op.getSource().getDefiningOp<memref::CollapseShapeOp>();
if (!collapseShapeOp)
return failure();
FailureOr<StridedMetadata> stridedMetadata =
resolveReshapeStridedMetadata<memref::CollapseShapeOp>(
rewriter, collapseShapeOp, getCollapsedSize, getCollapsedStride);
if (failed(stridedMetadata)) {
return rewriter.notifyMatchFailure(
op,
"failed to resolve metadata in terms of source collapse_shape op");
}
Location loc = collapseShapeOp.getLoc();
SmallVector<Value> results;
results.push_back(stridedMetadata->basePtr);
results.push_back(getValueOrCreateConstantIndexOp(rewriter, loc,
stridedMetadata->offset));
results.append(
getValueOrCreateConstantIndexOp(rewriter, loc, stridedMetadata->sizes));
results.append(getValueOrCreateConstantIndexOp(rewriter, loc,
stridedMetadata->strides));
rewriter.replaceOp(op, results);
return success();
}
};
template <typename AllocLikeOp>
struct ExtractStridedMetadataOpAllocFolder
: public OpRewritePattern<memref::ExtractStridedMetadataOp> {
public:
using OpRewritePattern<memref::ExtractStridedMetadataOp>::OpRewritePattern;
LogicalResult matchAndRewrite(memref::ExtractStridedMetadataOp op,
PatternRewriter &rewriter) const override {
auto allocLikeOp = op.getSource().getDefiningOp<AllocLikeOp>();
if (!allocLikeOp)
return failure();
auto memRefType = cast<MemRefType>(allocLikeOp.getResult().getType());
if (!memRefType.getLayout().isIdentity())
return rewriter.notifyMatchFailure(
allocLikeOp, "alloc-like operations should have been normalized");
Location loc = op.getLoc();
int rank = memRefType.getRank();
ValueRange dynamic = allocLikeOp.getDynamicSizes();
SmallVector<OpFoldResult> sizes;
sizes.reserve(rank);
unsigned dynamicPos = 0;
for (int64_t size : memRefType.getShape()) {
if (ShapedType::isDynamic(size))
sizes.push_back(dynamic[dynamicPos++]);
else
sizes.push_back(rewriter.getIndexAttr(size));
}
SmallVector<OpFoldResult> strides(rank, rewriter.getIndexAttr(1));
AffineExpr expr = rewriter.getAffineConstantExpr(1);
unsigned symbolNumber = 0;
for (int i = rank - 2; i >= 0; --i) {
expr = expr * rewriter.getAffineSymbolExpr(symbolNumber++);
assert(i + 1 + symbolNumber == sizes.size() &&
"The ArrayRef should encompass the last #symbolNumber sizes");
ArrayRef<OpFoldResult> sizesInvolvedInStride(&sizes[i + 1], symbolNumber);
strides[i] = makeComposedFoldedAffineApply(rewriter, loc, expr,
sizesInvolvedInStride);
}
SmallVector<Value> results;
results.reserve(rank * 2 + 2);
auto baseBufferType = cast<MemRefType>(op.getBaseBuffer().getType());
int64_t offset = 0;
if (op.getBaseBuffer().use_empty()) {
results.push_back(nullptr);
} else {
if (allocLikeOp.getType() == baseBufferType)
results.push_back(allocLikeOp);
else
results.push_back(rewriter.create<memref::ReinterpretCastOp>(
loc, baseBufferType, allocLikeOp, offset,
ArrayRef<int64_t>(),
ArrayRef<int64_t>()));
}
results.push_back(rewriter.create<arith::ConstantIndexOp>(loc, offset));
for (OpFoldResult size : sizes)
results.push_back(getValueOrCreateConstantIndexOp(rewriter, loc, size));
for (OpFoldResult stride : strides)
results.push_back(getValueOrCreateConstantIndexOp(rewriter, loc, stride));
rewriter.replaceOp(op, results);
return success();
}
};
struct ExtractStridedMetadataOpGetGlobalFolder
: public OpRewritePattern<memref::ExtractStridedMetadataOp> {
public:
using OpRewritePattern<memref::ExtractStridedMetadataOp>::OpRewritePattern;
LogicalResult matchAndRewrite(memref::ExtractStridedMetadataOp op,
PatternRewriter &rewriter) const override {
auto getGlobalOp = op.getSource().getDefiningOp<memref::GetGlobalOp>();
if (!getGlobalOp)
return failure();
auto memRefType = cast<MemRefType>(getGlobalOp.getResult().getType());
if (!memRefType.getLayout().isIdentity()) {
return rewriter.notifyMatchFailure(
getGlobalOp,
"get-global operation result should have been normalized");
}
Location loc = op.getLoc();
int rank = memRefType.getRank();
ArrayRef<int64_t> sizes = memRefType.getShape();
assert(!llvm::any_of(sizes, ShapedType::isDynamic) &&
"unexpected dynamic shape for result of `memref.get_global` op");
SmallVector<int64_t> strides = computeSuffixProduct(sizes);
SmallVector<Value> results;
results.reserve(rank * 2 + 2);
auto baseBufferType = cast<MemRefType>(op.getBaseBuffer().getType());
int64_t offset = 0;
if (getGlobalOp.getType() == baseBufferType)
results.push_back(getGlobalOp);
else
results.push_back(rewriter.create<memref::ReinterpretCastOp>(
loc, baseBufferType, getGlobalOp, offset,
ArrayRef<int64_t>(),
ArrayRef<int64_t>()));
results.push_back(rewriter.create<arith::ConstantIndexOp>(loc, offset));
for (auto size : sizes)
results.push_back(rewriter.create<arith::ConstantIndexOp>(loc, size));
for (auto stride : strides)
results.push_back(rewriter.create<arith::ConstantIndexOp>(loc, stride));
rewriter.replaceOp(op, results);
return success();
}
};
class RewriteExtractAlignedPointerAsIndexOfViewLikeOp
: public OpRewritePattern<memref::ExtractAlignedPointerAsIndexOp> {
using OpRewritePattern::OpRewritePattern;
LogicalResult
matchAndRewrite(memref::ExtractAlignedPointerAsIndexOp extractOp,
PatternRewriter &rewriter) const override {
auto viewLikeOp =
extractOp.getSource().getDefiningOp<ViewLikeOpInterface>();
if (!viewLikeOp)
return rewriter.notifyMatchFailure(extractOp, "not a ViewLike source");
rewriter.modifyOpInPlace(extractOp, [&]() {
extractOp.getSourceMutable().assign(viewLikeOp.getViewSource());
});
return success();
}
};
class ExtractStridedMetadataOpReinterpretCastFolder
: public OpRewritePattern<memref::ExtractStridedMetadataOp> {
using OpRewritePattern::OpRewritePattern;
LogicalResult
matchAndRewrite(memref::ExtractStridedMetadataOp extractStridedMetadataOp,
PatternRewriter &rewriter) const override {
auto reinterpretCastOp = extractStridedMetadataOp.getSource()
.getDefiningOp<memref::ReinterpretCastOp>();
if (!reinterpretCastOp)
return failure();
Location loc = extractStridedMetadataOp.getLoc();
SmallVector<Type> inferredReturnTypes;
if (failed(extractStridedMetadataOp.inferReturnTypes(
rewriter.getContext(), loc, {reinterpretCastOp.getSource()},
{}, nullptr, {},
inferredReturnTypes)))
return rewriter.notifyMatchFailure(
reinterpretCastOp, "reinterpret_cast source's type is incompatible");
auto memrefType = cast<MemRefType>(reinterpretCastOp.getResult().getType());
unsigned rank = memrefType.getRank();
SmallVector<OpFoldResult> results;
results.resize_for_overwrite(rank * 2 + 2);
auto newExtractStridedMetadata =
rewriter.create<memref::ExtractStridedMetadataOp>(
loc, reinterpretCastOp.getSource());
results[0] = newExtractStridedMetadata.getBaseBuffer();
results[1] = getValueOrCreateConstantIndexOp(
rewriter, loc, reinterpretCastOp.getMixedOffsets()[0]);
const unsigned sizeStartIdx = 2;
const unsigned strideStartIdx = sizeStartIdx + rank;
SmallVector<OpFoldResult> sizes = reinterpretCastOp.getMixedSizes();
SmallVector<OpFoldResult> strides = reinterpretCastOp.getMixedStrides();
for (unsigned i = 0; i < rank; ++i) {
results[sizeStartIdx + i] = sizes[i];
results[strideStartIdx + i] = strides[i];
}
rewriter.replaceOp(extractStridedMetadataOp,
getValueOrCreateConstantIndexOp(rewriter, loc, results));
return success();
}
};
class ExtractStridedMetadataOpCastFolder
: public OpRewritePattern<memref::ExtractStridedMetadataOp> {
using OpRewritePattern::OpRewritePattern;
LogicalResult
matchAndRewrite(memref::ExtractStridedMetadataOp extractStridedMetadataOp,
PatternRewriter &rewriter) const override {
Value source = extractStridedMetadataOp.getSource();
auto castOp = source.getDefiningOp<memref::CastOp>();
if (!castOp)
return failure();
Location loc = extractStridedMetadataOp.getLoc();
SmallVector<Type> inferredReturnTypes;
if (failed(extractStridedMetadataOp.inferReturnTypes(
rewriter.getContext(), loc, {castOp.getSource()},
{}, nullptr, {},
inferredReturnTypes)))
return rewriter.notifyMatchFailure(castOp,
"cast source's type is incompatible");
auto memrefType = cast<MemRefType>(source.getType());
unsigned rank = memrefType.getRank();
SmallVector<OpFoldResult> results;
results.resize_for_overwrite(rank * 2 + 2);
auto newExtractStridedMetadata =
rewriter.create<memref::ExtractStridedMetadataOp>(loc,
castOp.getSource());
results[0] = newExtractStridedMetadata.getBaseBuffer();
auto getConstantOrValue = [&rewriter](int64_t constant,
OpFoldResult ofr) -> OpFoldResult {
return !ShapedType::isDynamic(constant)
? OpFoldResult(rewriter.getIndexAttr(constant))
: ofr;
};
auto [sourceStrides, sourceOffset] = getStridesAndOffset(memrefType);
assert(sourceStrides.size() == rank && "unexpected number of strides");
results[1] =
getConstantOrValue(sourceOffset, newExtractStridedMetadata.getOffset());
const unsigned sizeStartIdx = 2;
const unsigned strideStartIdx = sizeStartIdx + rank;
ArrayRef<int64_t> sourceSizes = memrefType.getShape();
SmallVector<OpFoldResult> sizes = newExtractStridedMetadata.getSizes();
SmallVector<OpFoldResult> strides = newExtractStridedMetadata.getStrides();
for (unsigned i = 0; i < rank; ++i) {
results[sizeStartIdx + i] = getConstantOrValue(sourceSizes[i], sizes[i]);
results[strideStartIdx + i] =
getConstantOrValue(sourceStrides[i], strides[i]);
}
rewriter.replaceOp(extractStridedMetadataOp,
getValueOrCreateConstantIndexOp(rewriter, loc, results));
return success();
}
};
class ExtractStridedMetadataOpExtractStridedMetadataFolder
: public OpRewritePattern<memref::ExtractStridedMetadataOp> {
using OpRewritePattern::OpRewritePattern;
LogicalResult
matchAndRewrite(memref::ExtractStridedMetadataOp extractStridedMetadataOp,
PatternRewriter &rewriter) const override {
auto sourceExtractStridedMetadataOp =
extractStridedMetadataOp.getSource()
.getDefiningOp<memref::ExtractStridedMetadataOp>();
if (!sourceExtractStridedMetadataOp)
return failure();
Location loc = extractStridedMetadataOp.getLoc();
rewriter.replaceOp(extractStridedMetadataOp,
{sourceExtractStridedMetadataOp.getBaseBuffer(),
getValueOrCreateConstantIndexOp(
rewriter, loc, rewriter.getIndexAttr(0))});
return success();
}
};
}
void memref::populateExpandStridedMetadataPatterns(
RewritePatternSet &patterns) {
patterns.add<SubviewFolder,
ReshapeFolder<memref::ExpandShapeOp, getExpandedSizes,
getExpandedStrides>,
ReshapeFolder<memref::CollapseShapeOp, getCollapsedSize,
getCollapsedStride>,
ExtractStridedMetadataOpAllocFolder<memref::AllocOp>,
ExtractStridedMetadataOpAllocFolder<memref::AllocaOp>,
ExtractStridedMetadataOpCollapseShapeFolder,
ExtractStridedMetadataOpGetGlobalFolder,
RewriteExtractAlignedPointerAsIndexOfViewLikeOp,
ExtractStridedMetadataOpReinterpretCastFolder,
ExtractStridedMetadataOpSubviewFolder,
ExtractStridedMetadataOpCastFolder,
ExtractStridedMetadataOpExtractStridedMetadataFolder>(
patterns.getContext());
}
void memref::populateResolveExtractStridedMetadataPatterns(
RewritePatternSet &patterns) {
patterns.add<ExtractStridedMetadataOpAllocFolder<memref::AllocOp>,
ExtractStridedMetadataOpAllocFolder<memref::AllocaOp>,
ExtractStridedMetadataOpCollapseShapeFolder,
ExtractStridedMetadataOpGetGlobalFolder,
ExtractStridedMetadataOpSubviewFolder,
RewriteExtractAlignedPointerAsIndexOfViewLikeOp,
ExtractStridedMetadataOpReinterpretCastFolder,
ExtractStridedMetadataOpCastFolder,
ExtractStridedMetadataOpExtractStridedMetadataFolder>(
patterns.getContext());
}
namespace {
struct ExpandStridedMetadataPass final
: public memref::impl::ExpandStridedMetadataBase<
ExpandStridedMetadataPass> {
void runOnOperation() override;
};
}
void ExpandStridedMetadataPass::runOnOperation() {
RewritePatternSet patterns(&getContext());
memref::populateExpandStridedMetadataPatterns(patterns);
(void)applyPatternsAndFoldGreedily(getOperation(), std::move(patterns));
}
std::unique_ptr<Pass> memref::createExpandStridedMetadataPass() {
return std::make_unique<ExpandStridedMetadataPass>();
}