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);
2898 buildPropertiesAndDiscardableAttributes(
result, attrs);
2899 result.getOrAddProperties<Properties>().reassociation =
2902 result.addTypes(resultType);
2905LogicalResult CollapseShapeOp::verify() {
2906 MemRefType srcType = getSrcType();
2907 MemRefType resultType = getResultType();
2909 if (srcType.getRank() < resultType.getRank()) {
2910 auto r0 = srcType.getRank();
2911 auto r1 = resultType.getRank();
2912 return emitOpError(
"has source rank ")
2913 << r0 <<
" and result rank " << r1 <<
". This is not a collapse ("
2914 << r0 <<
" < " << r1 <<
").";
2919 srcType.getShape(), getReassociationIndices(),
2924 MemRefType expectedResultType;
2925 if (srcType.getLayout().isIdentity()) {
2928 MemRefLayoutAttrInterface layout;
2929 expectedResultType =
2930 MemRefType::get(resultType.getShape(), srcType.getElementType(), layout,
2931 srcType.getMemorySpace());
2936 FailureOr<StridedLayoutAttr> computedLayout =
2938 if (
failed(computedLayout))
2940 "invalid source layout map or collapsing non-contiguous dims");
2941 expectedResultType =
2942 MemRefType::get(resultType.getShape(), srcType.getElementType(),
2943 *computedLayout, srcType.getMemorySpace());
2946 if (expectedResultType != resultType)
2947 return emitOpError(
"expected collapsed type to be ")
2948 << expectedResultType <<
" but found " << resultType;
2960 auto cast = op.getOperand().getDefiningOp<CastOp>();
2964 if (!CastOp::canFoldIntoConsumerOp(cast))
2967 Type newResultType = CollapseShapeOp::computeCollapsedType(
2968 llvm::cast<MemRefType>(cast.getOperand().getType()),
2969 op.getReassociationIndices());
2971 if (newResultType == op.getResultType()) {
2973 op, [&]() { op.getSrcMutable().assign(cast.getSource()); });
2976 CollapseShapeOp::create(rewriter, op->getLoc(), cast.getSource(),
2977 op.getReassociationIndices());
2984void CollapseShapeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2985 MLIRContext *context) {
2987 ComposeReassociativeReshapeOps<CollapseShapeOp, ReshapeOpKind::kCollapse>,
2988 ComposeCollapseOfExpandOp<CollapseShapeOp, ExpandShapeOp, CastOp,
2989 memref::DimOp, MemRefType>,
2990 CollapseShapeOpMemRefCastFolder>(context);
2993OpFoldResult ExpandShapeOp::fold(FoldAdaptor adaptor) {
2995 adaptor.getOperands());
2998OpFoldResult CollapseShapeOp::fold(FoldAdaptor adaptor) {
3000 adaptor.getOperands());
3003FailureOr<std::optional<SmallVector<Value>>>
3004CollapseShapeOp::bubbleDownCasts(OpBuilder &builder) {
3012void ReshapeOp::getAsmResultNames(
3014 setNameFn(getResult(),
"reshape");
3017LogicalResult ReshapeOp::verify() {
3018 Type operandType = getSource().getType();
3019 Type resultType = getResult().getType();
3021 Type operandElementType =
3022 llvm::cast<ShapedType>(operandType).getElementType();
3023 Type resultElementType = llvm::cast<ShapedType>(resultType).getElementType();
3024 if (operandElementType != resultElementType)
3025 return emitOpError(
"element types of source and destination memref "
3026 "types should be the same");
3028 if (
auto operandMemRefType = llvm::dyn_cast<MemRefType>(operandType))
3029 if (!operandMemRefType.getLayout().isIdentity())
3030 return emitOpError(
"source memref type should have identity affine map");
3034 auto resultMemRefType = llvm::dyn_cast<MemRefType>(resultType);
3035 if (resultMemRefType) {
3036 if (!resultMemRefType.getLayout().isIdentity())
3037 return emitOpError(
"result memref type should have identity affine map");
3038 if (shapeSize == ShapedType::kDynamic)
3039 return emitOpError(
"cannot use shape operand with dynamic length to "
3040 "reshape to statically-ranked memref type");
3041 if (shapeSize != resultMemRefType.getRank())
3043 "length of shape operand differs from the result's memref rank");
3048FailureOr<std::optional<SmallVector<Value>>>
3049ReshapeOp::bubbleDownCasts(OpBuilder &builder) {
3057LogicalResult StoreOp::fold(FoldAdaptor adaptor,
3058 SmallVectorImpl<OpFoldResult> &results) {
3065std::optional<SmallVector<Value>>
3066StoreOp::updateMemrefAndIndices(RewriterBase &rewriter, Value newMemref,
3069 getMemrefMutable().assign(newMemref);
3070 getIndicesMutable().assign(newIndices);
3072 return std::nullopt;
3075FailureOr<std::optional<SmallVector<Value>>>
3076StoreOp::bubbleDownCasts(OpBuilder &builder) {
3085void SubViewOp::getAsmResultNames(
3087 setNameFn(getResult(),
"subview");
3093MemRefType SubViewOp::inferResultType(MemRefType sourceMemRefType,
3094 ArrayRef<int64_t> staticOffsets,
3095 ArrayRef<int64_t> staticSizes,
3096 ArrayRef<int64_t> staticStrides) {
3097 unsigned rank = sourceMemRefType.getRank();
3099 assert(staticOffsets.size() == rank &&
"staticOffsets length mismatch");
3100 assert(staticSizes.size() == rank &&
"staticSizes length mismatch");
3101 assert(staticStrides.size() == rank &&
"staticStrides length mismatch");
3104 auto [sourceStrides, sourceOffset] = sourceMemRefType.getStridesAndOffset();
3108 int64_t targetOffset = sourceOffset;
3109 for (
auto it : llvm::zip(staticOffsets, sourceStrides)) {
3110 auto staticOffset = std::get<0>(it), sourceStride = std::get<1>(it);
3119 SmallVector<int64_t, 4> targetStrides;
3120 targetStrides.reserve(staticOffsets.size());
3121 for (
auto it : llvm::zip(sourceStrides, staticStrides)) {
3122 auto sourceStride = std::get<0>(it), staticStride = std::get<1>(it);
3129 return MemRefType::get(staticSizes, sourceMemRefType.getElementType(),
3130 StridedLayoutAttr::get(sourceMemRefType.getContext(),
3131 targetOffset, targetStrides),
3132 sourceMemRefType.getMemorySpace());
3135MemRefType SubViewOp::inferResultType(MemRefType sourceMemRefType,
3136 ArrayRef<OpFoldResult> offsets,
3137 ArrayRef<OpFoldResult> sizes,
3138 ArrayRef<OpFoldResult> strides) {
3139 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
3140 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
3150 return SubViewOp::inferResultType(sourceMemRefType, staticOffsets,
3151 staticSizes, staticStrides);
3154MemRefType SubViewOp::inferRankReducedResultType(
3155 ArrayRef<int64_t> resultShape, MemRefType sourceRankedTensorType,
3156 ArrayRef<int64_t> offsets, ArrayRef<int64_t> sizes,
3157 ArrayRef<int64_t> strides) {
3158 MemRefType inferredType =
3159 inferResultType(sourceRankedTensorType, offsets, sizes, strides);
3160 assert(inferredType.getRank() >=
static_cast<int64_t
>(resultShape.size()) &&
3162 if (inferredType.getRank() ==
static_cast<int64_t
>(resultShape.size()))
3163 return inferredType;
3166 std::optional<llvm::SmallDenseSet<unsigned>> dimsToProject =
3168 assert(dimsToProject.has_value() &&
"invalid rank reduction");
3171 auto inferredLayout = llvm::cast<StridedLayoutAttr>(inferredType.getLayout());
3172 SmallVector<int64_t> rankReducedStrides;
3173 rankReducedStrides.reserve(resultShape.size());
3174 for (
auto [idx, value] : llvm::enumerate(inferredLayout.getStrides())) {
3175 if (!dimsToProject->contains(idx))
3176 rankReducedStrides.push_back(value);
3178 return MemRefType::get(resultShape, inferredType.getElementType(),
3179 StridedLayoutAttr::get(inferredLayout.getContext(),
3180 inferredLayout.getOffset(),
3181 rankReducedStrides),
3182 inferredType.getMemorySpace());
3185MemRefType SubViewOp::inferRankReducedResultType(
3186 ArrayRef<int64_t> resultShape, MemRefType sourceRankedTensorType,
3187 ArrayRef<OpFoldResult> offsets, ArrayRef<OpFoldResult> sizes,
3188 ArrayRef<OpFoldResult> strides) {
3189 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
3190 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
3194 return SubViewOp::inferRankReducedResultType(
3195 resultShape, sourceRankedTensorType, staticOffsets, staticSizes,
3201void SubViewOp::build(OpBuilder &
b, OperationState &
result,
3202 MemRefType resultType, Value source,
3203 ArrayRef<OpFoldResult> offsets,
3204 ArrayRef<OpFoldResult> sizes,
3205 ArrayRef<OpFoldResult> strides,
3206 ArrayRef<NamedAttribute> attrs) {
3207 SmallVector<int64_t> staticOffsets, staticSizes, staticStrides;
3208 SmallVector<Value> dynamicOffsets, dynamicSizes, dynamicStrides;
3212 auto sourceMemRefType = llvm::cast<MemRefType>(source.
getType());
3215 resultType = SubViewOp::inferResultType(sourceMemRefType, staticOffsets,
3216 staticSizes, staticStrides);
3218 result.addAttributes(attrs);
3219 build(
b,
result, resultType, source, dynamicOffsets, dynamicSizes,
3220 dynamicStrides,
b.getDenseI64ArrayAttr(staticOffsets),
3221 b.getDenseI64ArrayAttr(staticSizes),
3222 b.getDenseI64ArrayAttr(staticStrides));
3227void SubViewOp::build(OpBuilder &
b, OperationState &
result, Value source,
3228 ArrayRef<OpFoldResult> offsets,
3229 ArrayRef<OpFoldResult> sizes,
3230 ArrayRef<OpFoldResult> strides,
3231 ArrayRef<NamedAttribute> attrs) {
3232 build(
b,
result, MemRefType(), source, offsets, sizes, strides, attrs);
3236void SubViewOp::build(OpBuilder &
b, OperationState &
result, Value source,
3237 ArrayRef<int64_t> offsets, ArrayRef<int64_t> sizes,
3238 ArrayRef<int64_t> strides,
3239 ArrayRef<NamedAttribute> attrs) {
3240 SmallVector<OpFoldResult> offsetValues =
3241 llvm::map_to_vector<4>(offsets, [&](int64_t v) -> OpFoldResult {
3242 return b.getI64IntegerAttr(v);
3244 SmallVector<OpFoldResult> sizeValues = llvm::map_to_vector<4>(
3245 sizes, [&](int64_t v) -> OpFoldResult {
return b.getI64IntegerAttr(v); });
3246 SmallVector<OpFoldResult> strideValues =
3247 llvm::map_to_vector<4>(strides, [&](int64_t v) -> OpFoldResult {
3248 return b.getI64IntegerAttr(v);
3250 build(
b,
result, source, offsetValues, sizeValues, strideValues, attrs);
3255void SubViewOp::build(OpBuilder &
b, OperationState &
result,
3256 MemRefType resultType, Value source,
3257 ArrayRef<int64_t> offsets, ArrayRef<int64_t> sizes,
3258 ArrayRef<int64_t> strides,
3259 ArrayRef<NamedAttribute> attrs) {
3260 SmallVector<OpFoldResult> offsetValues =
3261 llvm::map_to_vector<4>(offsets, [&](int64_t v) -> OpFoldResult {
3262 return b.getI64IntegerAttr(v);
3264 SmallVector<OpFoldResult> sizeValues = llvm::map_to_vector<4>(
3265 sizes, [&](int64_t v) -> OpFoldResult {
return b.getI64IntegerAttr(v); });
3266 SmallVector<OpFoldResult> strideValues =
3267 llvm::map_to_vector<4>(strides, [&](int64_t v) -> OpFoldResult {
3268 return b.getI64IntegerAttr(v);
3270 build(
b,
result, resultType, source, offsetValues, sizeValues, strideValues,
3276void SubViewOp::build(OpBuilder &
b, OperationState &
result,
3277 MemRefType resultType, Value source,
ValueRange offsets,
3279 ArrayRef<NamedAttribute> attrs) {
3280 SmallVector<OpFoldResult> offsetValues = llvm::map_to_vector<4>(
3281 offsets, [](Value v) -> OpFoldResult {
return v; });
3282 SmallVector<OpFoldResult> sizeValues =
3283 llvm::map_to_vector<4>(sizes, [](Value v) -> OpFoldResult {
return v; });
3284 SmallVector<OpFoldResult> strideValues = llvm::map_to_vector<4>(
3285 strides, [](Value v) -> OpFoldResult {
return v; });
3286 build(
b,
result, resultType, source, offsetValues, sizeValues, strideValues);
3290void SubViewOp::build(OpBuilder &
b, OperationState &
result, Value source,
3292 ArrayRef<NamedAttribute> attrs) {
3293 build(
b,
result, MemRefType(), source, offsets, sizes, strides, attrs);
3297Value SubViewOp::getViewSource() {
return getSource(); }
3304 auto res1 = t1.getStridesAndOffset(t1Strides, t1Offset);
3305 auto res2 = t2.getStridesAndOffset(t2Strides, t2Offset);
3306 return succeeded(res1) && succeeded(res2) && t1Offset == t2Offset;
3313 const llvm::SmallBitVector &droppedDims) {
3314 assert(
size_t(t1.getRank()) == droppedDims.size() &&
3315 "incorrect number of bits");
3316 assert(
size_t(t1.getRank() - t2.getRank()) == droppedDims.count() &&
3317 "incorrect number of dropped dims");
3320 auto res1 = t1.getStridesAndOffset(t1Strides, t1Offset);
3321 auto res2 = t2.getStridesAndOffset(t2Strides, t2Offset);
3322 if (failed(res1) || failed(res2))
3324 for (
int64_t i = 0,
j = 0, e = t1.getRank(); i < e; ++i) {
3327 if (t1Strides[i] != t2Strides[
j])
3335 SubViewOp op,
Type expectedType) {
3336 auto memrefType = llvm::cast<ShapedType>(expectedType);
3341 return op->emitError(
"expected result rank to be smaller or equal to ")
3342 <<
"the source rank, but got " << op.getType();
3344 return op->emitError(
"expected result type to be ")
3346 <<
" or a rank-reduced version. (mismatch of result sizes), but got "
3349 return op->emitError(
"expected result element type to be ")
3350 << memrefType.getElementType() <<
", but got " << op.getType();
3352 return op->emitError(
3353 "expected result and source memory spaces to match, but got ")
3356 return op->emitError(
"expected result type to be ")
3358 <<
" or a rank-reduced version. (mismatch of result layout), but "
3362 llvm_unreachable(
"unexpected subview verification result");
3366LogicalResult SubViewOp::verify() {
3367 MemRefType baseType = getSourceType();
3368 MemRefType subViewType =
getType();
3369 ArrayRef<int64_t> staticOffsets = getStaticOffsets();
3370 ArrayRef<int64_t> staticSizes = getStaticSizes();
3371 ArrayRef<int64_t> staticStrides = getStaticStrides();
3374 if (baseType.getMemorySpace() != subViewType.getMemorySpace())
3375 return emitError(
"different memory spaces specified for base memref "
3377 << baseType <<
" and subview memref type " << subViewType;
3380 if (!baseType.isStrided())
3381 return emitError(
"base type ") << baseType <<
" is not strided";
3385 MemRefType expectedType = SubViewOp::inferResultType(
3386 baseType, staticOffsets, staticSizes, staticStrides);
3391 expectedType, subViewType);
3396 if (expectedType.getMemorySpace() != subViewType.getMemorySpace())
3398 *
this, expectedType);
3403 *
this, expectedType);
3413 *
this, expectedType);
3418 *
this, expectedType);
3422 SliceBoundsVerificationResult boundsResult =
3424 staticStrides,
true);
3426 return getOperation()->emitError(boundsResult.
errorMessage);
3432 return os <<
"range " << range.
offset <<
":" << range.
size <<
":"
3441 std::array<unsigned, 3> ranks = op.getArrayAttrMaxRanks();
3442 assert(ranks[0] == ranks[1] &&
"expected offset and sizes of equal ranks");
3443 assert(ranks[1] == ranks[2] &&
"expected sizes and strides of equal ranks");
3445 unsigned rank = ranks[0];
3447 for (
unsigned idx = 0; idx < rank; ++idx) {
3449 op.isDynamicOffset(idx)
3450 ? op.getDynamicOffset(idx)
3453 op.isDynamicSize(idx)
3454 ? op.getDynamicSize(idx)
3457 op.isDynamicStride(idx)
3458 ? op.getDynamicStride(idx)
3460 res.emplace_back(
Range{offset, size, stride});
3473 MemRefType currentResultType, MemRefType currentSourceType,
3476 MemRefType nonRankReducedType = SubViewOp::inferResultType(
3477 sourceType, mixedOffsets, mixedSizes, mixedStrides);
3479 currentSourceType, currentResultType, mixedSizes);
3480 if (failed(unusedDims))
3483 auto layout = llvm::cast<StridedLayoutAttr>(nonRankReducedType.getLayout());
3485 unsigned numDimsAfterReduction =
3486 nonRankReducedType.getRank() - unusedDims->count();
3487 shape.reserve(numDimsAfterReduction);
3488 strides.reserve(numDimsAfterReduction);
3489 for (
const auto &[idx, size, stride] :
3490 llvm::zip(llvm::seq<unsigned>(0, nonRankReducedType.getRank()),
3491 nonRankReducedType.getShape(), layout.getStrides())) {
3492 if (unusedDims->test(idx))
3494 shape.push_back(size);
3495 strides.push_back(stride);
3498 return MemRefType::get(
shape, nonRankReducedType.getElementType(),
3499 StridedLayoutAttr::get(sourceType.getContext(),
3500 layout.getOffset(), strides),
3501 nonRankReducedType.getMemorySpace());
3506 auto memrefType = llvm::cast<MemRefType>(
memref.getType());
3507 unsigned rank = memrefType.getRank();
3511 MemRefType targetType = SubViewOp::inferRankReducedResultType(
3512 targetShape, memrefType, offsets, sizes, strides);
3513 return b.createOrFold<memref::SubViewOp>(loc, targetType,
memref, offsets,
3520 auto sourceMemrefType = llvm::dyn_cast<MemRefType>(value.
getType());
3521 assert(sourceMemrefType &&
"not a ranked memref type");
3522 auto sourceShape = sourceMemrefType.getShape();
3523 if (sourceShape.equals(desiredShape))
3525 auto maybeRankReductionMask =
3527 if (!maybeRankReductionMask)
3537 if (subViewOp.getSourceType().getRank() != subViewOp.getType().getRank())
3540 auto mixedOffsets = subViewOp.getMixedOffsets();
3541 auto mixedSizes = subViewOp.getMixedSizes();
3542 auto mixedStrides = subViewOp.getMixedStrides();
3547 return !intValue || intValue.value() != 0;
3554 return !intValue || intValue.value() != 1;
3560 for (
const auto &size : llvm::enumerate(mixedSizes)) {
3562 if (!intValue || *intValue != sourceShape[size.index()])
3586class SubViewOpMemRefCastFolder final :
public OpRewritePattern<SubViewOp> {
3588 using OpRewritePattern<SubViewOp>::OpRewritePattern;
3590 LogicalResult matchAndRewrite(SubViewOp subViewOp,
3591 PatternRewriter &rewriter)
const override {
3594 if (llvm::any_of(subViewOp.getOperands(), [](Value operand) {
3595 return matchPattern(operand, matchConstantIndex());
3599 auto castOp = subViewOp.getSource().getDefiningOp<CastOp>();
3603 if (!CastOp::canFoldIntoConsumerOp(castOp))
3611 subViewOp.getType(), subViewOp.getSourceType(),
3612 llvm::cast<MemRefType>(castOp.getSource().getType()),
3613 subViewOp.getMixedOffsets(), subViewOp.getMixedSizes(),
3614 subViewOp.getMixedStrides());
3618 Value newSubView = SubViewOp::create(
3619 rewriter, subViewOp.getLoc(), resultType, castOp.getSource(),
3620 subViewOp.getOffsets(), subViewOp.getSizes(), subViewOp.getStrides(),
3621 subViewOp.getStaticOffsets(), subViewOp.getStaticSizes(),
3622 subViewOp.getStaticStrides());
3631class TrivialSubViewOpFolder final :
public OpRewritePattern<SubViewOp> {
3633 using OpRewritePattern<SubViewOp>::OpRewritePattern;
3635 LogicalResult matchAndRewrite(SubViewOp subViewOp,
3636 PatternRewriter &rewriter)
const override {
3639 if (subViewOp.getSourceType() == subViewOp.getType()) {
3640 rewriter.
replaceOp(subViewOp, subViewOp.getSource());
3644 subViewOp.getSource());
3656 MemRefType resTy = SubViewOp::inferResultType(
3657 op.getSourceType(), mixedOffsets, mixedSizes, mixedStrides);
3660 MemRefType nonReducedType = resTy;
3663 llvm::SmallBitVector droppedDims = op.getDroppedDims();
3664 if (droppedDims.none())
3665 return nonReducedType;
3668 auto [nonReducedStrides, offset] = nonReducedType.getStridesAndOffset();
3673 for (
int64_t i = 0; i < static_cast<int64_t>(mixedSizes.size()); ++i) {
3674 if (droppedDims.test(i))
3676 targetStrides.push_back(nonReducedStrides[i]);
3677 targetShape.push_back(nonReducedType.getDimSize(i));
3680 return MemRefType::get(targetShape, nonReducedType.getElementType(),
3681 StridedLayoutAttr::get(nonReducedType.getContext(),
3682 offset, targetStrides),
3683 nonReducedType.getMemorySpace());
3694void SubViewOp::getCanonicalizationPatterns(RewritePatternSet &results,
3695 MLIRContext *context) {
3697 .
add<OpWithOffsetSizesAndStridesConstantArgumentFolder<
3698 SubViewOp, SubViewReturnTypeCanonicalizer, SubViewCanonicalizer>,
3699 SubViewOpMemRefCastFolder, TrivialSubViewOpFolder>(context);
3702OpFoldResult SubViewOp::fold(FoldAdaptor adaptor) {
3703 MemRefType sourceMemrefType = getSource().getType();
3704 MemRefType resultMemrefType = getResult().getType();
3706 dyn_cast_if_present<StridedLayoutAttr>(resultMemrefType.getLayout());
3708 if (resultMemrefType == sourceMemrefType &&
3709 resultMemrefType.hasStaticShape() &&
3710 (!resultLayout || resultLayout.hasStaticLayout())) {
3711 return getViewSource();
3717 if (
auto srcSubview = getViewSource().getDefiningOp<SubViewOp>()) {
3718 auto srcSizes = srcSubview.getMixedSizes();
3720 auto offsets = getMixedOffsets();
3722 auto strides = getMixedStrides();
3723 bool allStridesOne = llvm::all_of(strides,
isOneInteger);
3724 bool allSizesSame = llvm::equal(sizes, srcSizes);
3725 if (allOffsetsZero && allStridesOne && allSizesSame &&
3726 resultMemrefType == sourceMemrefType)
3727 return getViewSource();
3733FailureOr<std::optional<SmallVector<Value>>>
3734SubViewOp::bubbleDownCasts(OpBuilder &builder) {
3738void SubViewOp::inferStridedMetadataRanges(
3739 ArrayRef<StridedMetadataRange> ranges,
GetIntRangeFn getIntRange,
3741 auto isUninitialized =
3742 +[](IntegerValueRange range) {
return range.isUninitialized(); };
3745 SmallVector<IntegerValueRange> offsetOperands =
3747 if (llvm::any_of(offsetOperands, isUninitialized))
3750 SmallVector<IntegerValueRange> sizeOperands =
3752 if (llvm::any_of(sizeOperands, isUninitialized))
3755 SmallVector<IntegerValueRange> stridesOperands =
3757 if (llvm::any_of(stridesOperands, isUninitialized))
3760 StridedMetadataRange sourceRange =
3761 ranges[getSourceMutable().getOperandNumber()];
3765 ArrayRef<ConstantIntRanges> srcStrides = sourceRange.
getStrides();
3771 ConstantIntRanges offset = sourceRange.
getOffsets()[0];
3772 SmallVector<ConstantIntRanges> strides, sizes;
3774 for (
size_t i = 0, e = droppedDims.size(); i < e; ++i) {
3775 bool dropped = droppedDims.test(i);
3777 ConstantIntRanges off =
3788 sizes.push_back(sizeOperands[i].getValue());
3791 setMetadata(getResult(),
3793 SmallVector<ConstantIntRanges>({std::move(offset)}),
3794 std::move(sizes), std::move(strides)));
3801void TransposeOp::getAsmResultNames(
3803 setNameFn(getResult(),
"transpose");
3809 auto originalSizes = memRefType.getShape();
3810 auto [originalStrides, offset] = memRefType.getStridesAndOffset();
3811 assert(originalStrides.size() ==
static_cast<unsigned>(memRefType.getRank()));
3820 StridedLayoutAttr::get(memRefType.getContext(), offset, strides));
3823Value TransposeOp::getViewSource() {
return getIn(); }
3825void TransposeOp::build(OpBuilder &
b, OperationState &
result, Value in,
3826 AffineMapAttr permutation,
3827 ArrayRef<NamedAttribute> attrs) {
3828 auto permutationMap = permutation.getValue();
3829 assert(permutationMap);
3831 auto memRefType = llvm::cast<MemRefType>(in.
getType());
3835 buildPropertiesAndDiscardableAttributes(
result, attrs);
3836 result.getOrAddProperties<Properties>().permutation = permutation;
3838 result.addTypes(resultType);
3842void TransposeOp::print(OpAsmPrinter &p) {
3843 p <<
" " << getIn() <<
" " << getPermutation();
3845 {getPermutationAttrStrName()});
3846 p <<
" : " << getIn().getType() <<
" to " <<
getType();
3849ParseResult TransposeOp::parse(OpAsmParser &parser, OperationState &
result) {
3850 OpAsmParser::UnresolvedOperand in;
3851 AffineMap permutation;
3852 MemRefType srcType, dstType;
3861 result.addAttribute(TransposeOp::getPermutationAttrStrName(),
3862 AffineMapAttr::get(permutation));
3866LogicalResult TransposeOp::verify() {
3868 return emitOpError(
"expected a permutation map");
3869 if (getPermutation().getNumDims() != getIn().
getType().getRank())
3870 return emitOpError(
"expected a permutation map of same rank as the input");
3872 auto srcType = llvm::cast<MemRefType>(getIn().
getType());
3873 auto resultType = llvm::cast<MemRefType>(
getType());
3875 .canonicalizeStridedLayout();
3877 if (resultType.canonicalizeStridedLayout() != canonicalResultType)
3878 return emitOpError(
"result type ")
3880 <<
" is not equivalent to the canonical transposed input type "
3881 << canonicalResultType;
3885OpFoldResult TransposeOp::fold(FoldAdaptor) {
3888 if (getPermutation().isIdentity() &&
getType() == getIn().
getType())
3892 if (
auto otherTransposeOp = getIn().getDefiningOp<memref::TransposeOp>()) {
3893 AffineMap composedPermutation =
3894 getPermutation().compose(otherTransposeOp.getPermutation());
3895 getInMutable().assign(otherTransposeOp.getIn());
3896 setPermutation(composedPermutation);
3902FailureOr<std::optional<SmallVector<Value>>>
3903TransposeOp::bubbleDownCasts(OpBuilder &builder) {
3911void ViewOp::getAsmResultNames(
function_ref<
void(Value, StringRef)> setNameFn) {
3912 setNameFn(getResult(),
"view");
3915LogicalResult ViewOp::verify() {
3916 auto baseType = llvm::cast<MemRefType>(getOperand(0).
getType());
3920 if (!baseType.getLayout().isIdentity())
3921 return emitError(
"unsupported map for base memref type ") << baseType;
3924 if (!viewType.getLayout().isIdentity())
3925 return emitError(
"unsupported map for result memref type ") << viewType;
3928 if (baseType.getMemorySpace() != viewType.getMemorySpace())
3929 return emitError(
"different memory spaces specified for base memref "
3931 << baseType <<
" and view memref type " << viewType;
3940Value ViewOp::getViewSource() {
return getSource(); }
3942OpFoldResult ViewOp::fold(FoldAdaptor adaptor) {
3943 MemRefType sourceMemrefType = getSource().getType();
3944 MemRefType resultMemrefType = getResult().getType();
3946 if (resultMemrefType == sourceMemrefType &&
3947 resultMemrefType.hasStaticShape() &&
isZeroInteger(getByteShift()))
3948 return getViewSource();
3953SmallVector<OpFoldResult> ViewOp::getMixedSizes() {
3954 SmallVector<OpFoldResult>
result;
3958 if (ShapedType::isDynamic(dim)) {
3959 result.push_back(getSizes()[ctr++]);
3961 result.push_back(
b.getIndexAttr(dim));
3973 SmallVectorImpl<Value> &foldedDynamicSizes) {
3974 SmallVector<int64_t> staticShape(type.getShape());
3975 assert(type.getNumDynamicDims() == dynamicSizes.size() &&
3976 "incorrect number of dynamic sizes");
3980 for (
auto [dim, dimSize] : llvm::enumerate(type.getShape())) {
3981 if (ShapedType::isStatic(dimSize))
3984 Value dynamicSize = dynamicSizes[ctr++];
3987 if (cst.value() < 0) {
3988 foldedDynamicSizes.push_back(dynamicSize);
3991 staticShape[dim] = cst.value();
3993 foldedDynamicSizes.push_back(dynamicSize);
3997 return MemRefType::Builder(type).setShape(staticShape);
4011struct ViewOpShapeFolder :
public OpRewritePattern<ViewOp> {
4014 LogicalResult matchAndRewrite(ViewOp viewOp,
4015 PatternRewriter &rewriter)
const override {
4016 SmallVector<Value> foldedDynamicSizes;
4017 MemRefType resultType = viewOp.getType();
4019 resultType, viewOp.getSizes(), foldedDynamicSizes);
4022 if (foldedMemRefType == resultType)
4026 auto newViewOp = ViewOp::create(rewriter, viewOp.getLoc(), foldedMemRefType,
4027 viewOp.getSource(), viewOp.getByteShift(),
4028 foldedDynamicSizes);
4036struct ViewOpMemrefCastFolder :
public OpRewritePattern<ViewOp> {
4039 LogicalResult matchAndRewrite(ViewOp viewOp,
4040 PatternRewriter &rewriter)
const override {
4041 auto memrefCastOp = viewOp.getSource().getDefiningOp<CastOp>();
4046 viewOp, viewOp.getType(), memrefCastOp.getSource(),
4047 viewOp.getByteShift(), viewOp.getSizes());
4053void ViewOp::getCanonicalizationPatterns(RewritePatternSet &results,
4054 MLIRContext *context) {
4055 results.
add<ViewOpShapeFolder, ViewOpMemrefCastFolder>(context);
4058FailureOr<std::optional<SmallVector<Value>>>
4059ViewOp::bubbleDownCasts(OpBuilder &builder) {
4067LogicalResult AtomicRMWOp::verify() {
4068 switch (getKind()) {
4069 case arith::AtomicRMWKind::addf:
4070 case arith::AtomicRMWKind::maximumf:
4071 case arith::AtomicRMWKind::minimumf:
4072 case arith::AtomicRMWKind::mulf:
4073 if (!llvm::isa<FloatType>(getValue().
getType()))
4074 return emitOpError() <<
"with kind '"
4075 << arith::stringifyAtomicRMWKind(getKind())
4076 <<
"' expects a floating-point type";
4078 case arith::AtomicRMWKind::addi:
4079 case arith::AtomicRMWKind::maxs:
4080 case arith::AtomicRMWKind::maxu:
4081 case arith::AtomicRMWKind::mins:
4082 case arith::AtomicRMWKind::minu:
4083 case arith::AtomicRMWKind::muli:
4084 case arith::AtomicRMWKind::ori:
4085 case arith::AtomicRMWKind::xori:
4086 case arith::AtomicRMWKind::andi:
4087 if (!llvm::isa<IntegerType>(getValue().
getType()))
4088 return emitOpError() <<
"with kind '"
4089 << arith::stringifyAtomicRMWKind(getKind())
4090 <<
"' expects an integer type";
4098OpFoldResult AtomicRMWOp::fold(FoldAdaptor adaptor) {
4102 return OpFoldResult();
4105FailureOr<std::optional<SmallVector<Value>>>
4106AtomicRMWOp::bubbleDownCasts(OpBuilder &builder) {
4113std::optional<SmallVector<Value>>
4114AtomicRMWOp::updateMemrefAndIndices(RewriterBase &rewriter, Value newMemref,
4117 getMemrefMutable().assign(newMemref);
4118 getIndicesMutable().assign(newIndices);
4120 return std::nullopt;
4127#define GET_OP_CLASSES
4128#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...
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.