25#include "llvm/ADT/STLExtras.h"
26#include "llvm/ADT/SmallBitVector.h"
27#include "llvm/ADT/SmallVectorExtras.h"
37 return arith::ConstantOp::materialize(builder, value, type, loc);
50 auto cast = operand.get().getDefiningOp<CastOp>();
51 if (cast && operand.get() != inner &&
52 !llvm::isa<UnrankedMemRefType>(cast.getOperand().getType())) {
53 operand.set(cast.getOperand());
63 if (
auto memref = llvm::dyn_cast<MemRefType>(type))
64 return RankedTensorType::get(
memref.getShape(),
memref.getElementType());
65 if (
auto memref = llvm::dyn_cast<UnrankedMemRefType>(type))
66 return UnrankedTensorType::get(
memref.getElementType());
72 auto memrefType = llvm::cast<MemRefType>(value.
getType());
73 if (memrefType.isDynamicDim(dim))
74 return builder.
createOrFold<memref::DimOp>(loc, value, dim);
81 auto memrefType = llvm::cast<MemRefType>(value.
getType());
83 for (
int64_t i = 0; i < memrefType.getRank(); ++i)
100 assert(constValues.size() == values.size() &&
101 "incorrect number of const values");
102 for (
auto [i, cstVal] : llvm::enumerate(constValues)) {
104 if (ShapedType::isStatic(cstVal)) {
118static std::tuple<MemorySpaceCastOpInterface, PtrLikeTypeInterface, Type>
120 MemorySpaceCastOpInterface castOp =
121 MemorySpaceCastOpInterface::getIfPromotableCast(src);
129 FailureOr<PtrLikeTypeInterface> srcTy = resultTy.
clonePtrWith(
130 castOp.getSourcePtr().getType().getMemorySpace(), std::nullopt);
134 FailureOr<PtrLikeTypeInterface> tgtTy = resultTy.
clonePtrWith(
135 castOp.getTargetPtr().getType().getMemorySpace(), std::nullopt);
140 if (!castOp.isValidMemorySpaceCast(*tgtTy, *srcTy))
143 return std::make_tuple(castOp, *tgtTy, *srcTy);
148template <
typename ConcreteOpTy>
149static FailureOr<std::optional<SmallVector<Value>>>
159 llvm::append_range(operands, op->getOperands());
163 auto newOp = ConcreteOpTy::create(
164 builder, op.getLoc(),
TypeRange(resTy), operands, op.getProperties(),
165 op->getDiscardableAttrDictionary().getValue());
168 MemorySpaceCastOpInterface
result = castOp.cloneMemorySpaceCastOp(
171 return std::optional<SmallVector<Value>>(
179void AllocOp::getAsmResultNames(
181 setNameFn(getResult(),
"alloc");
184void AllocaOp::getAsmResultNames(
186 setNameFn(getResult(),
"alloca");
189template <
typename AllocLikeOp>
191 static_assert(llvm::is_one_of<AllocLikeOp, AllocOp, AllocaOp>::value,
192 "applies to only alloc or alloca");
193 auto memRefType = llvm::dyn_cast<MemRefType>(op.getResult().getType());
195 return op.emitOpError(
"result must be a memref");
200 unsigned numSymbols = 0;
201 if (!memRefType.getLayout().isIdentity())
202 numSymbols = memRefType.getLayout().getAffineMap().getNumSymbols();
203 if (op.getSymbolOperands().size() != numSymbols)
204 return op.emitOpError(
"symbol operand count does not equal memref symbol "
206 << numSymbols <<
", got " << op.getSymbolOperands().size();
213LogicalResult AllocaOp::verify() {
217 "requires an ancestor op with AutomaticAllocationScope trait");
224template <
typename AllocLikeOp>
226 using OpRewritePattern<AllocLikeOp>::OpRewritePattern;
228 LogicalResult matchAndRewrite(AllocLikeOp alloc,
229 PatternRewriter &rewriter)
const override {
232 if (llvm::none_of(alloc.getDynamicSizes(), [](Value operand) {
234 if (!matchPattern(operand, m_ConstantInt(&constSizeArg)))
236 return constSizeArg.isNonNegative();
240 auto memrefType = alloc.getType();
244 SmallVector<int64_t, 4> newShapeConstants;
245 newShapeConstants.reserve(memrefType.getRank());
246 SmallVector<Value, 4> dynamicSizes;
248 unsigned dynamicDimPos = 0;
249 for (
unsigned dim = 0, e = memrefType.getRank(); dim < e; ++dim) {
250 int64_t dimSize = memrefType.getDimSize(dim);
252 if (ShapedType::isStatic(dimSize)) {
253 newShapeConstants.push_back(dimSize);
256 auto dynamicSize = alloc.getDynamicSizes()[dynamicDimPos];
259 constSizeArg.isNonNegative()) {
261 newShapeConstants.push_back(constSizeArg.getZExtValue());
264 newShapeConstants.push_back(ShapedType::kDynamic);
265 dynamicSizes.push_back(dynamicSize);
271 MemRefType newMemRefType =
272 MemRefType::Builder(memrefType).setShape(newShapeConstants);
273 assert(dynamicSizes.size() == newMemRefType.getNumDynamicDims());
276 auto newAlloc = AllocLikeOp::create(rewriter, alloc.getLoc(), newMemRefType,
277 dynamicSizes, alloc.getSymbolOperands(),
278 alloc.getAlignmentAttr());
288 using OpRewritePattern<T>::OpRewritePattern;
290 LogicalResult matchAndRewrite(T alloc,
291 PatternRewriter &rewriter)
const override {
292 if (llvm::any_of(alloc->getUsers(), [&](Operation *op) {
293 if (auto storeOp = dyn_cast<StoreOp>(op))
294 return storeOp.getValue() == alloc;
295 return !isa<DeallocOp>(op);
299 for (Operation *user : llvm::make_early_inc_range(alloc->getUsers()))
310 results.
add<SimplifyAllocConst<AllocOp>, SimplifyDeadAlloc<AllocOp>>(context);
315 results.
add<SimplifyAllocConst<AllocaOp>, SimplifyDeadAlloc<AllocaOp>>(
323LogicalResult ReallocOp::verify() {
324 auto sourceType = llvm::cast<MemRefType>(getOperand(0).
getType());
325 MemRefType resultType =
getType();
328 if (!sourceType.getLayout().isIdentity())
329 return emitError(
"unsupported layout for source memref type ")
333 if (!resultType.getLayout().isIdentity())
334 return emitError(
"unsupported layout for result memref type ")
338 if (sourceType.getMemorySpace() != resultType.getMemorySpace())
339 return emitError(
"different memory spaces specified for source memref "
341 << sourceType <<
" and result memref type " << resultType;
349 if (resultType.getNumDynamicDims() && !getDynamicResultSize())
350 return emitError(
"missing dimension operand for result type ")
352 if (!resultType.getNumDynamicDims() && getDynamicResultSize())
353 return emitError(
"unnecessary dimension operand for result type ")
361 results.
add<SimplifyDeadAlloc<ReallocOp>>(context);
369 bool printBlockTerminators =
false;
372 if (!getResults().empty()) {
373 p <<
" -> (" << getResultTypes() <<
")";
374 printBlockTerminators =
true;
379 printBlockTerminators);
385 result.regions.reserve(1);
395 AllocaScopeOp::ensureTerminator(*bodyRegion, parser.
getBuilder(),
405void AllocaScopeOp::getSuccessorRegions(
422 MemoryEffectOpInterface
interface = dyn_cast<MemoryEffectOpInterface>(op);
427 interface.getEffectOnValue<MemoryEffects::Allocate>(res)) {
428 if (isa<SideEffects::AutomaticAllocationScopeResource>(
429 effect->getResource()))
445 MemoryEffectOpInterface
interface = dyn_cast<MemoryEffectOpInterface>(op);
450 interface.getEffectOnValue<MemoryEffects::Allocate>(res)) {
451 if (isa<SideEffects::AutomaticAllocationScopeResource>(
452 effect->getResource()))
476 bool hasPotentialAlloca =
489 if (hasPotentialAlloca) {
522 if (!lastParentWithoutScope ||
535 lastParentWithoutScope = lastParentWithoutScope->
getParentOp();
536 if (!lastParentWithoutScope ||
543 Region *containingRegion =
nullptr;
544 for (
auto &r : lastParentWithoutScope->
getRegions()) {
545 if (r.isAncestor(op->getParentRegion())) {
546 assert(containingRegion ==
nullptr &&
547 "only one region can contain the op");
548 containingRegion = &r;
551 assert(containingRegion &&
"op must be contained in a region");
561 return containingRegion->isAncestor(v.getParentRegion());
564 toHoist.push_back(alloc);
571 for (
auto *op : toHoist) {
572 auto *cloned = rewriter.
clone(*op);
573 rewriter.
replaceOp(op, cloned->getResults());
588LogicalResult AssumeAlignmentOp::verify() {
589 if (!llvm::isPowerOf2_32(getAlignment()))
590 return emitOpError(
"alignment must be power of 2");
594void AssumeAlignmentOp::getAsmResultNames(
596 setNameFn(getResult(),
"assume_align");
599OpFoldResult AssumeAlignmentOp::fold(FoldAdaptor adaptor) {
600 auto source = getMemref().getDefiningOp<AssumeAlignmentOp>();
603 if (source.getAlignment() != getAlignment())
608FailureOr<std::optional<SmallVector<Value>>>
609AssumeAlignmentOp::bubbleDownCasts(
OpBuilder &builder) {
613FailureOr<OpFoldResult> AssumeAlignmentOp::reifyDimOfResult(
OpBuilder &builder,
616 assert(resultIndex == 0 &&
"AssumeAlignmentOp has a single result");
617 return getMixedSize(builder, getLoc(), getMemref(), dim);
624LogicalResult DistinctObjectsOp::verify() {
625 if (getOperandTypes() != getResultTypes())
626 return emitOpError(
"operand types and result types must match");
628 if (getOperandTypes().empty())
629 return emitOpError(
"expected at least one operand");
634LogicalResult DistinctObjectsOp::inferReturnTypes(
639 llvm::copy(operands.
getTypes(), std::back_inserter(inferredReturnTypes));
648 setNameFn(getResult(),
"cast");
688bool CastOp::canFoldIntoConsumerOp(CastOp castOp) {
689 MemRefType sourceType =
690 llvm::dyn_cast<MemRefType>(castOp.getSource().getType());
691 MemRefType resultType = llvm::dyn_cast<MemRefType>(castOp.getType());
694 if (!sourceType || !resultType)
698 if (sourceType.getElementType() != resultType.getElementType())
702 if (sourceType.getRank() != resultType.getRank())
706 int64_t sourceOffset, resultOffset;
708 if (
failed(sourceType.getStridesAndOffset(sourceStrides, sourceOffset)) ||
709 failed(resultType.getStridesAndOffset(resultStrides, resultOffset)))
713 for (
auto it : llvm::zip(sourceType.getShape(), resultType.getShape())) {
714 auto ss = std::get<0>(it), st = std::get<1>(it);
716 if (ShapedType::isDynamic(ss) && ShapedType::isStatic(st))
721 if (sourceOffset != resultOffset)
722 if (ShapedType::isDynamic(sourceOffset) &&
723 ShapedType::isStatic(resultOffset))
727 for (
auto it : llvm::zip(sourceStrides, resultStrides)) {
728 auto ss = std::get<0>(it), st = std::get<1>(it);
730 if (ShapedType::isDynamic(ss) && ShapedType::isStatic(st))
738 if (inputs.size() != 1 || outputs.size() != 1)
740 if (inputs == outputs)
742 Type a = inputs.front(),
b = outputs.front();
743 auto aT = llvm::dyn_cast<MemRefType>(a);
744 auto bT = llvm::dyn_cast<MemRefType>(
b);
746 auto uaT = llvm::dyn_cast<UnrankedMemRefType>(a);
747 auto ubT = llvm::dyn_cast<UnrankedMemRefType>(
b);
750 if (aT.getElementType() != bT.getElementType())
752 if (aT.getLayout() != bT.getLayout()) {
755 if (
failed(aT.getStridesAndOffset(aStrides, aOffset)) ||
756 failed(bT.getStridesAndOffset(bStrides, bOffset)) ||
757 aStrides.size() != bStrides.size())
766 return (ShapedType::isDynamic(a) || ShapedType::isDynamic(
b) || a ==
b);
768 if (!checkCompatible(aOffset, bOffset))
771 if (aT.getDimSize(
index) == 1 || bT.getDimSize(
index) == 1)
773 if (!checkCompatible(aStride, bStrides[
index]))
777 if (aT.getMemorySpace() != bT.getMemorySpace())
781 if (aT.getRank() != bT.getRank())
784 for (
unsigned i = 0, e = aT.getRank(); i != e; ++i) {
785 int64_t aDim = aT.getDimSize(i), bDim = bT.getDimSize(i);
786 if (ShapedType::isStatic(aDim) && ShapedType::isStatic(bDim) &&
800 auto aEltType = (aT) ? aT.getElementType() : uaT.getElementType();
801 auto bEltType = (bT) ? bT.getElementType() : ubT.getElementType();
802 if (aEltType != bEltType)
805 auto aMemSpace = (aT) ? aT.getMemorySpace() : uaT.getMemorySpace();
806 auto bMemSpace = (bT) ? bT.getMemorySpace() : ubT.getMemorySpace();
807 return aMemSpace == bMemSpace;
817FailureOr<std::optional<SmallVector<Value>>>
818CastOp::bubbleDownCasts(
OpBuilder &builder) {
830 using OpRewritePattern<CopyOp>::OpRewritePattern;
832 LogicalResult matchAndRewrite(CopyOp copyOp,
833 PatternRewriter &rewriter)
const override {
834 if (copyOp.getSource() != copyOp.getTarget())
843 using OpRewritePattern<CopyOp>::OpRewritePattern;
845 static bool isEmptyMemRef(BaseMemRefType type) {
849 LogicalResult matchAndRewrite(CopyOp copyOp,
850 PatternRewriter &rewriter)
const override {
851 if (isEmptyMemRef(copyOp.getSource().getType()) ||
852 isEmptyMemRef(copyOp.getTarget().getType())) {
864 results.
add<FoldEmptyCopy, FoldSelfCopy>(context);
871 for (
OpOperand &operand : op->getOpOperands()) {
873 if (castOp && memref::CastOp::canFoldIntoConsumerOp(castOp)) {
874 operand.set(castOp.getOperand());
881LogicalResult CopyOp::fold(FoldAdaptor adaptor,
882 SmallVectorImpl<OpFoldResult> &results) {
892LogicalResult DeallocOp::fold(FoldAdaptor adaptor,
893 SmallVectorImpl<OpFoldResult> &results) {
902void DimOp::getAsmResultNames(
function_ref<
void(Value, StringRef)> setNameFn) {
903 setNameFn(getResult(),
"dim");
906void DimOp::build(OpBuilder &builder, OperationState &
result, Value source,
908 auto loc =
result.location;
910 build(builder,
result, source, indexValue);
913std::optional<int64_t> DimOp::getConstantIndex() {
922 auto rankedSourceType = dyn_cast<MemRefType>(getSource().
getType());
923 if (!rankedSourceType)
926 if (rankedSourceType.getRank() <= constantIndex)
932void DimOp::inferResultRangesFromOptional(ArrayRef<IntegerValueRange> argRanges,
934 setResultRange(getResult(),
943 std::map<int64_t, unsigned> numOccurences;
944 for (
auto val : vals)
945 numOccurences[val]++;
946 return numOccurences;
956static FailureOr<llvm::SmallBitVector>
958 MemRefType reducedType,
960 int64_t rankReduction = originalType.getRank() - reducedType.getRank();
961 if (rankReduction <= 0)
962 return llvm::SmallBitVector(originalType.getRank());
966 for (
const auto &it : llvm::enumerate(sizes)) {
968 sourceSizes[it.index()] = *cst;
970 sourceSizes[it.index()] = ShapedType::kDynamic;
974 llvm::SmallBitVector usedSourceDims(originalType.getRank());
976 for (
int64_t resultSize : resultSizes) {
977 bool matched =
false;
978 for (
int64_t j = startJ;
j < originalType.getRank(); ++
j) {
979 if (sourceSizes[
j] == resultSize) {
980 usedSourceDims.set(
j);
990 llvm::SmallBitVector unusedDims(originalType.getRank());
991 for (
int64_t i = 0; i < originalType.getRank(); ++i)
992 if (!usedSourceDims.test(i))
1005 MemRefType originalType, MemRefType reducedType,
1007 llvm::SmallBitVector unusedDims) {
1015 std::map<int64_t, unsigned> currUnaccountedStrides =
1017 std::map<int64_t, unsigned> candidateStridesNumOccurences =
1019 for (
size_t dim = 0, e = unusedDims.size(); dim != e; ++dim) {
1020 if (!unusedDims.test(dim))
1022 int64_t originalStride = originalStrides[dim];
1023 if (currUnaccountedStrides[originalStride] >
1024 candidateStridesNumOccurences[originalStride]) {
1026 currUnaccountedStrides[originalStride]--;
1029 if (currUnaccountedStrides[originalStride] ==
1030 candidateStridesNumOccurences[originalStride]) {
1032 unusedDims.reset(dim);
1035 if (currUnaccountedStrides[originalStride] <
1036 candidateStridesNumOccurences[originalStride]) {
1042 if (
static_cast<int64_t>(unusedDims.count()) + reducedType.getRank() !=
1043 originalType.getRank())
1055static FailureOr<llvm::SmallBitVector>
1058 llvm::SmallBitVector unusedDims(originalType.getRank());
1059 if (originalType.getRank() == reducedType.getRank())
1062 for (
const auto &dim : llvm::enumerate(sizes))
1063 if (
auto attr = llvm::dyn_cast_if_present<Attribute>(dim.value()))
1064 if (llvm::cast<IntegerAttr>(attr).getInt() == 1)
1065 unusedDims.set(dim.index());
1069 if (
static_cast<int64_t>(unusedDims.count()) + reducedType.getRank() ==
1070 originalType.getRank())
1074 int64_t originalOffset, candidateOffset;
1076 originalType.getStridesAndOffset(originalStrides, originalOffset)) ||
1078 reducedType.getStridesAndOffset(candidateStrides, candidateOffset)))
1086 if (strides.size() <= 1)
1088 return llvm::any_of(strides.drop_back(),
1089 [](
int64_t s) { return !ShapedType::isDynamic(s); });
1091 if (hasNonTrivialStaticStride(originalStrides) ||
1092 hasNonTrivialStaticStride(candidateStrides)) {
1093 FailureOr<llvm::SmallBitVector> strideBased =
1096 candidateStrides, unusedDims);
1097 if (succeeded(strideBased))
1098 return *strideBased;
1104llvm::SmallBitVector SubViewOp::getDroppedDims() {
1105 MemRefType sourceType = getSourceType();
1106 MemRefType resultType =
getType();
1107 FailureOr<llvm::SmallBitVector> unusedDims =
1109 assert(succeeded(unusedDims) &&
"unable to find unused dims of subview");
1113OpFoldResult DimOp::fold(FoldAdaptor adaptor) {
1115 std::optional<int64_t> index = getConstantIndex();
1120 auto memrefType = llvm::dyn_cast<MemRefType>(getSource().
getType());
1126 int64_t indexVal = index.value();
1127 if (indexVal < 0 || indexVal >= memrefType.getRank())
1131 if (!memrefType.isDynamicDim(indexVal)) {
1133 return builder.
getIndexAttr(memrefType.getShape()[indexVal]);
1138 Operation *definingOp = getSource().getDefiningOp();
1140 if (
auto alloc = dyn_cast_or_null<AllocOp>(definingOp))
1141 return *(alloc.getDynamicSizes().begin() +
1142 memrefType.getDynamicDimIndex(indexVal));
1144 if (
auto alloca = dyn_cast_or_null<AllocaOp>(definingOp))
1145 return *(alloca.getDynamicSizes().begin() +
1146 memrefType.getDynamicDimIndex(indexVal));
1148 if (
auto view = dyn_cast_or_null<ViewOp>(definingOp))
1149 return *(view.getDynamicSizes().begin() +
1150 memrefType.getDynamicDimIndex(indexVal));
1152 if (
auto subview = dyn_cast_or_null<SubViewOp>(definingOp)) {
1157 unsigned dynamicResultDimIdx = memrefType.getDynamicDimIndex(indexVal);
1158 unsigned dynamicIdx = 0;
1159 for (OpFoldResult size : subview.getMixedSizes()) {
1160 if (llvm::isa<Attribute>(size))
1162 if (dynamicIdx == dynamicResultDimIdx)
1179struct DimOfMemRefReshape :
public OpRewritePattern<DimOp> {
1180 using OpRewritePattern<DimOp>::OpRewritePattern;
1182 LogicalResult matchAndRewrite(DimOp dim,
1183 PatternRewriter &rewriter)
const override {
1184 auto reshape = dim.getSource().getDefiningOp<ReshapeOp>();
1188 dim,
"Dim op is not defined by a reshape op.");
1199 if (dim.getIndex().getParentBlock() == reshape->getBlock()) {
1200 if (
auto *definingOp = dim.getIndex().getDefiningOp()) {
1201 if (reshape->isBeforeInBlock(definingOp)) {
1204 "dim.getIndex is not defined before reshape in the same block.");
1209 else if (dim->getBlock() != reshape->getBlock() &&
1210 !dim.getIndex().getParentRegion()->isProperAncestor(
1211 reshape->getParentRegion())) {
1216 dim,
"dim.getIndex does not dominate reshape.");
1222 Location loc = dim.getLoc();
1224 LoadOp::create(rewriter, loc, reshape.getShape(), dim.getIndex());
1225 if (
load.getType() != dim.getType())
1226 load = arith::IndexCastOp::create(rewriter, loc, dim.getType(),
load);
1234void DimOp::getCanonicalizationPatterns(RewritePatternSet &results,
1235 MLIRContext *context) {
1236 results.
add<DimOfMemRefReshape>(context);
1243void DmaStartOp::build(OpBuilder &builder, OperationState &
result,
1244 Value srcMemRef,
ValueRange srcIndices, Value destMemRef,
1246 Value tagMemRef,
ValueRange tagIndices, Value stride,
1247 Value elementsPerStride) {
1248 result.addOperands(srcMemRef);
1249 result.addOperands(srcIndices);
1250 result.addOperands(destMemRef);
1251 result.addOperands(destIndices);
1252 result.addOperands({numElements, tagMemRef});
1253 result.addOperands(tagIndices);
1255 result.addOperands({stride, elementsPerStride});
1258void DmaStartOp::print(OpAsmPrinter &p) {
1259 p <<
" " << getSrcMemRef() <<
'[' << getSrcIndices() <<
"], "
1260 << getDstMemRef() <<
'[' << getDstIndices() <<
"], " <<
getNumElements()
1261 <<
", " << getTagMemRef() <<
'[' << getTagIndices() <<
']';
1263 p <<
", " << getStride() <<
", " << getNumElementsPerStride();
1266 p <<
" : " << getSrcMemRef().getType() <<
", " << getDstMemRef().getType()
1267 <<
", " << getTagMemRef().getType();
1278ParseResult DmaStartOp::parse(OpAsmParser &parser, OperationState &
result) {
1279 OpAsmParser::UnresolvedOperand srcMemRefInfo;
1280 SmallVector<OpAsmParser::UnresolvedOperand, 4> srcIndexInfos;
1281 OpAsmParser::UnresolvedOperand dstMemRefInfo;
1282 SmallVector<OpAsmParser::UnresolvedOperand, 4> dstIndexInfos;
1283 OpAsmParser::UnresolvedOperand numElementsInfo;
1284 OpAsmParser::UnresolvedOperand tagMemrefInfo;
1285 SmallVector<OpAsmParser::UnresolvedOperand, 4> tagIndexInfos;
1286 SmallVector<OpAsmParser::UnresolvedOperand, 2> strideInfo;
1288 SmallVector<Type, 3> types;
1308 bool isStrided = strideInfo.size() == 2;
1309 if (!strideInfo.empty() && !isStrided) {
1311 "expected two stride related operands");
1316 if (types.size() != 3)
1338LogicalResult DmaStartOp::verify() {
1343 if (numOperands < 4)
1344 return emitOpError(
"expected at least 4 operands");
1349 if (!llvm::isa<MemRefType>(getSrcMemRef().
getType()))
1350 return emitOpError(
"expected source to be of memref type");
1351 if (numOperands < getSrcMemRefRank() + 4)
1352 return emitOpError() <<
"expected at least " << getSrcMemRefRank() + 4
1354 if (!getSrcIndices().empty() &&
1355 !llvm::all_of(getSrcIndices().getTypes(),
1356 [](Type t) {
return t.
isIndex(); }))
1357 return emitOpError(
"expected source indices to be of index type");
1360 if (!llvm::isa<MemRefType>(getDstMemRef().
getType()))
1361 return emitOpError(
"expected destination to be of memref type");
1362 unsigned numExpectedOperands = getSrcMemRefRank() + getDstMemRefRank() + 4;
1363 if (numOperands < numExpectedOperands)
1364 return emitOpError() <<
"expected at least " << numExpectedOperands
1366 if (!getDstIndices().empty() &&
1367 !llvm::all_of(getDstIndices().getTypes(),
1368 [](Type t) {
return t.
isIndex(); }))
1369 return emitOpError(
"expected destination indices to be of index type");
1373 return emitOpError(
"expected num elements to be of index type");
1376 if (!llvm::isa<MemRefType>(getTagMemRef().
getType()))
1377 return emitOpError(
"expected tag to be of memref type");
1378 numExpectedOperands += getTagMemRefRank();
1379 if (numOperands < numExpectedOperands)
1380 return emitOpError() <<
"expected at least " << numExpectedOperands
1382 if (!getTagIndices().empty() &&
1383 !llvm::all_of(getTagIndices().getTypes(),
1384 [](Type t) {
return t.
isIndex(); }))
1385 return emitOpError(
"expected tag indices to be of index type");
1389 if (numOperands != numExpectedOperands &&
1390 numOperands != numExpectedOperands + 2)
1391 return emitOpError(
"incorrect number of operands");
1395 if (!getStride().
getType().isIndex() ||
1396 !getNumElementsPerStride().
getType().isIndex())
1398 "expected stride and num elements per stride to be of type index");
1404LogicalResult DmaStartOp::fold(FoldAdaptor adaptor,
1405 SmallVectorImpl<OpFoldResult> &results) {
1410void DmaStartOp::setMemrefsAndIndices(RewriterBase &rewriter, Value newSrc,
1414 SmallVector<Value> newOperands;
1415 newOperands.push_back(newSrc);
1416 llvm::append_range(newOperands, newSrcIndices);
1417 newOperands.push_back(newDst);
1418 llvm::append_range(newOperands, newDstIndices);
1420 newOperands.push_back(getTagMemRef());
1421 llvm::append_range(newOperands, getTagIndices());
1423 newOperands.push_back(getStride());
1424 newOperands.push_back(getNumElementsPerStride());
1427 rewriter.
modifyOpInPlace(*
this, [&]() { (*this)->setOperands(newOperands); });
1434LogicalResult DmaWaitOp::fold(FoldAdaptor adaptor,
1435 SmallVectorImpl<OpFoldResult> &results) {
1440LogicalResult DmaWaitOp::verify() {
1442 unsigned numTagIndices = getTagIndices().size();
1443 unsigned tagMemRefRank = getTagMemRefRank();
1444 if (numTagIndices != tagMemRefRank)
1445 return emitOpError() <<
"expected tagIndices to have the same number of "
1446 "elements as the tagMemRef rank, expected "
1447 << tagMemRefRank <<
", but got " << numTagIndices;
1455void ExtractAlignedPointerAsIndexOp::getAsmResultNames(
1457 setNameFn(getResult(),
"intptr");
1466LogicalResult ExtractStridedMetadataOp::inferReturnTypes(
1467 MLIRContext *context, std::optional<Location> location,
1468 ExtractStridedMetadataOp::Adaptor adaptor,
1469 SmallVectorImpl<Type> &inferredReturnTypes) {
1470 auto sourceType = llvm::dyn_cast<MemRefType>(adaptor.getSource().getType());
1474 unsigned sourceRank = sourceType.getRank();
1475 IndexType indexType = IndexType::get(context);
1477 MemRefType::get({}, sourceType.getElementType(),
1478 MemRefLayoutAttrInterface{}, sourceType.getMemorySpace());
1480 inferredReturnTypes.push_back(memrefType);
1482 inferredReturnTypes.push_back(indexType);
1484 for (
unsigned i = 0; i < sourceRank * 2; ++i)
1485 inferredReturnTypes.push_back(indexType);
1489void ExtractStridedMetadataOp::getAsmResultNames(
1491 setNameFn(getBaseBuffer(),
"base_buffer");
1492 setNameFn(getOffset(),
"offset");
1495 if (!getSizes().empty()) {
1496 setNameFn(getSizes().front(),
"sizes");
1497 setNameFn(getStrides().front(),
"strides");
1504template <
typename Container>
1508 assert(values.size() == maybeConstants.size() &&
1509 " expected values and maybeConstants of the same size");
1510 bool atLeastOneReplacement =
false;
1511 for (
auto [maybeConstant,
result] : llvm::zip(maybeConstants, values)) {
1516 assert(isa<Attribute>(maybeConstant) &&
1517 "The constified value should be either unchanged (i.e., == result) "
1521 llvm::cast<IntegerAttr>(cast<Attribute>(maybeConstant)).getInt());
1526 atLeastOneReplacement =
true;
1529 return atLeastOneReplacement;
1533ExtractStridedMetadataOp::fold(FoldAdaptor adaptor,
1534 SmallVectorImpl<OpFoldResult> &results) {
1535 OpBuilder builder(*
this);
1539 getConstifiedMixedOffset());
1541 getConstifiedMixedSizes());
1543 builder, getLoc(), getStrides(), getConstifiedMixedStrides());
1546 if (
auto prev = getSource().getDefiningOp<CastOp>())
1547 if (isa<MemRefType>(prev.getSource().getType())) {
1548 getSourceMutable().assign(prev.getSource());
1549 atLeastOneReplacement =
true;
1552 return success(atLeastOneReplacement);
1555SmallVector<OpFoldResult> ExtractStridedMetadataOp::getConstifiedMixedSizes() {
1561SmallVector<OpFoldResult>
1562ExtractStridedMetadataOp::getConstifiedMixedStrides() {
1564 SmallVector<int64_t> staticValues;
1566 LogicalResult status =
1567 getSource().getType().getStridesAndOffset(staticValues, unused);
1569 assert(succeeded(status) &&
"could not get strides from type");
1574OpFoldResult ExtractStridedMetadataOp::getConstifiedMixedOffset() {
1576 SmallVector<OpFoldResult> values(1, offsetOfr);
1577 SmallVector<int64_t> staticValues, unused;
1579 LogicalResult status =
1580 getSource().getType().getStridesAndOffset(unused, offset);
1582 assert(succeeded(status) &&
"could not get offset from type");
1583 staticValues.push_back(offset);
1592void GenericAtomicRMWOp::build(OpBuilder &builder, OperationState &
result,
1594 OpBuilder::InsertionGuard g(builder);
1595 result.addOperands(memref);
1598 if (
auto memrefType = llvm::dyn_cast<MemRefType>(memref.
getType())) {
1599 Type elementType = memrefType.getElementType();
1600 result.addTypes(elementType);
1602 Region *bodyRegion =
result.addRegion();
1608LogicalResult GenericAtomicRMWOp::verify() {
1609 auto &body = getRegion();
1610 if (body.getNumArguments() != 1)
1611 return emitOpError(
"expected single number of entry block arguments");
1613 if (getResult().
getType() != body.getArgument(0).getType())
1614 return emitOpError(
"expected block argument of the same type result type");
1617 body.walk([&](Operation *nestedOp) {
1621 "body of 'memref.generic_atomic_rmw' should contain "
1622 "only operations with no side effects");
1629ParseResult GenericAtomicRMWOp::parse(OpAsmParser &parser,
1630 OperationState &
result) {
1631 OpAsmParser::UnresolvedOperand memref;
1633 SmallVector<OpAsmParser::UnresolvedOperand, 4> ivs;
1643 Region *body =
result.addRegion();
1651void GenericAtomicRMWOp::print(OpAsmPrinter &p) {
1652 p <<
' ' << getMemref() <<
"[" <<
getIndices()
1653 <<
"] : " << getMemref().
getType() <<
' ';
1662std::optional<SmallVector<Value>> GenericAtomicRMWOp::updateMemrefAndIndices(
1663 RewriterBase &rewriter, Value newMemref,
ValueRange newIndices) {
1665 getMemrefMutable().assign(newMemref);
1666 getIndicesMutable().assign(newIndices);
1668 return std::nullopt;
1675LogicalResult AtomicYieldOp::verify() {
1676 Type parentType = (*this)->getParentOp()->getResultTypes().front();
1677 Type resultType = getResult().getType();
1678 if (parentType != resultType)
1679 return emitOpError() <<
"types mismatch between yield op: " << resultType
1680 <<
" and its parent: " << parentType;
1692 if (!op.isExternal()) {
1694 if (op.isUninitialized())
1695 p <<
"uninitialized";
1708 auto memrefType = llvm::dyn_cast<MemRefType>(type);
1709 if (!memrefType || !memrefType.hasStaticShape())
1711 <<
"type should be static shaped memref, but got " << type;
1712 typeAttr = TypeAttr::get(type);
1718 initialValue = UnitAttr::get(parser.
getContext());
1725 if (!llvm::isa<ElementsAttr>(initialValue))
1727 <<
"initial value should be a unit or elements attribute";
1731LogicalResult GlobalOp::verify() {
1732 auto memrefType = llvm::dyn_cast<MemRefType>(
getType());
1733 if (!memrefType || !memrefType.hasStaticShape())
1734 return emitOpError(
"type should be static shaped memref, but got ")
1739 if (getInitialValue().has_value()) {
1740 Attribute initValue = getInitialValue().value();
1741 if (!llvm::isa<UnitAttr>(initValue) && !llvm::isa<ElementsAttr>(initValue))
1742 return emitOpError(
"initial value should be a unit or elements "
1743 "attribute, but got ")
1748 if (
auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) {
1750 auto initElementType =
1751 cast<TensorType>(elementsAttr.getType()).getElementType();
1752 auto memrefElementType = memrefType.getElementType();
1754 if (initElementType != memrefElementType)
1755 return emitOpError(
"initial value element expected to be of type ")
1756 << memrefElementType <<
", but was of type " << initElementType;
1761 auto initShape = elementsAttr.getShapedType().getShape();
1762 auto memrefShape = memrefType.getShape();
1763 if (initShape != memrefShape)
1764 return emitOpError(
"initial value shape expected to be ")
1765 << memrefShape <<
" but was " << initShape;
1773ElementsAttr GlobalOp::getConstantInitValue() {
1774 auto initVal = getInitialValue();
1775 if (getConstant() && initVal.has_value())
1776 return llvm::cast<ElementsAttr>(initVal.value());
1785GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1791 return emitOpError(
"'")
1792 << getName() <<
"' does not reference a valid global memref";
1794 Type resultType = getResult().getType();
1795 if (global.getType() != resultType)
1796 return emitOpError(
"result type ")
1797 << resultType <<
" does not match type " << global.getType()
1798 <<
" of the global memref @" << getName();
1810 result = dyn_cast<BoolAttr>(attr);
1813 "expected boolean attribute");
1821OpFoldResult LoadOp::fold(FoldAdaptor adaptor) {
1827 auto getGlobalOp = getMemref().getDefiningOp<memref::GetGlobalOp>();
1833 getGlobalOp, getGlobalOp.getNameAttr());
1838 dyn_cast_or_null<SplatElementsAttr>(global.getConstantInitValue());
1842 return splatAttr.getSplatValue<Attribute>();
1847std::optional<SmallVector<Value>>
1848LoadOp::updateMemrefAndIndices(RewriterBase &rewriter, Value newMemref,
1851 getMemrefMutable().assign(newMemref);
1852 getIndicesMutable().assign(newIndices);
1854 return std::nullopt;
1857FailureOr<std::optional<SmallVector<Value>>>
1858LoadOp::bubbleDownCasts(OpBuilder &builder) {
1867void MemorySpaceCastOp::getAsmResultNames(
1869 setNameFn(getResult(),
"memspacecast");
1873 if (inputs.size() != 1 || outputs.size() != 1)
1875 Type a = inputs.front(),
b = outputs.front();
1876 auto aT = llvm::dyn_cast<MemRefType>(a);
1877 auto bT = llvm::dyn_cast<MemRefType>(
b);
1879 auto uaT = llvm::dyn_cast<UnrankedMemRefType>(a);
1880 auto ubT = llvm::dyn_cast<UnrankedMemRefType>(
b);
1883 if (aT.getElementType() != bT.getElementType())
1885 if (aT.getLayout() != bT.getLayout())
1887 if (aT.getShape() != bT.getShape())
1892 return uaT.getElementType() == ubT.getElementType();
1897OpFoldResult MemorySpaceCastOp::fold(FoldAdaptor adaptor) {
1900 if (
auto parentCast = getSource().getDefiningOp<MemorySpaceCastOp>()) {
1901 getSourceMutable().assign(parentCast.getSource());
1915bool MemorySpaceCastOp::isValidMemorySpaceCast(PtrLikeTypeInterface tgt,
1916 PtrLikeTypeInterface src) {
1917 return isa<BaseMemRefType>(tgt) &&
1918 tgt.clonePtrWith(src.getMemorySpace(), std::nullopt) == src;
1921MemorySpaceCastOpInterface MemorySpaceCastOp::cloneMemorySpaceCastOp(
1922 OpBuilder &
b, PtrLikeTypeInterface tgt,
1924 assert(isValidMemorySpaceCast(tgt, src.getType()) &&
"invalid arguments");
1925 return MemorySpaceCastOp::create(
b, getLoc(), tgt, src);
1929bool MemorySpaceCastOp::isSourcePromotable() {
1930 return getDest().getType().getMemorySpace() ==
nullptr;
1937void PrefetchOp::print(OpAsmPrinter &p) {
1938 p <<
" " << getMemref() <<
'[';
1940 p <<
']' <<
", " << (getIsWrite() ?
"write" :
"read");
1941 p <<
", locality<" << getLocalityHint();
1942 p <<
">, " << (getIsDataCache() ?
"data" :
"instr");
1944 (*this)->getDiscardableAttrDictionary(),
1945 {
"localityHint",
"isWrite",
"isDataCache"});
1949ParseResult PrefetchOp::parse(OpAsmParser &parser, OperationState &
result) {
1950 OpAsmParser::UnresolvedOperand memrefInfo;
1951 SmallVector<OpAsmParser::UnresolvedOperand, 4> indexInfo;
1952 IntegerAttr localityHint;
1954 StringRef readOrWrite, cacheType;
1971 if (readOrWrite !=
"read" && readOrWrite !=
"write")
1973 "rw specifier has to be 'read' or 'write'");
1974 result.addAttribute(PrefetchOp::getIsWriteAttrStrName(),
1977 if (cacheType !=
"data" && cacheType !=
"instr")
1979 "cache type has to be 'data' or 'instr'");
1981 result.addAttribute(PrefetchOp::getIsDataCacheAttrStrName(),
1987LogicalResult PrefetchOp::verify() {
1989 return emitOpError(
"too few indices");
1994LogicalResult PrefetchOp::fold(FoldAdaptor adaptor,
1995 SmallVectorImpl<OpFoldResult> &results) {
2002std::optional<SmallVector<Value>>
2003PrefetchOp::updateMemrefAndIndices(RewriterBase &rewriter, Value newMemref,
2006 getMemrefMutable().assign(newMemref);
2007 getIndicesMutable().assign(newIndices);
2009 return std::nullopt;
2016OpFoldResult RankOp::fold(FoldAdaptor adaptor) {
2018 auto type = getOperand().getType();
2019 auto shapedType = llvm::dyn_cast<ShapedType>(type);
2020 if (shapedType && shapedType.hasRank())
2021 return IntegerAttr::get(IndexType::get(
getContext()), shapedType.getRank());
2022 return IntegerAttr();
2029void ReinterpretCastOp::getAsmResultNames(
2031 setNameFn(getResult(),
"reinterpret_cast");
2037void ReinterpretCastOp::build(OpBuilder &
b, OperationState &
result,
2038 MemRefType resultType, Value source,
2039 OpFoldResult offset, ArrayRef<OpFoldResult> sizes,
2040 ArrayRef<OpFoldResult> strides,
2041 ArrayRef<NamedAttribute> attrs) {
2042 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
2043 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
2047 result.addAttributes(attrs);
2048 build(
b,
result, resultType, source, dynamicOffsets, dynamicSizes,
2049 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
2050 b.getDenseI64ArrayAttr(staticSizes),
2051 b.getDenseI64ArrayAttr(staticStrides));
2054void ReinterpretCastOp::build(OpBuilder &
b, OperationState &
result,
2055 Value source, OpFoldResult offset,
2056 ArrayRef<OpFoldResult> sizes,
2057 ArrayRef<OpFoldResult> strides,
2058 ArrayRef<NamedAttribute> attrs) {
2059 auto sourceType = cast<BaseMemRefType>(source.
getType());
2060 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
2061 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
2065 auto stridedLayout = StridedLayoutAttr::get(
2066 b.getContext(), staticOffsets.front(), staticStrides);
2067 auto resultType = MemRefType::get(staticSizes, sourceType.getElementType(),
2068 stridedLayout, sourceType.getMemorySpace());
2069 build(
b,
result, resultType, source, offset, sizes, strides, attrs);
2072void ReinterpretCastOp::build(OpBuilder &
b, OperationState &
result,
2073 MemRefType resultType, Value source,
2074 int64_t offset, ArrayRef<int64_t> sizes,
2075 ArrayRef<int64_t> strides,
2076 ArrayRef<NamedAttribute> attrs) {
2077 SmallVector<OpFoldResult> sizeValues = llvm::map_to_vector<4>(
2078 sizes, [&](int64_t v) -> OpFoldResult {
return b.getI64IntegerAttr(v); });
2079 SmallVector<OpFoldResult> strideValues =
2080 llvm::map_to_vector<4>(strides, [&](int64_t v) -> OpFoldResult {
2081 return b.getI64IntegerAttr(v);
2083 build(
b,
result, resultType, source,
b.getI64IntegerAttr(offset), sizeValues,
2084 strideValues, attrs);
2087void ReinterpretCastOp::build(OpBuilder &
b, OperationState &
result,
2088 MemRefType resultType, Value source, Value offset,
2090 ArrayRef<NamedAttribute> attrs) {
2091 SmallVector<OpFoldResult> sizeValues =
2092 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
2093 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
2094 strides, [](Value v) -> OpFoldResult {
return v; });
2095 build(
b,
result, resultType, source, offset, sizeValues, strideValues, attrs);
2100LogicalResult ReinterpretCastOp::verify() {
2102 auto srcType = llvm::cast<BaseMemRefType>(getSource().
getType());
2103 auto resultType = llvm::cast<MemRefType>(
getType());
2104 if (srcType.getMemorySpace() != resultType.getMemorySpace())
2105 return emitError(
"different memory spaces specified for source type ")
2106 << srcType <<
" and result memref type " << resultType;
2112 for (
auto [idx, resultSize, expectedSize] :
2113 llvm::enumerate(resultType.getShape(), getStaticSizes())) {
2114 if (ShapedType::isStatic(resultSize) && resultSize != expectedSize)
2115 return emitError(
"expected result type with size = ")
2116 << (ShapedType::isDynamic(expectedSize)
2117 ? std::string(
"dynamic")
2118 : std::to_string(expectedSize))
2119 <<
" instead of " << resultSize <<
" in dim = " << idx;
2125 int64_t resultOffset;
2126 SmallVector<int64_t, 4> resultStrides;
2127 if (
failed(resultType.getStridesAndOffset(resultStrides, resultOffset)))
2128 return emitError(
"expected result type to have strided layout but found ")
2132 int64_t expectedOffset = getStaticOffsets().front();
2133 if (ShapedType::isStatic(resultOffset) && resultOffset != expectedOffset)
2134 return emitError(
"expected result type with offset = ")
2135 << (ShapedType::isDynamic(expectedOffset)
2136 ? std::string(
"dynamic")
2137 : std::to_string(expectedOffset))
2138 <<
" instead of " << resultOffset;
2141 for (
auto [idx, resultStride, expectedStride] :
2142 llvm::enumerate(resultStrides, getStaticStrides())) {
2143 if (ShapedType::isStatic(resultStride) && resultStride != expectedStride)
2144 return emitError(
"expected result type with stride = ")
2145 << (ShapedType::isDynamic(expectedStride)
2146 ? std::string(
"dynamic")
2147 : std::to_string(expectedStride))
2148 <<
" instead of " << resultStride <<
" in dim = " << idx;
2154OpFoldResult ReinterpretCastOp::fold(FoldAdaptor ) {
2155 Value src = getSource();
2156 auto getPrevSrc = [&]() -> Value {
2159 return prev.getSource();
2163 return prev.getSource();
2169 return prev.getSource();
2174 if (
auto prevSrc = getPrevSrc()) {
2175 getSourceMutable().assign(prevSrc);
2188SmallVector<OpFoldResult> ReinterpretCastOp::getConstifiedMixedSizes() {
2194SmallVector<OpFoldResult> ReinterpretCastOp::getConstifiedMixedStrides() {
2195 SmallVector<OpFoldResult> values = getMixedStrides();
2196 SmallVector<int64_t> staticValues;
2198 LogicalResult status =
getType().getStridesAndOffset(staticValues, unused);
2200 assert(succeeded(status) &&
"could not get strides from type");
2205OpFoldResult ReinterpretCastOp::getConstifiedMixedOffset() {
2206 SmallVector<OpFoldResult> values = getMixedOffsets();
2207 assert(values.size() == 1 &&
2208 "reinterpret_cast must have one and only one offset");
2209 SmallVector<int64_t> staticValues, unused;
2211 LogicalResult status =
getType().getStridesAndOffset(unused, offset);
2213 assert(succeeded(status) &&
"could not get offset from type");
2214 staticValues.push_back(offset);
2262struct ReinterpretCastOpExtractStridedMetadataFolder
2263 :
public OpRewritePattern<ReinterpretCastOp> {
2265 using OpRewritePattern<ReinterpretCastOp>::OpRewritePattern;
2267 LogicalResult matchAndRewrite(ReinterpretCastOp op,
2268 PatternRewriter &rewriter)
const override {
2269 auto extractStridedMetadata =
2270 op.getSource().getDefiningOp<ExtractStridedMetadataOp>();
2271 if (!extractStridedMetadata)
2276 auto isReinterpretCastNoop = [&]() ->
bool {
2278 if (!llvm::equal(extractStridedMetadata.getConstifiedMixedStrides(),
2279 op.getConstifiedMixedStrides()))
2283 if (!llvm::equal(extractStridedMetadata.getConstifiedMixedSizes(),
2284 op.getConstifiedMixedSizes()))
2288 assert(op.getMixedOffsets().size() == 1 &&
2289 "reinterpret_cast with more than one offset should have been "
2290 "rejected by the verifier");
2291 return extractStridedMetadata.getConstifiedMixedOffset() ==
2292 op.getConstifiedMixedOffset();
2295 if (!isReinterpretCastNoop()) {
2312 op.getSourceMutable().assign(extractStridedMetadata.getSource());
2322 Type srcTy = extractStridedMetadata.getSource().getType();
2323 if (srcTy == op.getResult().getType())
2324 rewriter.
replaceOp(op, extractStridedMetadata.getSource());
2327 extractStridedMetadata.getSource());
2333struct ReinterpretCastOpConstantFolder
2334 :
public OpRewritePattern<ReinterpretCastOp> {
2336 using OpRewritePattern<ReinterpretCastOp>::OpRewritePattern;
2338 LogicalResult matchAndRewrite(ReinterpretCastOp op,
2339 PatternRewriter &rewriter)
const override {
2340 unsigned srcStaticCount = llvm::count_if(
2341 llvm::concat<OpFoldResult>(op.getMixedOffsets(), op.getMixedSizes(),
2342 op.getMixedStrides()),
2343 [](OpFoldResult ofr) { return isa<Attribute>(ofr); });
2345 SmallVector<OpFoldResult> offsets = {op.getConstifiedMixedOffset()};
2346 SmallVector<OpFoldResult> sizes = op.getConstifiedMixedSizes();
2347 SmallVector<OpFoldResult> strides = op.getConstifiedMixedStrides();
2354 offsets[0] = op.getMixedOffsets()[0];
2359 for (
auto it : llvm::zip(op.getMixedSizes(), sizes)) {
2360 auto &srcSizeOfr = std::get<0>(it);
2361 auto &sizeOfr = std::get<1>(it);
2364 sizeOfr = srcSizeOfr;
2371 if (srcStaticCount ==
2372 llvm::count_if(llvm::concat<OpFoldResult>(offsets, sizes, strides),
2373 [](OpFoldResult ofr) {
return isa<Attribute>(ofr); }))
2376 auto newReinterpretCast = ReinterpretCastOp::create(
2377 rewriter, op->getLoc(), op.getSource(), offsets[0], sizes, strides);
2385void ReinterpretCastOp::getCanonicalizationPatterns(RewritePatternSet &results,
2386 MLIRContext *context) {
2387 results.
add<ReinterpretCastOpExtractStridedMetadataFolder,
2388 ReinterpretCastOpConstantFolder>(context);
2391FailureOr<std::optional<SmallVector<Value>>>
2392ReinterpretCastOp::bubbleDownCasts(OpBuilder &builder) {
2400void CollapseShapeOp::getAsmResultNames(
2402 setNameFn(getResult(),
"collapse_shape");
2405void ExpandShapeOp::getAsmResultNames(
2407 setNameFn(getResult(),
"expand_shape");
2410LogicalResult ExpandShapeOp::reifyResultShapes(
2412 reifiedResultShapes = {
2413 getMixedValues(getStaticOutputShape(), getOutputShape(), builder)};
2426 bool allowMultipleDynamicDimsPerGroup) {
2428 if (collapsedShape.size() != reassociation.size())
2429 return op->
emitOpError(
"invalid number of reassociation groups: found ")
2430 << reassociation.size() <<
", expected " << collapsedShape.size();
2435 for (
const auto &it : llvm::enumerate(reassociation)) {
2437 int64_t collapsedDim = it.index();
2439 bool foundDynamic =
false;
2440 for (
int64_t expandedDim : group) {
2441 if (expandedDim != nextDim++)
2442 return op->
emitOpError(
"reassociation indices must be contiguous");
2444 if (expandedDim >=
static_cast<int64_t>(expandedShape.size()))
2446 << expandedDim <<
" is out of bounds";
2449 if (ShapedType::isDynamic(expandedShape[expandedDim])) {
2450 if (foundDynamic && !allowMultipleDynamicDimsPerGroup)
2452 "at most one dimension in a reassociation group may be dynamic");
2453 foundDynamic =
true;
2458 if (ShapedType::isDynamic(collapsedShape[collapsedDim]) != foundDynamic)
2461 <<
") must be dynamic if and only if reassociation group is "
2466 if (!foundDynamic) {
2468 for (
int64_t expandedDim : group)
2469 groupSize *= expandedShape[expandedDim];
2470 if (groupSize != collapsedShape[collapsedDim])
2472 << collapsedShape[collapsedDim]
2473 <<
") must equal reassociation group size (" << groupSize <<
")";
2477 if (collapsedShape.empty()) {
2479 for (
int64_t d : expandedShape)
2482 "rank 0 memrefs can only be extended/collapsed with/from ones");
2483 }
else if (nextDim !=
static_cast<int64_t>(expandedShape.size())) {
2487 << expandedShape.size()
2488 <<
") inconsistent with number of reassociation indices (" << nextDim
2495SmallVector<AffineMap, 4> CollapseShapeOp::getReassociationMaps() {
2499SmallVector<ReassociationExprs, 4> CollapseShapeOp::getReassociationExprs() {
2501 getReassociationIndices());
2504SmallVector<AffineMap, 4> ExpandShapeOp::getReassociationMaps() {
2508SmallVector<ReassociationExprs, 4> ExpandShapeOp::getReassociationExprs() {
2510 getReassociationIndices());
2515static FailureOr<StridedLayoutAttr>
2520 if (failed(srcType.getStridesAndOffset(srcStrides, srcOffset)))
2522 assert(srcStrides.size() == reassociation.size() &&
"invalid reassociation");
2537 reverseResultStrides.reserve(resultShape.size());
2538 unsigned shapeIndex = resultShape.size() - 1;
2539 for (
auto it : llvm::reverse(llvm::zip(reassociation, srcStrides))) {
2541 int64_t currentStrideToExpand = std::get<1>(it);
2542 for (
unsigned idx = 0, e = reassoc.size(); idx < e; ++idx) {
2543 reverseResultStrides.push_back(currentStrideToExpand);
2544 currentStrideToExpand =
2550 auto resultStrides = llvm::to_vector<8>(llvm::reverse(reverseResultStrides));
2551 resultStrides.resize(resultShape.size(), 1);
2552 return StridedLayoutAttr::get(srcType.getContext(), srcOffset, resultStrides);
2555FailureOr<MemRefType> ExpandShapeOp::computeExpandedType(
2556 MemRefType srcType, ArrayRef<int64_t> resultShape,
2557 ArrayRef<ReassociationIndices> reassociation) {
2558 if (srcType.getLayout().isIdentity()) {
2561 MemRefLayoutAttrInterface layout;
2562 return MemRefType::get(resultShape, srcType.getElementType(), layout,
2563 srcType.getMemorySpace());
2567 FailureOr<StridedLayoutAttr> computedLayout =
2569 if (
failed(computedLayout))
2571 return MemRefType::get(resultShape, srcType.getElementType(), *computedLayout,
2572 srcType.getMemorySpace());
2575FailureOr<SmallVector<OpFoldResult>>
2576ExpandShapeOp::inferOutputShape(OpBuilder &
b, Location loc,
2577 MemRefType expandedType,
2578 ArrayRef<ReassociationIndices> reassociation,
2579 ArrayRef<OpFoldResult> inputShape) {
2580 std::optional<SmallVector<OpFoldResult>> outputShape =
2585 return *outputShape;
2588void ExpandShapeOp::build(OpBuilder &builder, OperationState &
result,
2589 Type resultType, Value src,
2590 ArrayRef<ReassociationIndices> reassociation,
2591 ArrayRef<OpFoldResult> outputShape) {
2592 auto [staticOutputShape, dynamicOutputShape] =
2594 build(builder,
result, llvm::cast<MemRefType>(resultType), src,
2596 dynamicOutputShape, staticOutputShape);
2599void ExpandShapeOp::build(OpBuilder &builder, OperationState &
result,
2600 Type resultType, Value src,
2601 ArrayRef<ReassociationIndices> reassociation) {
2602 SmallVector<OpFoldResult> inputShape =
2604 MemRefType memrefResultTy = llvm::cast<MemRefType>(resultType);
2605 FailureOr<SmallVector<OpFoldResult>> outputShape = inferOutputShape(
2606 builder,
result.location, memrefResultTy, reassociation, inputShape);
2609 assert(succeeded(outputShape) &&
"unable to infer output shape");
2610 build(builder,
result, memrefResultTy, src, reassociation, *outputShape);
2613void ExpandShapeOp::build(OpBuilder &builder, OperationState &
result,
2614 ArrayRef<int64_t> resultShape, Value src,
2615 ArrayRef<ReassociationIndices> reassociation) {
2617 auto srcType = llvm::cast<MemRefType>(src.
getType());
2618 FailureOr<MemRefType> resultType =
2619 ExpandShapeOp::computeExpandedType(srcType, resultShape, reassociation);
2622 assert(succeeded(resultType) &&
"could not compute layout");
2623 build(builder,
result, *resultType, src, reassociation);
2626void ExpandShapeOp::build(OpBuilder &builder, OperationState &
result,
2627 ArrayRef<int64_t> resultShape, Value src,
2628 ArrayRef<ReassociationIndices> reassociation,
2629 ArrayRef<OpFoldResult> outputShape) {
2631 auto srcType = llvm::cast<MemRefType>(src.
getType());
2632 FailureOr<MemRefType> resultType =
2633 ExpandShapeOp::computeExpandedType(srcType, resultShape, reassociation);
2636 assert(succeeded(resultType) &&
"could not compute layout");
2637 build(builder,
result, *resultType, src, reassociation, outputShape);
2640LogicalResult ExpandShapeOp::verify() {
2641 MemRefType srcType = getSrcType();
2642 MemRefType resultType = getResultType();
2644 if (srcType.getRank() > resultType.getRank()) {
2645 auto r0 = srcType.getRank();
2646 auto r1 = resultType.getRank();
2647 return emitOpError(
"has source rank ")
2648 << r0 <<
" and result rank " << r1 <<
". This is not an expansion ("
2649 << r0 <<
" > " << r1 <<
").";
2654 resultType.getShape(),
2655 getReassociationIndices(),
2660 FailureOr<MemRefType> expectedResultType = ExpandShapeOp::computeExpandedType(
2661 srcType, resultType.getShape(), getReassociationIndices());
2662 if (
failed(expectedResultType))
2663 return emitOpError(
"invalid source layout map");
2666 if (*expectedResultType != resultType)
2667 return emitOpError(
"expected expanded type to be ")
2668 << *expectedResultType <<
" but found " << resultType;
2670 if ((int64_t)getStaticOutputShape().size() != resultType.getRank())
2671 return emitOpError(
"expected number of static shape bounds to be equal to "
2672 "the output rank (")
2673 << resultType.getRank() <<
") but found "
2674 << getStaticOutputShape().size() <<
" inputs instead";
2676 if ((int64_t)getOutputShape().size() !=
2677 llvm::count(getStaticOutputShape(), ShapedType::kDynamic))
2678 return emitOpError(
"mismatch in dynamic dims in output_shape and "
2679 "static_output_shape: static_output_shape has ")
2680 << llvm::count(getStaticOutputShape(), ShapedType::kDynamic)
2681 <<
" dynamic dims while output_shape has " << getOutputShape().size()
2692 ArrayRef<int64_t> resShape = getResult().getType().getShape();
2693 for (
auto [pos, shape] : llvm::enumerate(resShape)) {
2694 if (ShapedType::isStatic(shape) && shape != staticOutputShapes[pos]) {
2695 return emitOpError(
"invalid output shape provided at pos ") << pos;
2708 auto cast = op.getSrc().getDefiningOp<CastOp>();
2712 if (!CastOp::canFoldIntoConsumerOp(cast))
2720 for (
auto [dimIdx, dimSize] : enumerate(originalOutputShape)) {
2722 if (!sizeOpt.has_value()) {
2723 newOutputShapeSizes.push_back(ShapedType::kDynamic);
2727 newOutputShapeSizes.push_back(sizeOpt.value());
2728 newOutputShape[dimIdx] = rewriter.
getIndexAttr(sizeOpt.value());
2731 Value castSource = cast.getSource();
2732 auto castSourceType = llvm::cast<MemRefType>(castSource.
getType());
2734 op.getReassociationIndices();
2735 for (
auto [idx, group] : llvm::enumerate(reassociationIndices)) {
2736 auto newOutputShapeSizesSlice =
2737 ArrayRef(newOutputShapeSizes).slice(group.front(), group.size());
2738 bool newOutputDynamic =
2739 llvm::is_contained(newOutputShapeSizesSlice, ShapedType::kDynamic);
2740 if (castSourceType.isDynamicDim(idx) != newOutputDynamic)
2742 op,
"folding cast will result in changing dynamicity in "
2743 "reassociation group");
2746 FailureOr<MemRefType> newResultTypeOrFailure =
2747 ExpandShapeOp::computeExpandedType(castSourceType, newOutputShapeSizes,
2748 reassociationIndices);
2750 if (failed(newResultTypeOrFailure))
2752 op,
"could not compute new expanded type after folding cast");
2754 if (*newResultTypeOrFailure == op.getResultType()) {
2756 op, [&]() { op.getSrcMutable().assign(castSource); });
2758 Value newOp = ExpandShapeOp::create(rewriter, op->getLoc(),
2759 *newResultTypeOrFailure, castSource,
2760 reassociationIndices, newOutputShape);
2767void ExpandShapeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2768 MLIRContext *context) {
2770 ComposeReassociativeReshapeOps<ExpandShapeOp, ReshapeOpKind::kExpand>,
2771 ComposeExpandOfCollapseOp<ExpandShapeOp, CollapseShapeOp, CastOp>,
2772 ExpandShapeOpMemRefCastFolder>(context);
2775FailureOr<std::optional<SmallVector<Value>>>
2776ExpandShapeOp::bubbleDownCasts(OpBuilder &builder) {
2787static FailureOr<StridedLayoutAttr>
2790 bool strict =
false) {
2793 auto srcShape = srcType.getShape();
2794 if (failed(srcType.getStridesAndOffset(srcStrides, srcOffset)))
2803 resultStrides.reserve(reassociation.size());
2806 while (srcShape[ref.back()] == 1 && ref.size() > 1)
2807 ref = ref.drop_back();
2808 if (ShapedType::isStatic(srcShape[ref.back()]) || ref.size() == 1) {
2809 resultStrides.push_back(srcStrides[ref.back()]);
2815 resultStrides.push_back(ShapedType::kDynamic);
2820 unsigned resultStrideIndex = resultStrides.size() - 1;
2824 for (
int64_t idx : llvm::reverse(trailingReassocs)) {
2829 if (srcShape[idx - 1] == 1)
2841 if (strict && (stride.saturated || srcStride.saturated))
2844 if (!stride.saturated && !srcStride.saturated && stride != srcStride)
2848 return StridedLayoutAttr::get(srcType.getContext(), srcOffset, resultStrides);
2851bool CollapseShapeOp::isGuaranteedCollapsible(
2852 MemRefType srcType, ArrayRef<ReassociationIndices> reassociation) {
2854 if (srcType.getLayout().isIdentity())
2861MemRefType CollapseShapeOp::computeCollapsedType(
2862 MemRefType srcType, ArrayRef<ReassociationIndices> reassociation) {
2863 SmallVector<int64_t> resultShape;
2864 resultShape.reserve(reassociation.size());
2867 for (int64_t srcDim : group)
2870 resultShape.push_back(groupSize.asInteger());
2873 if (srcType.getLayout().isIdentity()) {
2876 MemRefLayoutAttrInterface layout;
2877 return MemRefType::get(resultShape, srcType.getElementType(), layout,
2878 srcType.getMemorySpace());
2884 FailureOr<StridedLayoutAttr> computedLayout =
2886 assert(succeeded(computedLayout) &&
2887 "invalid source layout map or collapsing non-contiguous dims");
2888 return MemRefType::get(resultShape, srcType.getElementType(), *computedLayout,
2889 srcType.getMemorySpace());
2892void CollapseShapeOp::build(OpBuilder &
b, OperationState &
result, Value src,
2893 ArrayRef<ReassociationIndices> reassociation,
2894 ArrayRef<NamedAttribute> attrs) {
2895 auto srcType = llvm::cast<MemRefType>(src.
getType());
2896 MemRefType resultType =
2897 CollapseShapeOp::computeCollapsedType(srcType, reassociation);
2900 build(
b,
result, resultType, src, attrs);
2903LogicalResult CollapseShapeOp::verify() {
2904 MemRefType srcType = getSrcType();
2905 MemRefType resultType = getResultType();
2907 if (srcType.getRank() < resultType.getRank()) {
2908 auto r0 = srcType.getRank();
2909 auto r1 = resultType.getRank();
2910 return emitOpError(
"has source rank ")
2911 << r0 <<
" and result rank " << r1 <<
". This is not a collapse ("
2912 << r0 <<
" < " << r1 <<
").";
2917 srcType.getShape(), getReassociationIndices(),
2922 MemRefType expectedResultType;
2923 if (srcType.getLayout().isIdentity()) {
2926 MemRefLayoutAttrInterface layout;
2927 expectedResultType =
2928 MemRefType::get(resultType.getShape(), srcType.getElementType(), layout,
2929 srcType.getMemorySpace());
2934 FailureOr<StridedLayoutAttr> computedLayout =
2936 if (
failed(computedLayout))
2938 "invalid source layout map or collapsing non-contiguous dims");
2939 expectedResultType =
2940 MemRefType::get(resultType.getShape(), srcType.getElementType(),
2941 *computedLayout, srcType.getMemorySpace());
2944 if (expectedResultType != resultType)
2945 return emitOpError(
"expected collapsed type to be ")
2946 << expectedResultType <<
" but found " << resultType;
2958 auto cast = op.getOperand().getDefiningOp<CastOp>();
2962 if (!CastOp::canFoldIntoConsumerOp(cast))
2965 Type newResultType = CollapseShapeOp::computeCollapsedType(
2966 llvm::cast<MemRefType>(cast.getOperand().getType()),
2967 op.getReassociationIndices());
2969 if (newResultType == op.getResultType()) {
2971 op, [&]() { op.getSrcMutable().assign(cast.getSource()); });
2974 CollapseShapeOp::create(rewriter, op->getLoc(), cast.getSource(),
2975 op.getReassociationIndices());
2982void CollapseShapeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2983 MLIRContext *context) {
2985 ComposeReassociativeReshapeOps<CollapseShapeOp, ReshapeOpKind::kCollapse>,
2986 ComposeCollapseOfExpandOp<CollapseShapeOp, ExpandShapeOp, CastOp,
2987 memref::DimOp, MemRefType>,
2988 CollapseShapeOpMemRefCastFolder>(context);
2991OpFoldResult ExpandShapeOp::fold(FoldAdaptor adaptor) {
2993 adaptor.getOperands());
2996OpFoldResult CollapseShapeOp::fold(FoldAdaptor adaptor) {
2998 adaptor.getOperands());
3001FailureOr<std::optional<SmallVector<Value>>>
3002CollapseShapeOp::bubbleDownCasts(OpBuilder &builder) {
3010void ReshapeOp::getAsmResultNames(
3012 setNameFn(getResult(),
"reshape");
3015LogicalResult ReshapeOp::verify() {
3016 Type operandType = getSource().getType();
3017 Type resultType = getResult().getType();
3019 Type operandElementType =
3020 llvm::cast<ShapedType>(operandType).getElementType();
3021 Type resultElementType = llvm::cast<ShapedType>(resultType).getElementType();
3022 if (operandElementType != resultElementType)
3023 return emitOpError(
"element types of source and destination memref "
3024 "types should be the same");
3026 if (
auto operandMemRefType = llvm::dyn_cast<MemRefType>(operandType))
3027 if (!operandMemRefType.getLayout().isIdentity())
3028 return emitOpError(
"source memref type should have identity affine map");
3032 auto resultMemRefType = llvm::dyn_cast<MemRefType>(resultType);
3033 if (resultMemRefType) {
3034 if (!resultMemRefType.getLayout().isIdentity())
3035 return emitOpError(
"result memref type should have identity affine map");
3036 if (shapeSize == ShapedType::kDynamic)
3037 return emitOpError(
"cannot use shape operand with dynamic length to "
3038 "reshape to statically-ranked memref type");
3039 if (shapeSize != resultMemRefType.getRank())
3041 "length of shape operand differs from the result's memref rank");
3046FailureOr<std::optional<SmallVector<Value>>>
3047ReshapeOp::bubbleDownCasts(OpBuilder &builder) {
3055LogicalResult StoreOp::fold(FoldAdaptor adaptor,
3056 SmallVectorImpl<OpFoldResult> &results) {
3063std::optional<SmallVector<Value>>
3064StoreOp::updateMemrefAndIndices(RewriterBase &rewriter, Value newMemref,
3067 getMemrefMutable().assign(newMemref);
3068 getIndicesMutable().assign(newIndices);
3070 return std::nullopt;
3073FailureOr<std::optional<SmallVector<Value>>>
3074StoreOp::bubbleDownCasts(OpBuilder &builder) {
3083void SubViewOp::getAsmResultNames(
3085 setNameFn(getResult(),
"subview");
3091MemRefType SubViewOp::inferResultType(MemRefType sourceMemRefType,
3092 ArrayRef<int64_t> staticOffsets,
3093 ArrayRef<int64_t> staticSizes,
3094 ArrayRef<int64_t> staticStrides) {
3095 unsigned rank = sourceMemRefType.getRank();
3097 assert(staticOffsets.size() == rank &&
"staticOffsets length mismatch");
3098 assert(staticSizes.size() == rank &&
"staticSizes length mismatch");
3099 assert(staticStrides.size() == rank &&
"staticStrides length mismatch");
3102 auto [sourceStrides, sourceOffset] = sourceMemRefType.getStridesAndOffset();
3106 int64_t targetOffset = sourceOffset;
3107 for (
auto it : llvm::zip(staticOffsets, sourceStrides)) {
3108 auto staticOffset = std::get<0>(it), sourceStride = std::get<1>(it);
3117 SmallVector<int64_t, 4> targetStrides;
3118 targetStrides.reserve(staticOffsets.size());
3119 for (
auto it : llvm::zip(sourceStrides, staticStrides)) {
3120 auto sourceStride = std::get<0>(it), staticStride = std::get<1>(it);
3127 return MemRefType::get(staticSizes, sourceMemRefType.getElementType(),
3128 StridedLayoutAttr::get(sourceMemRefType.getContext(),
3129 targetOffset, targetStrides),
3130 sourceMemRefType.getMemorySpace());
3133MemRefType SubViewOp::inferResultType(MemRefType sourceMemRefType,
3134 ArrayRef<OpFoldResult> offsets,
3135 ArrayRef<OpFoldResult> sizes,
3136 ArrayRef<OpFoldResult> strides) {
3137 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
3138 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
3148 return SubViewOp::inferResultType(sourceMemRefType, staticOffsets,
3149 staticSizes, staticStrides);
3152MemRefType SubViewOp::inferRankReducedResultType(
3153 ArrayRef<int64_t> resultShape, MemRefType sourceRankedTensorType,
3154 ArrayRef<int64_t> offsets, ArrayRef<int64_t> sizes,
3155 ArrayRef<int64_t> strides) {
3156 MemRefType inferredType =
3157 inferResultType(sourceRankedTensorType, offsets, sizes, strides);
3158 assert(inferredType.getRank() >=
static_cast<int64_t
>(resultShape.size()) &&
3160 if (inferredType.getRank() ==
static_cast<int64_t
>(resultShape.size()))
3161 return inferredType;
3164 std::optional<llvm::SmallDenseSet<unsigned>> dimsToProject =
3166 assert(dimsToProject.has_value() &&
"invalid rank reduction");
3169 auto inferredLayout = llvm::cast<StridedLayoutAttr>(inferredType.getLayout());
3170 SmallVector<int64_t> rankReducedStrides;
3171 rankReducedStrides.reserve(resultShape.size());
3172 for (
auto [idx, value] : llvm::enumerate(inferredLayout.getStrides())) {
3173 if (!dimsToProject->contains(idx))
3174 rankReducedStrides.push_back(value);
3176 return MemRefType::get(resultShape, inferredType.getElementType(),
3177 StridedLayoutAttr::get(inferredLayout.getContext(),
3178 inferredLayout.getOffset(),
3179 rankReducedStrides),
3180 inferredType.getMemorySpace());
3183MemRefType SubViewOp::inferRankReducedResultType(
3184 ArrayRef<int64_t> resultShape, MemRefType sourceRankedTensorType,
3185 ArrayRef<OpFoldResult> offsets, ArrayRef<OpFoldResult> sizes,
3186 ArrayRef<OpFoldResult> strides) {
3187 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
3188 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
3192 return SubViewOp::inferRankReducedResultType(
3193 resultShape, sourceRankedTensorType, staticOffsets, staticSizes,
3199void SubViewOp::build(OpBuilder &
b, OperationState &
result,
3200 MemRefType resultType, Value source,
3201 ArrayRef<OpFoldResult> offsets,
3202 ArrayRef<OpFoldResult> sizes,
3203 ArrayRef<OpFoldResult> strides,
3204 ArrayRef<NamedAttribute> attrs) {
3205 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
3206 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
3210 auto sourceMemRefType = llvm::cast<MemRefType>(source.
getType());
3213 resultType = SubViewOp::inferResultType(sourceMemRefType, staticOffsets,
3214 staticSizes, staticStrides);
3216 result.addAttributes(attrs);
3217 build(
b,
result, resultType, source, dynamicOffsets, dynamicSizes,
3218 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
3219 b.getDenseI64ArrayAttr(staticSizes),
3220 b.getDenseI64ArrayAttr(staticStrides));
3225void SubViewOp::build(OpBuilder &
b, OperationState &
result, Value source,
3226 ArrayRef<OpFoldResult> offsets,
3227 ArrayRef<OpFoldResult> sizes,
3228 ArrayRef<OpFoldResult> strides,
3229 ArrayRef<NamedAttribute> attrs) {
3230 build(
b,
result, MemRefType(), source, offsets, sizes, strides, attrs);
3234void SubViewOp::build(OpBuilder &
b, OperationState &
result, Value source,
3235 ArrayRef<int64_t> offsets, ArrayRef<int64_t> sizes,
3236 ArrayRef<int64_t> strides,
3237 ArrayRef<NamedAttribute> attrs) {
3238 SmallVector<OpFoldResult> offsetValues =
3239 llvm::map_to_vector<4>(offsets, [&](int64_t v) -> OpFoldResult {
3240 return b.getI64IntegerAttr(v);
3242 SmallVector<OpFoldResult> sizeValues = llvm::map_to_vector<4>(
3243 sizes, [&](int64_t v) -> OpFoldResult {
return b.getI64IntegerAttr(v); });
3244 SmallVector<OpFoldResult> strideValues =
3245 llvm::map_to_vector<4>(strides, [&](int64_t v) -> OpFoldResult {
3246 return b.getI64IntegerAttr(v);
3248 build(
b,
result, source, offsetValues, sizeValues, strideValues, attrs);
3253void SubViewOp::build(OpBuilder &
b, OperationState &
result,
3254 MemRefType resultType, Value source,
3255 ArrayRef<int64_t> offsets, ArrayRef<int64_t> sizes,
3256 ArrayRef<int64_t> strides,
3257 ArrayRef<NamedAttribute> attrs) {
3258 SmallVector<OpFoldResult> offsetValues =
3259 llvm::map_to_vector<4>(offsets, [&](int64_t v) -> OpFoldResult {
3260 return b.getI64IntegerAttr(v);
3262 SmallVector<OpFoldResult> sizeValues = llvm::map_to_vector<4>(
3263 sizes, [&](int64_t v) -> OpFoldResult {
return b.getI64IntegerAttr(v); });
3264 SmallVector<OpFoldResult> strideValues =
3265 llvm::map_to_vector<4>(strides, [&](int64_t v) -> OpFoldResult {
3266 return b.getI64IntegerAttr(v);
3268 build(
b,
result, resultType, source, offsetValues, sizeValues, strideValues,
3274void SubViewOp::build(OpBuilder &
b, OperationState &
result,
3275 MemRefType resultType, Value source,
ValueRange offsets,
3277 ArrayRef<NamedAttribute> attrs) {
3278 SmallVector<OpFoldResult> offsetValues = llvm::map_to_vector<4>(
3279 offsets, [](Value v) -> OpFoldResult {
return v; });
3280 SmallVector<OpFoldResult> sizeValues =
3281 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
3282 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
3283 strides, [](Value v) -> OpFoldResult {
return v; });
3284 build(
b,
result, resultType, source, offsetValues, sizeValues, strideValues);
3288void SubViewOp::build(OpBuilder &
b, OperationState &
result, Value source,
3290 ArrayRef<NamedAttribute> attrs) {
3291 build(
b,
result, MemRefType(), source, offsets, sizes, strides, attrs);
3295Value SubViewOp::getViewSource() {
return getSource(); }
3302 auto res1 = t1.getStridesAndOffset(t1Strides, t1Offset);
3303 auto res2 = t2.getStridesAndOffset(t2Strides, t2Offset);
3304 return succeeded(res1) && succeeded(res2) && t1Offset == t2Offset;
3311 const llvm::SmallBitVector &droppedDims) {
3312 assert(
size_t(t1.getRank()) == droppedDims.size() &&
3313 "incorrect number of bits");
3314 assert(
size_t(t1.getRank() - t2.getRank()) == droppedDims.count() &&
3315 "incorrect number of dropped dims");
3318 auto res1 = t1.getStridesAndOffset(t1Strides, t1Offset);
3319 auto res2 = t2.getStridesAndOffset(t2Strides, t2Offset);
3320 if (failed(res1) || failed(res2))
3322 for (
int64_t i = 0,
j = 0, e = t1.getRank(); i < e; ++i) {
3325 if (t1Strides[i] != t2Strides[
j])
3333 SubViewOp op,
Type expectedType) {
3334 auto memrefType = llvm::cast<ShapedType>(expectedType);
3339 return op->emitError(
"expected result rank to be smaller or equal to ")
3340 <<
"the source rank, but got " << op.getType();
3342 return op->emitError(
"expected result type to be ")
3344 <<
" or a rank-reduced version. (mismatch of result sizes), but got "
3347 return op->emitError(
"expected result element type to be ")
3348 << memrefType.getElementType() <<
", but got " << op.getType();
3350 return op->emitError(
3351 "expected result and source memory spaces to match, but got ")
3354 return op->emitError(
"expected result type to be ")
3356 <<
" or a rank-reduced version. (mismatch of result layout), but "
3360 llvm_unreachable(
"unexpected subview verification result");
3364LogicalResult SubViewOp::verify() {
3365 MemRefType baseType = getSourceType();
3366 MemRefType subViewType =
getType();
3367 ArrayRef<int64_t> staticOffsets = getStaticOffsets();
3368 ArrayRef<int64_t> staticSizes = getStaticSizes();
3369 ArrayRef<int64_t> staticStrides = getStaticStrides();
3372 if (baseType.getMemorySpace() != subViewType.getMemorySpace())
3373 return emitError(
"different memory spaces specified for base memref "
3375 << baseType <<
" and subview memref type " << subViewType;
3378 if (!baseType.isStrided())
3379 return emitError(
"base type ") << baseType <<
" is not strided";
3383 MemRefType expectedType = SubViewOp::inferResultType(
3384 baseType, staticOffsets, staticSizes, staticStrides);
3389 expectedType, subViewType);
3394 if (expectedType.getMemorySpace() != subViewType.getMemorySpace())
3396 *
this, expectedType);
3401 *
this, expectedType);
3411 *
this, expectedType);
3416 *
this, expectedType);
3420 SliceBoundsVerificationResult boundsResult =
3422 staticStrides,
true);
3424 return getOperation()->emitError(boundsResult.
errorMessage);
3430 return os <<
"range " << range.
offset <<
":" << range.
size <<
":"
3439 std::array<unsigned, 3> ranks = op.getArrayAttrMaxRanks();
3440 assert(ranks[0] == ranks[1] &&
"expected offset and sizes of equal ranks");
3441 assert(ranks[1] == ranks[2] &&
"expected sizes and strides of equal ranks");
3443 unsigned rank = ranks[0];
3445 for (
unsigned idx = 0; idx < rank; ++idx) {
3447 op.isDynamicOffset(idx)
3448 ? op.getDynamicOffset(idx)
3451 op.isDynamicSize(idx)
3452 ? op.getDynamicSize(idx)
3455 op.isDynamicStride(idx)
3456 ? op.getDynamicStride(idx)
3458 res.emplace_back(
Range{offset, size, stride});
3471 MemRefType currentResultType, MemRefType currentSourceType,
3474 MemRefType nonRankReducedType = SubViewOp::inferResultType(
3475 sourceType, mixedOffsets, mixedSizes, mixedStrides);
3477 currentSourceType, currentResultType, mixedSizes);
3478 if (failed(unusedDims))
3481 auto layout = llvm::cast<StridedLayoutAttr>(nonRankReducedType.getLayout());
3483 unsigned numDimsAfterReduction =
3484 nonRankReducedType.getRank() - unusedDims->count();
3485 shape.reserve(numDimsAfterReduction);
3486 strides.reserve(numDimsAfterReduction);
3487 for (
const auto &[idx, size, stride] :
3488 llvm::zip(llvm::seq<unsigned>(0, nonRankReducedType.getRank()),
3489 nonRankReducedType.getShape(), layout.getStrides())) {
3490 if (unusedDims->test(idx))
3492 shape.push_back(size);
3493 strides.push_back(stride);
3496 return MemRefType::get(
shape, nonRankReducedType.getElementType(),
3497 StridedLayoutAttr::get(sourceType.getContext(),
3498 layout.getOffset(), strides),
3499 nonRankReducedType.getMemorySpace());
3504 auto memrefType = llvm::cast<MemRefType>(
memref.getType());
3505 unsigned rank = memrefType.getRank();
3509 MemRefType targetType = SubViewOp::inferRankReducedResultType(
3510 targetShape, memrefType, offsets, sizes, strides);
3511 return b.createOrFold<memref::SubViewOp>(loc, targetType,
memref, offsets,
3518 auto sourceMemrefType = llvm::dyn_cast<MemRefType>(value.
getType());
3519 assert(sourceMemrefType &&
"not a ranked memref type");
3520 auto sourceShape = sourceMemrefType.getShape();
3521 if (sourceShape.equals(desiredShape))
3523 auto maybeRankReductionMask =
3525 if (!maybeRankReductionMask)
3535 if (subViewOp.getSourceType().getRank() != subViewOp.getType().getRank())
3538 auto mixedOffsets = subViewOp.getMixedOffsets();
3539 auto mixedSizes = subViewOp.getMixedSizes();
3540 auto mixedStrides = subViewOp.getMixedStrides();
3545 return !intValue || intValue.value() != 0;
3552 return !intValue || intValue.value() != 1;
3558 for (
const auto &size : llvm::enumerate(mixedSizes)) {
3560 if (!intValue || *intValue != sourceShape[size.index()])
3584class SubViewOpMemRefCastFolder final :
public OpRewritePattern<SubViewOp> {
3586 using OpRewritePattern<SubViewOp>::OpRewritePattern;
3588 LogicalResult matchAndRewrite(SubViewOp subViewOp,
3589 PatternRewriter &rewriter)
const override {
3592 if (llvm::any_of(subViewOp.getOperands(), [](Value operand) {
3593 return matchPattern(operand, matchConstantIndex());
3597 auto castOp = subViewOp.getSource().getDefiningOp<CastOp>();
3601 if (!CastOp::canFoldIntoConsumerOp(castOp))
3609 subViewOp.getType(), subViewOp.getSourceType(),
3610 llvm::cast<MemRefType>(castOp.getSource().getType()),
3611 subViewOp.getMixedOffsets(), subViewOp.getMixedSizes(),
3612 subViewOp.getMixedStrides());
3616 Value newSubView = SubViewOp::create(
3617 rewriter, subViewOp.getLoc(), resultType, castOp.getSource(),
3618 subViewOp.getOffsets(), subViewOp.getSizes(), subViewOp.getStrides(),
3619 subViewOp.getStaticOffsets(), subViewOp.getStaticSizes(),
3620 subViewOp.getStaticStrides());
3629class TrivialSubViewOpFolder final :
public OpRewritePattern<SubViewOp> {
3631 using OpRewritePattern<SubViewOp>::OpRewritePattern;
3633 LogicalResult matchAndRewrite(SubViewOp subViewOp,
3634 PatternRewriter &rewriter)
const override {
3637 if (subViewOp.getSourceType() == subViewOp.getType()) {
3638 rewriter.
replaceOp(subViewOp, subViewOp.getSource());
3642 subViewOp.getSource());
3654 MemRefType resTy = SubViewOp::inferResultType(
3655 op.getSourceType(), mixedOffsets, mixedSizes, mixedStrides);
3658 MemRefType nonReducedType = resTy;
3661 llvm::SmallBitVector droppedDims = op.getDroppedDims();
3662 if (droppedDims.none())
3663 return nonReducedType;
3666 auto [nonReducedStrides, offset] = nonReducedType.getStridesAndOffset();
3671 for (
int64_t i = 0; i < static_cast<int64_t>(mixedSizes.size()); ++i) {
3672 if (droppedDims.test(i))
3674 targetStrides.push_back(nonReducedStrides[i]);
3675 targetShape.push_back(nonReducedType.getDimSize(i));
3678 return MemRefType::get(targetShape, nonReducedType.getElementType(),
3679 StridedLayoutAttr::get(nonReducedType.getContext(),
3680 offset, targetStrides),
3681 nonReducedType.getMemorySpace());
3692void SubViewOp::getCanonicalizationPatterns(RewritePatternSet &results,
3693 MLIRContext *context) {
3695 .
add<OpWithOffsetSizesAndStridesConstantArgumentFolder<
3696 SubViewOp, SubViewReturnTypeCanonicalizer, SubViewCanonicalizer>,
3697 SubViewOpMemRefCastFolder, TrivialSubViewOpFolder>(context);
3700OpFoldResult SubViewOp::fold(FoldAdaptor adaptor) {
3701 MemRefType sourceMemrefType = getSource().getType();
3702 MemRefType resultMemrefType = getResult().getType();
3704 dyn_cast_if_present<StridedLayoutAttr>(resultMemrefType.getLayout());
3706 if (resultMemrefType == sourceMemrefType &&
3707 resultMemrefType.hasStaticShape() &&
3708 (!resultLayout || resultLayout.hasStaticLayout())) {
3709 return getViewSource();
3715 if (
auto srcSubview = getViewSource().getDefiningOp<SubViewOp>()) {
3716 auto srcSizes = srcSubview.getMixedSizes();
3718 auto offsets = getMixedOffsets();
3720 auto strides = getMixedStrides();
3721 bool allStridesOne = llvm::all_of(strides,
isOneInteger);
3722 bool allSizesSame = llvm::equal(sizes, srcSizes);
3723 if (allOffsetsZero && allStridesOne && allSizesSame &&
3724 resultMemrefType == sourceMemrefType)
3725 return getViewSource();
3731FailureOr<std::optional<SmallVector<Value>>>
3732SubViewOp::bubbleDownCasts(OpBuilder &builder) {
3736void SubViewOp::inferStridedMetadataRanges(
3737 ArrayRef<StridedMetadataRange> ranges,
GetIntRangeFn getIntRange,
3739 auto isUninitialized =
3740 +[](IntegerValueRange range) {
return range.isUninitialized(); };
3743 SmallVector<IntegerValueRange> offsetOperands =
3745 if (llvm::any_of(offsetOperands, isUninitialized))
3748 SmallVector<IntegerValueRange> sizeOperands =
3750 if (llvm::any_of(sizeOperands, isUninitialized))
3753 SmallVector<IntegerValueRange> stridesOperands =
3755 if (llvm::any_of(stridesOperands, isUninitialized))
3758 StridedMetadataRange sourceRange =
3759 ranges[getSourceMutable().getOperandNumber()];
3763 ArrayRef<ConstantIntRanges> srcStrides = sourceRange.
getStrides();
3769 ConstantIntRanges offset = sourceRange.
getOffsets()[0];
3770 SmallVector<ConstantIntRanges> strides, sizes;
3772 for (
size_t i = 0, e = droppedDims.size(); i < e; ++i) {
3773 bool dropped = droppedDims.test(i);
3775 ConstantIntRanges off =
3786 sizes.push_back(sizeOperands[i].getValue());
3789 setMetadata(getResult(),
3791 SmallVector<ConstantIntRanges>({std::move(offset)}),
3792 std::move(sizes), std::move(strides)));
3799void TransposeOp::getAsmResultNames(
3801 setNameFn(getResult(),
"transpose");
3807 auto originalSizes = memRefType.getShape();
3808 auto [originalStrides, offset] = memRefType.getStridesAndOffset();
3809 assert(originalStrides.size() ==
static_cast<unsigned>(memRefType.getRank()));
3818 StridedLayoutAttr::get(memRefType.getContext(), offset, strides));
3821Value TransposeOp::getViewSource() {
return getIn(); }
3823void TransposeOp::build(OpBuilder &
b, OperationState &
result, Value in,
3824 AffineMapAttr permutation,
3825 ArrayRef<NamedAttribute> attrs) {
3826 auto permutationMap = permutation.getValue();
3827 assert(permutationMap);
3829 auto memRefType = llvm::cast<MemRefType>(in.
getType());
3833 result.addAttribute(TransposeOp::getPermutationAttrStrName(), permutation);
3834 build(
b,
result, resultType, in, attrs);
3838void TransposeOp::print(OpAsmPrinter &p) {
3839 p <<
" " << getIn() <<
" " << getPermutation();
3841 {getPermutationAttrStrName()});
3842 p <<
" : " << getIn().getType() <<
" to " <<
getType();
3845ParseResult TransposeOp::parse(OpAsmParser &parser, OperationState &
result) {
3846 OpAsmParser::UnresolvedOperand in;
3847 AffineMap permutation;
3848 MemRefType srcType, dstType;
3857 result.addAttribute(TransposeOp::getPermutationAttrStrName(),
3858 AffineMapAttr::get(permutation));
3862LogicalResult TransposeOp::verify() {
3864 return emitOpError(
"expected a permutation map");
3865 if (getPermutation().getNumDims() != getIn().
getType().getRank())
3866 return emitOpError(
"expected a permutation map of same rank as the input");
3868 auto srcType = llvm::cast<MemRefType>(getIn().
getType());
3869 auto resultType = llvm::cast<MemRefType>(
getType());
3871 .canonicalizeStridedLayout();
3873 if (resultType.canonicalizeStridedLayout() != canonicalResultType)
3874 return emitOpError(
"result type ")
3876 <<
" is not equivalent to the canonical transposed input type "
3877 << canonicalResultType;
3881OpFoldResult TransposeOp::fold(FoldAdaptor) {
3884 if (getPermutation().isIdentity() &&
getType() == getIn().
getType())
3888 if (
auto otherTransposeOp = getIn().getDefiningOp<memref::TransposeOp>()) {
3889 AffineMap composedPermutation =
3890 getPermutation().compose(otherTransposeOp.getPermutation());
3891 getInMutable().assign(otherTransposeOp.getIn());
3892 setPermutation(composedPermutation);
3898FailureOr<std::optional<SmallVector<Value>>>
3899TransposeOp::bubbleDownCasts(OpBuilder &builder) {
3907void ViewOp::getAsmResultNames(
function_ref<
void(Value, StringRef)> setNameFn) {
3908 setNameFn(getResult(),
"view");
3911LogicalResult ViewOp::verify() {
3912 auto baseType = llvm::cast<MemRefType>(getOperand(0).
getType());
3916 if (!baseType.getLayout().isIdentity())
3917 return emitError(
"unsupported map for base memref type ") << baseType;
3920 if (!viewType.getLayout().isIdentity())
3921 return emitError(
"unsupported map for result memref type ") << viewType;
3924 if (baseType.getMemorySpace() != viewType.getMemorySpace())
3925 return emitError(
"different memory spaces specified for base memref "
3927 << baseType <<
" and view memref type " << viewType;
3936Value ViewOp::getViewSource() {
return getSource(); }
3938OpFoldResult ViewOp::fold(FoldAdaptor adaptor) {
3939 MemRefType sourceMemrefType = getSource().getType();
3940 MemRefType resultMemrefType = getResult().getType();
3942 if (resultMemrefType == sourceMemrefType &&
3943 resultMemrefType.hasStaticShape() &&
isZeroInteger(getByteShift()))
3944 return getViewSource();
3949SmallVector<OpFoldResult> ViewOp::getMixedSizes() {
3950 SmallVector<OpFoldResult>
result;
3954 if (ShapedType::isDynamic(dim)) {
3955 result.push_back(getSizes()[ctr++]);
3957 result.push_back(
b.getIndexAttr(dim));
3969 SmallVectorImpl<Value> &foldedDynamicSizes) {
3970 SmallVector<int64_t> staticShape(type.getShape());
3971 assert(type.getNumDynamicDims() == dynamicSizes.size() &&
3972 "incorrect number of dynamic sizes");
3976 for (
auto [dim, dimSize] : llvm::enumerate(type.getShape())) {
3977 if (ShapedType::isStatic(dimSize))
3980 Value dynamicSize = dynamicSizes[ctr++];
3983 if (cst.value() < 0) {
3984 foldedDynamicSizes.push_back(dynamicSize);
3987 staticShape[dim] = cst.value();
3989 foldedDynamicSizes.push_back(dynamicSize);
3993 return MemRefType::Builder(type).setShape(staticShape);
4007struct ViewOpShapeFolder :
public OpRewritePattern<ViewOp> {
4010 LogicalResult matchAndRewrite(ViewOp viewOp,
4011 PatternRewriter &rewriter)
const override {
4012 SmallVector<Value> foldedDynamicSizes;
4013 MemRefType resultType = viewOp.getType();
4015 resultType, viewOp.getSizes(), foldedDynamicSizes);
4018 if (foldedMemRefType == resultType)
4022 auto newViewOp = ViewOp::create(rewriter, viewOp.getLoc(), foldedMemRefType,
4023 viewOp.getSource(), viewOp.getByteShift(),
4024 foldedDynamicSizes);
4032struct ViewOpMemrefCastFolder :
public OpRewritePattern<ViewOp> {
4035 LogicalResult matchAndRewrite(ViewOp viewOp,
4036 PatternRewriter &rewriter)
const override {
4037 auto memrefCastOp = viewOp.getSource().getDefiningOp<CastOp>();
4042 viewOp, viewOp.getType(), memrefCastOp.getSource(),
4043 viewOp.getByteShift(), viewOp.getSizes());
4049void ViewOp::getCanonicalizationPatterns(RewritePatternSet &results,
4050 MLIRContext *context) {
4051 results.
add<ViewOpShapeFolder, ViewOpMemrefCastFolder>(context);
4054FailureOr<std::optional<SmallVector<Value>>>
4055ViewOp::bubbleDownCasts(OpBuilder &builder) {
4063LogicalResult AtomicRMWOp::verify() {
4064 switch (getKind()) {
4065 case arith::AtomicRMWKind::addf:
4066 case arith::AtomicRMWKind::maximumf:
4067 case arith::AtomicRMWKind::minimumf:
4068 case arith::AtomicRMWKind::mulf:
4069 if (!llvm::isa<FloatType>(getValue().
getType()))
4070 return emitOpError() <<
"with kind '"
4071 << arith::stringifyAtomicRMWKind(getKind())
4072 <<
"' expects a floating-point type";
4074 case arith::AtomicRMWKind::addi:
4075 case arith::AtomicRMWKind::maxs:
4076 case arith::AtomicRMWKind::maxu:
4077 case arith::AtomicRMWKind::mins:
4078 case arith::AtomicRMWKind::minu:
4079 case arith::AtomicRMWKind::muli:
4080 case arith::AtomicRMWKind::ori:
4081 case arith::AtomicRMWKind::xori:
4082 case arith::AtomicRMWKind::andi:
4083 if (!llvm::isa<IntegerType>(getValue().
getType()))
4084 return emitOpError() <<
"with kind '"
4085 << arith::stringifyAtomicRMWKind(getKind())
4086 <<
"' expects an integer type";
4094OpFoldResult AtomicRMWOp::fold(FoldAdaptor adaptor) {
4098 return OpFoldResult();
4101FailureOr<std::optional<SmallVector<Value>>>
4102AtomicRMWOp::bubbleDownCasts(OpBuilder &builder) {
4109std::optional<SmallVector<Value>>
4110AtomicRMWOp::updateMemrefAndIndices(RewriterBase &rewriter, Value newMemref,
4113 getMemrefMutable().assign(newMemref);
4114 getIndicesMutable().assign(newIndices);
4116 return std::nullopt;
4123#define GET_OP_CLASSES
4124#include "mlir/Dialect/MemRef/IR/MemRefOps.cpp.inc"
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static bool hasSideEffects(Operation *op)
static bool isPermutation(const std::vector< PermutationTy > &permutation)
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
static LogicalResult foldCopyOfCast(CopyOp op)
If the source/target of a CopyOp is a CastOp that does not modify the shape and element type,...
static void constifyIndexValues(SmallVectorImpl< OpFoldResult > &values, ArrayRef< int64_t > constValues)
Helper function that sets values[i] to constValues[i] if the latter is a static value,...
static void printGlobalMemrefOpTypeAndInitialValue(OpAsmPrinter &p, GlobalOp op, TypeAttr type, Attribute initialValue)
static LogicalResult verifyCollapsedShape(Operation *op, ArrayRef< int64_t > collapsedShape, ArrayRef< int64_t > expandedShape, ArrayRef< ReassociationIndices > reassociation, bool allowMultipleDynamicDimsPerGroup)
Helper function for verifying the shape of ExpandShapeOp and ResultShapeOp result and operand.
static bool isOpItselfPotentialAutomaticAllocation(Operation *op)
Given an operation, return whether this op itself could allocate an AutomaticAllocationScopeResource.
static MemRefType inferTransposeResultType(MemRefType memRefType, AffineMap permutationMap)
Build a strided memref type by applying permutationMap to memRefType.
static ParseResult parseBoolAttr(OpAsmParser &parser, BoolAttr &result)
static bool isGuaranteedAutomaticAllocation(Operation *op)
Given an operation, return whether this op is guaranteed to allocate an AutomaticAllocationScopeResou...
static FailureOr< llvm::SmallBitVector > computeMemRefRankReductionMaskByStrides(MemRefType originalType, MemRefType reducedType, ArrayRef< int64_t > originalStrides, ArrayRef< int64_t > candidateStrides, llvm::SmallBitVector unusedDims)
Returns the set of source dimensions that are dropped in a rank reduction.
static FailureOr< StridedLayoutAttr > computeExpandedLayoutMap(MemRefType srcType, ArrayRef< int64_t > resultShape, ArrayRef< ReassociationIndices > reassociation)
Compute the layout map after expanding a given source MemRef type with the specified reassociation in...
static bool haveCompatibleOffsets(MemRefType t1, MemRefType t2)
Return true if t1 and t2 have equal offsets (both dynamic or of same static value).
static void printBoolAttr(OpAsmPrinter &printer, Operation *, BoolAttr attr)
static bool replaceConstantUsesOf(OpBuilder &rewriter, Location loc, Container values, ArrayRef< OpFoldResult > maybeConstants)
Helper function to perform the replacement of all constant uses of values by a materialized constant ...
static LogicalResult produceSubViewErrorMsg(SliceVerificationResult result, SubViewOp op, Type expectedType)
static MemRefType getCanonicalSubViewResultType(MemRefType currentResultType, MemRefType currentSourceType, MemRefType sourceType, ArrayRef< OpFoldResult > mixedOffsets, ArrayRef< OpFoldResult > mixedSizes, ArrayRef< OpFoldResult > mixedStrides)
Compute the canonical result type of a SubViewOp.
static ParseResult parseGlobalMemrefOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr, Attribute &initialValue)
static std::tuple< MemorySpaceCastOpInterface, PtrLikeTypeInterface, Type > getMemorySpaceCastInfo(BaseMemRefType resultTy, Value src)
Helper function to retrieve a lossless memory-space cast, and the corresponding new result memref typ...
static FailureOr< llvm::SmallBitVector > computeMemRefRankReductionMask(MemRefType originalType, MemRefType reducedType, ArrayRef< OpFoldResult > sizes)
Given the originalType and a candidateReducedType whose shape is assumed to be a subset of originalTy...
static bool isTrivialSubViewOp(SubViewOp subViewOp)
Helper method to check if a subview operation is trivially a no-op.
static bool lastNonTerminatorInRegion(Operation *op)
Return whether this op is the last non terminating op in a region.
static std::map< int64_t, unsigned > getNumOccurences(ArrayRef< int64_t > vals)
Return a map with key being elements in vals and data being number of occurences of it.
static bool haveCompatibleStrides(MemRefType t1, MemRefType t2, const llvm::SmallBitVector &droppedDims)
Return true if t1 and t2 have equal strides (both dynamic or of same static value).
static FailureOr< StridedLayoutAttr > computeCollapsedLayoutMap(MemRefType srcType, ArrayRef< ReassociationIndices > reassociation, bool strict=false)
Compute the layout map after collapsing a given source MemRef type with the specified reassociation i...
static FailureOr< std::optional< SmallVector< Value > > > bubbleDownCastsPassthroughOpImpl(ConcreteOpTy op, OpBuilder &builder, OpOperand &src)
Implementation of bubbleDownCasts method for memref operations that return a single memref result.
static FailureOr< llvm::SmallBitVector > computeMemRefRankReductionMaskByPosition(MemRefType originalType, MemRefType reducedType, ArrayRef< OpFoldResult > sizes)
Returns the set of source dimensions that are dropped in a rank reduction.
static LogicalResult verifyAllocLikeOp(AllocLikeOp op)
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 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 ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
@ Square
Square brackets surrounding zero or more operands.
virtual ParseResult parseColonTypeList(SmallVectorImpl< Type > &result)=0
Parse a colon followed by a type list, which must have at least one type.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalEqual()=0
Parse a = token if present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseAffineMap(AffineMap &map)=0
Parse an affine map instance into 'map'.
ParseResult addTypeToList(Type type, SmallVectorImpl< Type > &result)
Add the specified type to the end of the specified type list and return success.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseOptionalArrowTypeList(SmallVectorImpl< Type > &result)=0
Parse an optional arrow followed by a type list.
ParseResult parseKeywordType(const char *keyword, Type &result)
Parse a keyword followed by a type.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
virtual void printAttributeWithoutType(Attribute attr)
Print the given attribute without its type.
virtual void printAttribute(Attribute attr)
Attributes are known-constant values of operations.
This class provides a shared interface for ranked and unranked memref types.
ArrayRef< int64_t > getShape() const
Returns the shape of this memref type.
FailureOr< PtrLikeTypeInterface > clonePtrWith(Attribute memorySpace, std::optional< Type > elementType) const
Clone this type with the given memory space and element type.
bool hasRank() const
Returns if this type is ranked, i.e. it has a known number of dimensions.
Block represents an ordered list of Operations.
Operation * getTerminator()
Get the terminator operation of this block.
bool mightHaveTerminator()
Return "true" if this block might have a terminator.
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
This class is a general helper class for creating context-global objects like types,...
IntegerAttr getIndexAttr(int64_t value)
IntegerType getIntegerType(unsigned width)
BoolAttr getBoolAttr(bool value)
IRValueT get() const
Return the current value being used by this operand.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This is a builder type that keeps local references to arguments.
Builder & setShape(ArrayRef< int64_t > newShape)
Builder & setLayout(MemRefLayoutAttrInterface newLayout)
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region ®ion, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
ParseResult parseTrailingOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None)
Parse zero or more trailing SSA comma-separated trailing operand references with a specified surround...
virtual ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printOperands(const ContainerType &container)
Print a comma separated list of operands.
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
This class helps build Operations.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
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.
unsigned getOperandNumber() const
Return which operand this is in the OpOperand list of the Operation.
A trait of region holding operations that define a new scope for automatic allocations,...
This trait indicates that the memory effects of an operation includes the effects of operations neste...
type_range getType() const
Operation is the basic unit of execution within MLIR.
void replaceUsesOfWith(Value from, Value to)
Replace any uses of 'from' with 'to' within this operation.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Block * getBlock()
Returns the operation block that contains this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
MutableArrayRef< OpOperand > getOpOperands()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
Region * getParentRegion()
Returns the region to which the instruction belongs.
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...
Type-safe wrapper around a void* for passing properties, including the properties structs of operatio...
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
This class provides an abstraction over the different types of ranges over Regions.
This class represents a successor of a region.
bool isOperation() const
Return true if the successor is an operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
bool hasOneBlock()
Return true if this region has exactly one block.
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...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={})
Inline the operations of block 'source' into block 'dest' before the given position.
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.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
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...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
This class provides an abstraction over the different types of ranges over Values.
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.
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 WalkResult advance()
static WalkResult interrupt()
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
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
FailureOr< std::optional< SmallVector< Value > > > bubbleDownInPlaceMemorySpaceCastImpl(OpOperand &operand, ValueRange results)
Tries to bubble-down inplace a MemorySpaceCastOpInterface operation referenced by operand.
ConstantIntRanges inferAdd(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)
ConstantIntRanges inferMul(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)
ConstantIntRanges inferShapedDimOpInterface(ShapedDimOpInterface op, const IntegerValueRange &maybeDim)
Returns the integer range for the result of a ShapedDimOpInterface given the optional inferred ranges...
Type getTensorTypeFromMemRefType(Type type)
Return an unranked/ranked tensor type for the given unranked/ranked memref type.
OpFoldResult getMixedSize(OpBuilder &builder, Location loc, Value value, int64_t dim)
Return the dimension of the given memref value.
LogicalResult foldMemRefCast(Operation *op, Value inner=nullptr)
This is a common utility used for patterns of the form "someop(memref.cast) -> someop".
SmallVector< OpFoldResult > getMixedSizes(OpBuilder &builder, Location loc, Value value)
Return the dimensions of the given memref value.
Value createCanonicalRankReducingSubViewOp(OpBuilder &b, Location loc, Value memref, ArrayRef< int64_t > targetShape)
Create a rank-reducing SubViewOp @[0 .
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.
MemRefType getMemRefType(T &&t)
Convenience method to abbreviate casting getType().
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...
SliceVerificationResult
Enum that captures information related to verifier error conditions on slice insert/extract type of o...
constexpr StringRef getReassociationAttrName()
Attribute name for the ArrayAttr which encodes reassociation indices.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
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.
SmallVector< Range, 8 > getOrCreateRanges(OffsetSizeAndStrideOpInterface op, OpBuilder &b, Location loc)
Return the list of Range (i.e.
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>>.
bool isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
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.
SmallVector< SmallVector< OpFoldResult > > ReifiedRankedShapedTypeDims
SmallVector< IntegerValueRange > getIntValueRanges(ArrayRef< OpFoldResult > values, GetIntRangeFn getIntRange, int32_t indexBitwidth)
Helper function to collect the integer range values of an array of op fold results.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
bool isZeroInteger(OpFoldResult v)
Return "true" if v is an integer value/attribute with constant value 0.
bool hasValidStrides(SmallVector< int64_t > strides)
Helper function to check whether the passed in strides are valid.
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.
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.
LogicalResult verifyElementTypesMatch(Operation *op, ShapedType lhs, ShapedType rhs, StringRef lhsName, StringRef rhsName)
Verify that two shaped types have matching element types.
SmallVector< T > applyPermutationMap(AffineMap map, llvm::ArrayRef< T > source)
Apply a permutation from map to source and return the result.
OpFoldResult getAsOpFoldResult(Value val)
Given a value, try to extract a constant Attribute.
function_ref< void(Value, const StridedMetadataRange &)> SetStridedMetadataRangeFn
Callback function type for setting the strided metadata of a value.
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...
SmallVector< int64_t, 2 > ReassociationIndices
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
bool isOneInteger(OpFoldResult v)
Return true if v is an IntegerAttr with value 1.
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.
function_ref< IntegerValueRange(Value)> GetIntRangeFn
Helper callback type to get the integer range of a value.
Move allocations into an allocation scope, if it is legal to move them (e.g.
LogicalResult matchAndRewrite(AllocaScopeOp op, PatternRewriter &rewriter) const override
Inline an AllocaScopeOp if either the direct parent is an allocation scope or it contains no allocati...
LogicalResult matchAndRewrite(AllocaScopeOp op, PatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(CollapseShapeOp op, PatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(ExpandShapeOp op, PatternRewriter &rewriter) const override
A canonicalizer wrapper to replace SubViewOps.
void operator()(PatternRewriter &rewriter, SubViewOp op, SubViewOp newOp)
Return the canonical type of the result of a subview.
MemRefType operator()(SubViewOp op, ArrayRef< OpFoldResult > mixedOffsets, ArrayRef< OpFoldResult > mixedSizes, ArrayRef< OpFoldResult > mixedStrides)
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
This represents an operation in an abstracted form, suitable for use with the builder APIs.
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...
static SaturatedInteger wrap(int64_t v)
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.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.