From 0bd6390b541e8a95ee4d2fc8abcdcaf1d7c580cb Mon Sep 17 00:00:00 2001 From: Nicolas Vasilache Date: Wed, 13 Nov 2019 12:09:40 -0800 Subject: [PATCH] Deprecate linalg.subview in favor of std.subview This CL uses the now standard std.subview in linalg. Two shortcuts are currently taken to allow this port: 1. the type resulting from a view is currently degraded to fully dynamic to pass the SubViewOp verifier. 2. indexing into SubViewOp may access out of bounds since lowering to LLVM does not currently enforce it by construction. These will be fixed in subsequent commits after discussions. PiperOrigin-RevId: 280250129 --- mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.h | 1 - mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.td | 64 -------- mlir/include/mlir/Dialect/Linalg/Utils/Utils.h | 5 +- mlir/include/mlir/Dialect/StandardOps/Ops.h | 2 + mlir/include/mlir/Dialect/StandardOps/Ops.td | 16 +- mlir/include/mlir/IR/StandardTypes.h | 14 +- .../Dialect/Linalg/Analysis/DependenceAnalysis.cpp | 2 +- mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp | 74 --------- mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp | 42 ++--- .../Linalg/Transforms/LowerToLLVMDialect.cpp | 22 +-- mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp | 27 +-- mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp | 61 +++---- mlir/lib/Dialect/Linalg/Utils/Utils.cpp | 9 +- mlir/lib/Dialect/StandardOps/Ops.cpp | 54 ++++++ mlir/lib/IR/StandardTypes.cpp | 2 + .../Conversion/LoopsToGPU/imperfect_linalg.mlir | 26 +-- mlir/test/Dialect/Linalg/fusion-2-level.mlir | 35 ++-- mlir/test/Dialect/Linalg/fusion.mlir | 100 +++++------- mlir/test/Dialect/Linalg/invalid.mlir | 8 - mlir/test/Dialect/Linalg/llvm.mlir | 33 +--- mlir/test/Dialect/Linalg/promote.mlir | 29 ++-- mlir/test/Dialect/Linalg/roundtrip.mlir | 10 -- mlir/test/Dialect/Linalg/tile.mlir | 181 +++++++++++---------- mlir/test/Dialect/Linalg/tile_conv.mlir | 36 ++-- 24 files changed, 335 insertions(+), 518 deletions(-) diff --git a/mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.h b/mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.h index b1dbdf3..0e4201c 100644 --- a/mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.h +++ b/mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.h @@ -85,7 +85,6 @@ SmallVector loopToOperandRangesMaps(Operation *op); #define GET_OP_CLASSES #include "mlir/Dialect/Linalg/IR/LinalgLibraryOps.h.inc" -llvm::raw_ostream &operator<<(llvm::raw_ostream &os, SubViewOp::Range &range); } // namespace linalg } // namespace mlir diff --git a/mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.td b/mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.td index b7aca21..96974de 100644 --- a/mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.td +++ b/mlir/include/mlir/Dialect/Linalg/IR/LinalgOps.td @@ -131,70 +131,6 @@ def SliceOp : Linalg_Op<"slice", [NoSideEffect]>, }]; } -def SubViewOp : Linalg_Op<"subview", [NoSideEffect]>, - Arguments<(ins AnyStridedMemRef:$view, Variadic:$ranges)>, - Results<(outs AnyStridedMemRef)> { - let summary = "subview operation"; - let description = [{ - The "linalg.subview" op produces a linalg.view which is a subview of a given - base view. This allows defining a subregion within the underlying buffer. - - The "linalg.subview" operation takes a base view, a list of indices and - returns a new linalg.view of the same type that is contained within the - view. This operation is equivalent to a non-rank-reducing slice operation. - The main difference is the operands are all of type `index` and no - intermediate linalg.range operations are required. A "linalg.subview" is - thus a specialized linalg.slice with a higher level of abstraction. - - Similary to linalg.slice, if a range extends past the size of the base view, - the slice operation automatically truncates it to be within the bounds of - the view. - - Example: - - %1 = linalg.subview %0[%1, %2, %3, %4, %5, %6] : - memref - - }]; - // TODO(ntv) evolve syntax towards: - // linalg.subview %0[%1:%2:%3][%4:%5:%6] : - // memref - - let builders = [OpBuilder< - "Builder *b, OperationState &result, Value *buffer, " - "ArrayRef ranges, Type resultType = Type(), " - "ArrayRef attrs = {}">]; - - let verifier = [{ - auto rank = getViewType().getRank(); - if (getNumOperands() != 3 * rank + 1) - return emitOpError("expected a strided memref followed by ") << (3 * rank) - << " indices specifying a range for each dimension"; - return success(); - }]; - - let extraClassDeclaration = [{ - Value *getView() { return getOperand(0); } - MemRefType getViewType() { return getView()->getType().cast(); } - - struct Range { Value *min; Value *max; Value *step; }; - - Range getRange(unsigned i) { - return Range{ - getOperand(1 + 3*i), getOperand(1 + 3*i + 1), getOperand(1 + 3*i + 2)}; - } - - SmallVector getRanges() { - SmallVector res; - unsigned rank = getViewType().getRank(); - res.reserve(rank); - for (unsigned i = 0; i < rank; ++i) - res.push_back(getRange(i)); - return res; - } - }]; -} - def TransposeOp : Linalg_Op<"transpose", [NoSideEffect]>, Arguments<(ins AnyStridedMemRef:$view, AffineMapAttr:$permutation)>, Results<(outs AnyStridedMemRef)> { diff --git a/mlir/include/mlir/Dialect/Linalg/Utils/Utils.h b/mlir/include/mlir/Dialect/Linalg/Utils/Utils.h index 7e04aab..91c7082 100644 --- a/mlir/include/mlir/Dialect/Linalg/Utils/Utils.h +++ b/mlir/include/mlir/Dialect/Linalg/Utils/Utils.h @@ -20,6 +20,7 @@ #include "mlir/Dialect/Linalg/IR/LinalgOps.h" #include "mlir/Dialect/LoopOps/LoopOps.h" +#include "mlir/Dialect/StandardOps/Ops.h" #include "mlir/EDSC/Helpers.h" namespace mlir { @@ -40,7 +41,7 @@ public: /// *only* way to capture the loop induction variable. LoopRangeBuilder(ValueHandle *iv, ValueHandle range); LoopRangeBuilder(ValueHandle *iv, Value *range); - LoopRangeBuilder(ValueHandle *iv, linalg::SubViewOp::Range range); + LoopRangeBuilder(ValueHandle *iv, SubViewOp::Range range); LoopRangeBuilder(const LoopRangeBuilder &) = delete; LoopRangeBuilder(LoopRangeBuilder &&) = default; @@ -64,7 +65,7 @@ public: LoopNestRangeBuilder(llvm::ArrayRef ivs, llvm::ArrayRef ranges); LoopNestRangeBuilder(llvm::ArrayRef ivs, - llvm::ArrayRef ranges); + llvm::ArrayRef ranges); edsc::ValueHandle operator()(std::function fun = nullptr); private: diff --git a/mlir/include/mlir/Dialect/StandardOps/Ops.h b/mlir/include/mlir/Dialect/StandardOps/Ops.h index 31ebae3..fd69534 100644 --- a/mlir/include/mlir/Dialect/StandardOps/Ops.h +++ b/mlir/include/mlir/Dialect/StandardOps/Ops.h @@ -359,6 +359,8 @@ ParseResult parseDimAndSymbolList(OpAsmParser &parser, SmallVector &operands, unsigned &numDims); +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, SubViewOp::Range &range); + } // end namespace mlir #endif // MLIR_DIALECT_STANDARDOPS_OPS_H diff --git a/mlir/include/mlir/Dialect/StandardOps/Ops.td b/mlir/include/mlir/Dialect/StandardOps/Ops.td index 57d77f7..bfd2452 100644 --- a/mlir/include/mlir/Dialect/StandardOps/Ops.td +++ b/mlir/include/mlir/Dialect/StandardOps/Ops.td @@ -1251,7 +1251,7 @@ def SubViewOp : Std_Op<"subview", [SameVariadicOperandSize]> { // strides in each dimension, are represented in the view memref layout // map as symbols 's1', 's2' and 's3'. %1 = subview %0[%i, %j, %k][%size0, %size1, %size2][%x, %y, %z] - : memref<8x16x4xf32, (d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)> + : memref<8x16x4xf32, (d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)> to memref (d0 * s1 + d1 * s2 + d2 * s3 + s0)> } @@ -1261,6 +1261,12 @@ def SubViewOp : Std_Op<"subview", [SameVariadicOperandSize]> { Variadic:$sizes, Variadic:$strides); let results = (outs AnyMemRef); + let builders = [OpBuilder< + "Builder *b, OperationState &result, Value *source, " + "ArrayRef offsets, ArrayRef sizes, " + "ArrayRef strides, Type resultType = Type(), " + "ArrayRef attrs = {}">]; + let extraClassDeclaration = [{ /// The result of a subview is always a memref. MemRefType getType() { return getResult()->getType().cast(); } @@ -1287,6 +1293,14 @@ def SubViewOp : Std_Op<"subview", [SameVariadicOperandSize]> { return {operand_begin() + getStrideOperandsStart(), operand_begin() + getStrideOperandsStart() + getType().getRank()}; } + + // Auxiliary range data structure and helper function that unpacks the + // offset, size and stride operands of the SubViewOp into a list of triples. + // Such a list of triple is sometimes more convenient to manipulate. + struct Range { + Value *offset, *size, *stride; + }; + SmallVector getRanges(); }]; // TODO(andydavis) Add canonicalizer. diff --git a/mlir/include/mlir/IR/StandardTypes.h b/mlir/include/mlir/IR/StandardTypes.h index 9446fb7..264b165 100644 --- a/mlir/include/mlir/IR/StandardTypes.h +++ b/mlir/include/mlir/IR/StandardTypes.h @@ -186,6 +186,13 @@ public: using ImplType = detail::ShapedTypeStorage; using Type::Type; + // TODO(ntv): merge these two special values in a single one used everywhere. + // Unfortunately, uses of `-1` have crept deep into the codebase now and are + // hard to track. + static constexpr int64_t kDynamicSize = -1; + static constexpr int64_t kDynamicStrideOrOffset = + std::numeric_limits::min(); + /// Return the element type. Type getElementType() const; @@ -395,8 +402,12 @@ public: /// Returns the memory space in which data referred to by this memref resides. unsigned getMemorySpace() const; + // TODO(ntv): merge these two special values in a single one used everywhere. + // Unfortunately, uses of `-1` have crept deep into the codebase now and are + // hard to track. + static constexpr int64_t kDynamicSize = -1; static int64_t getDynamicStrideOrOffset() { - return std::numeric_limits::min(); + return ShapedType::kDynamicStrideOrOffset; } static bool kindof(unsigned kind) { return kind == StandardTypes::MemRef; } @@ -411,7 +422,6 @@ private: using Base::getImpl; }; - /// Tuple types represent a collection of other types. Note: This type merely /// provides a common mechanism for representing tuples in MLIR. It is up to /// dialect authors to provides operations for manipulating them, e.g. diff --git a/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp b/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp index 8772171..8eb18da 100644 --- a/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp +++ b/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp @@ -78,7 +78,7 @@ Value *Aliases::find(Value *v) { return it.first->second; } if (auto view = dyn_cast_or_null(v->getDefiningOp())) { - v = view.getView(); + v = view.source(); continue; } llvm::errs() << "View alias analysis reduces to: " << *v << "\n"; diff --git a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp index 06563ff..867b8ab2 100644 --- a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp +++ b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp @@ -344,73 +344,6 @@ static LogicalResult verify(SliceOp op) { } //===----------------------------------------------------------------------===// -// SubViewOp -//===----------------------------------------------------------------------===// -static Type getSubViewResultType(MemRefType memRefType) { - auto rank = memRefType.getRank(); - SmallVector sizes(rank, -1); - int64_t offset; - SmallVector strides; - Type elementType = memRefType.getElementType(); - auto res = getStridesAndOffset(memRefType, strides, offset); - assert(succeeded(res) && "SubViewOp expected strided memref type"); - (void)res; - // Assume sizes and offset are fully dynamic for now until canonicalization - // occurs on the ranges. - // Strides don't change though. - // TODO(ntv) for canonicalization it may be better to use a (min, size, step) - // instead of a (min, max, step) abstraction. - auto stridedLayout = makeStridedLinearLayoutMap( - strides, MemRefType::getDynamicStrideOrOffset(), memRefType.getContext()); - return MemRefType::get(sizes, elementType, stridedLayout, - memRefType.getMemorySpace()); -} - -void mlir::linalg::SubViewOp::build(Builder *b, OperationState &result, - Value *view, ArrayRef ranges, - Type resultType, - ArrayRef attrs) { - if (!resultType) - resultType = getSubViewResultType(view->getType().cast()); - build(b, result, resultType, view, ranges); - result.addAttributes(attrs); -} - -static void print(OpAsmPrinter &p, mlir::linalg::SubViewOp op) { - p << op.getOperationName() << " " << *op.getOperand(0) << "["; - auto ranges = op.getRanges(); - interleaveComma(ranges, p, [&p](const mlir::linalg::SubViewOp::Range &i) { - p << *i.min << ", " << *i.max << ", " << *i.step; - }); - p << "]"; - p.printOptionalAttrDict(op.getAttrs()); - p << " : " << op.getViewType(); -} - -static ParseResult parseSubViewOp(OpAsmParser &parser, OperationState &result) { - OpAsmParser::OperandType inputView, resultView; - MemRefType memRefType; - if (parser.parseOperand(inputView)) - return failure(); - - SmallVector ops; - // TODO(ntv) evolve parsing from - // linalg.subview %0[%1, %2, %3, %4, %5, %6] - // to something resembling - // linalg.subview %0[%1:%2:%3][%4:%5:%6] - if (parser.parseOperandList(ops, OpAsmParser::Delimiter::Square) || - parser.parseOptionalAttrDict(result.attributes) || - parser.parseColonType(memRefType)) - return failure(); - - auto indexTy = parser.getBuilder().getIndexType(); - return failure( - parser.resolveOperand(inputView, memRefType, result.operands) || - parser.resolveOperands(ops, indexTy, result.operands) || - parser.addTypeToList(getSubViewResultType(memRefType), result.types)); -} - -//===----------------------------------------------------------------------===// // TransposeOp //===----------------------------------------------------------------------===// void mlir::linalg::TransposeOp::build(Builder *b, OperationState &result, @@ -646,13 +579,6 @@ static LogicalResult verify(ConvOp op) { return success(); } -llvm::raw_ostream & -mlir::linalg::operator<<(llvm::raw_ostream &os, - mlir::linalg::SubViewOp::Range &range) { - return os << "range " << *range.min << ":" << *range.max << ":" - << *range.step; -} - namespace mlir { namespace linalg { diff --git a/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp b/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp index c6dffc3..453daba 100644 --- a/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp +++ b/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp @@ -74,9 +74,8 @@ static llvm::cl::list clTileSizes( // a subset of the original loop ranges of `op`. // This is achieved by applying the `loopToOperandRangesMaps` permutation maps // to the `loopRanges` in order to obtain view ranges. -static LinalgOp -cloneWithLoopRanges(OpBuilder &b, Location loc, LinalgOp op, - ArrayRef loopRanges) { +static LinalgOp cloneWithLoopRanges(OpBuilder &b, Location loc, LinalgOp op, + ArrayRef loopRanges) { auto maps = loopToOperandRangesMaps(op); SmallVector clonedViews; clonedViews.reserve(op.getNumInputsAndOutputs()); @@ -88,8 +87,7 @@ cloneWithLoopRanges(OpBuilder &b, Location loc, LinalgOp op, auto map = maps[idx]; LLVM_DEBUG(dbgs() << "map: " << map << "\n"); Value *view = en.value(); - SmallVector viewRanges( - map.getNumResults()); + SmallVector viewRanges(map.getNumResults()); for (auto en2 : llvm::enumerate(map.getResults())) { unsigned d = en2.index(); // loopToOperandRangesMaps are permutations-only. @@ -99,16 +97,19 @@ cloneWithLoopRanges(OpBuilder &b, Location loc, LinalgOp op, << "\t" << "loopPos: " << loopPos << "\t" << viewRanges[d]); } - // TODO(ntv): opportunities for folding/CSE here rather than build new IR. - SmallVector subViewOperands; - subViewOperands.reserve(viewRanges.size() * 3); + // Construct a new subview for the tile. + unsigned rank = viewRanges.size(); + SmallVector offsets, sizes, strides; + offsets.reserve(rank); + sizes.reserve(rank); + strides.reserve(rank); for (auto r : viewRanges) { - subViewOperands.push_back(r.min); - subViewOperands.push_back(r.max); - subViewOperands.push_back(r.step); + offsets.push_back(r.offset); + sizes.push_back(r.size); + strides.push_back(r.stride); } clonedViews.push_back( - b.create(loc, view, subViewOperands)); + b.create(loc, view, offsets, sizes, strides)); } auto operands = getAssumedNonViewOperands(op); clonedViews.append(operands.begin(), operands.end()); @@ -153,7 +154,7 @@ static ViewDimension getViewDefiningLoopRange(LinalgOp op, unsigned loopDepth) { static LinalgOp fuse(Value *producedView, LinalgOp producer, LinalgOp consumer, unsigned consumerIdx, unsigned producerIdx, OperationFolder *folder) { - auto subView = dyn_cast_or_null( + auto subView = dyn_cast_or_null( consumer.getInput(consumerIdx)->getDefiningOp()); auto slice = dyn_cast_or_null( consumer.getInput(consumerIdx)->getDefiningOp()); @@ -172,13 +173,13 @@ static LinalgOp fuse(Value *producedView, LinalgOp producer, LinalgOp consumer, unsigned nPar = producer.getNumParallelLoops(); unsigned nRed = producer.getNumReductionLoops(); unsigned nWin = producer.getNumWindowLoops(); - SmallVector loopRanges(nPar + nRed + nWin); + SmallVector loopRanges(nPar + nRed + nWin); // Iterate over dimensions identified by the producer map for `producerIdx`. // This defines a subset of the loop ranges that we need to complete later. for (auto en : llvm::enumerate(producerMap.getResults())) { unsigned posInProducerLoop = en.value().cast().getPosition(); - loopRanges[posInProducerLoop] = subView.getRange(en.index()); + loopRanges[posInProducerLoop] = subView.getRanges()[en.index()]; } OpBuilder b(consumer.getOperation()); @@ -187,14 +188,14 @@ static LinalgOp fuse(Value *producedView, LinalgOp producer, LinalgOp consumer, // producer map for `producerIdx`, we need to explicitly compute the view that // defines the loop ranges using the `producer`. for (unsigned i = 0, nLoops = loopRanges.size(); i < nLoops; ++i) { - if (loopRanges[i].min) + if (loopRanges[i].offset) LLVM_DEBUG(llvm::dbgs() << "existing LoopRange: " << loopRanges[i] << "\n"); else { auto viewDim = getViewDefiningLoopRange(producer, i); - loopRanges[i] = mlir::linalg::SubViewOp::Range{ - constant_index(folder, 0), dim(viewDim.view, viewDim.dimension), - constant_index(folder, 1)}; + loopRanges[i] = SubViewOp::Range{constant_index(folder, 0), + dim(viewDim.view, viewDim.dimension), + constant_index(folder, 1)}; LLVM_DEBUG(llvm::dbgs() << "new LoopRange: " << loopRanges[i] << "\n"); } } @@ -286,8 +287,7 @@ Optional mlir::linalg::fuseProducerOf( // Must be a subview or a slice to guarantee there are loops we can fuse // into. - auto subView = dyn_cast_or_null( - consumedView->getDefiningOp()); + auto subView = dyn_cast_or_null(consumedView->getDefiningOp()); auto slice = dyn_cast_or_null(consumedView->getDefiningOp()); if (!subView && !slice) { LLVM_DEBUG(dbgs() << "\nNot fusable (not a subview or slice)"); diff --git a/mlir/lib/Dialect/Linalg/Transforms/LowerToLLVMDialect.cpp b/mlir/lib/Dialect/Linalg/Transforms/LowerToLLVMDialect.cpp index 05f4bce..9d03953 100644 --- a/mlir/lib/Dialect/Linalg/Transforms/LowerToLLVMDialect.cpp +++ b/mlir/lib/Dialect/Linalg/Transforms/LowerToLLVMDialect.cpp @@ -503,24 +503,6 @@ public: } }; -/// A non-conversion rewrite pattern kicks in to convert SubViewOp into RangeOps -/// and SliceOps. -class SubViewOpConversion : public OpRewritePattern { -public: - using OpRewritePattern::OpRewritePattern; - - PatternMatchResult matchAndRewrite(mlir::linalg::SubViewOp op, - PatternRewriter &rewriter) const override { - auto *view = op.getView(); - SmallVector ranges; - for (auto sliceRange : op.getRanges()) - ranges.push_back(rewriter.create( - op.getLoc(), sliceRange.min, sliceRange.max, sliceRange.step)); - rewriter.replaceOpWithNewOp(op, view, ranges); - return matchSuccess(); - } -}; - /// Populate the given list with patterns that convert from Linalg to Standard. static void populateLinalgToStandardConversionPatterns(OwningRewritePatternList &patterns, @@ -530,8 +512,8 @@ populateLinalgToStandardConversionPatterns(OwningRewritePatternList &patterns, patterns.insert, LinalgOpConversion, LinalgOpConversion, LinalgOpConversion, LinalgOpConversion, - LinalgOpConversion, LinalgOpConversion, - SubViewOpConversion>(ctx); + LinalgOpConversion, LinalgOpConversion>( + ctx); } /// Populate the given list with patterns that convert from Linalg to LLVM. diff --git a/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp b/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp index 3afee41..3c6e139 100644 --- a/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp +++ b/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp @@ -89,13 +89,13 @@ static Value *allocBuffer(Type elementType, Value *size, bool dynamicBuffers) { // boundary tiles. For now this is done with an unconditional `fill` op followed // by a partial `copy` op. static PromotionInfo promoteFullTileBuffer(OpBuilder &b, Location loc, - mlir::linalg::SubViewOp subView, + SubViewOp subView, bool dynamicBuffers, OperationFolder *folder) { auto zero = constant_index(folder, 0); auto one = constant_index(folder, 1); - auto viewType = subView.getViewType(); + auto viewType = subView.getType(); auto rank = viewType.getRank(); Value *allocSize = one; SmallVector fullRanges, partialRanges; @@ -104,12 +104,7 @@ static PromotionInfo promoteFullTileBuffer(OpBuilder &b, Location loc, for (auto en : llvm::enumerate(subView.getRanges())) { auto rank = en.index(); auto rangeValue = en.value(); - Value *d = - isa(rangeValue.max->getDefiningOp()) - ? rangeValue.max - : applyMapToValues(b, loc, getAffineDifferenceMap(b.getContext()), - {rangeValue.max, rangeValue.min}, folder) - .front(); + Value *d = rangeValue.size; allocSize = muli(folder, allocSize, d).getValue(); fullRanges.push_back(d); partialRanges.push_back(range(folder, zero, dim(subView, rank), one)); @@ -135,9 +130,8 @@ mlir::linalg::promoteSubViews(OpBuilder &b, Location loc, res.reserve(subViews.size()); DenseMap promotionInfoMap; for (auto *v : subViews) { - mlir::linalg::SubViewOp subView = - cast(v->getDefiningOp()); - auto viewType = subView.getViewType(); + SubViewOp subView = cast(v->getDefiningOp()); + auto viewType = subView.getType(); // TODO(ntv): support more cases than just float. if (!viewType.getElementType().isa()) continue; @@ -148,14 +142,13 @@ mlir::linalg::promoteSubViews(OpBuilder &b, Location loc, } for (auto *v : subViews) { - mlir::linalg::SubViewOp subView = - cast(v->getDefiningOp()); + SubViewOp subView = cast(v->getDefiningOp()); auto info = promotionInfoMap.find(v); if (info == promotionInfoMap.end()) continue; // TODO(ntv): value to fill with should be related to the operation. // For now, just use APFloat(0.0f). - auto t = subView.getViewType().getElementType().cast(); + auto t = subView.getType().getElementType().cast(); Value *fillVal = constant_float(folder, APFloat(0.0f), t); // TODO(ntv): fill is only necessary if `promotionInfo` has a full local // view that is different from the partial local view and we are on the @@ -167,8 +160,7 @@ mlir::linalg::promoteSubViews(OpBuilder &b, Location loc, auto info = promotionInfoMap.find(v); if (info == promotionInfoMap.end()) continue; - copy(cast(v->getDefiningOp()), - info->second.partialLocalView); + copy(cast(v->getDefiningOp()), info->second.partialLocalView); } return res; } @@ -226,8 +218,7 @@ static void promoteSubViews(FuncOp f, bool dynamicBuffers) { // nothing. SetVector subViews; for (auto it : op.getInputsAndOutputs()) - if (auto sv = - dyn_cast_or_null(it->getDefiningOp())) + if (auto sv = dyn_cast_or_null(it->getDefiningOp())) subViews.insert(sv); if (!subViews.empty()) { promoteSubViewOperands(op, subViews, dynamicBuffers, &folder); diff --git a/mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp b/mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp index b7a5740..76b1858 100644 --- a/mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp +++ b/mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp @@ -65,7 +65,7 @@ static bool isZero(Value *v) { // avoiding affine map manipulations. // The returned ranges correspond to the loop ranges, in the proper order, that // are tiled and for which new loops will be created. -static SmallVector +static SmallVector makeTiledLoopRanges(OpBuilder &b, Location loc, AffineMap map, ArrayRef allViewSizes, ArrayRef allTileSizes, OperationFolder *folder) { @@ -83,10 +83,10 @@ makeTiledLoopRanges(OpBuilder &b, Location loc, AffineMap map, } // Create a new range with the applied tile sizes. - SmallVector res; + SmallVector res; for (unsigned idx = 0, e = tileSizes.size(); idx < e; ++idx) { - res.push_back(mlir::linalg::SubViewOp::Range{ - constant_index(folder, 0), viewSizes[idx], tileSizes[idx]}); + res.push_back(SubViewOp::Range{constant_index(folder, 0), viewSizes[idx], + tileSizes[idx]}); } return res; } @@ -153,16 +153,11 @@ makeTiledViews(OpBuilder &b, Location loc, LinalgOp linalgOp, // Construct (potentially temporary) mins and maxes on which to apply maps // that define tile subviews. - SmallVector mins, maxes; + SmallVector lbs, subViewSizes; for (unsigned idx = 0, idxIvs = 0, e = tileSizes.size(); idx < e; ++idx) { - if (isZero(tileSizes[idx])) { - mins.push_back(constant_index(folder, 0)); - maxes.push_back(viewSizes[idx]); - } else { - ValueHandle lb(ivs[idxIvs++]), step(tileSizes[idx]); - mins.push_back(lb); - maxes.push_back(lb + step); - } + bool isTiled = !isZero(tileSizes[idx]); + lbs.push_back(isTiled ? ivs[idxIvs++] : (Value *)constant_index(folder, 0)); + subViewSizes.push_back(isTiled ? tileSizes[idx] : viewSizes[idx]); } auto *op = linalgOp.getOperation(); @@ -182,41 +177,39 @@ makeTiledViews(OpBuilder &b, Location loc, LinalgOp linalgOp, } // Construct a new subview for the tile. - SmallVector subViewRangeOperands; - subViewRangeOperands.reserve(rank * 3); + SmallVector offsets, sizes, strides; + offsets.reserve(rank); + sizes.reserve(rank); + strides.reserve(rank); for (unsigned r = 0; r < rank; ++r) { if (!isTiled(map.getSubMap({r}), tileSizes)) { - subViewRangeOperands.push_back(mlir::linalg::SubViewOp::Range{ - constant_index(folder, 0), dim(view, r), - constant_index(folder, 1)}); + offsets.push_back(constant_index(folder, 0)); + sizes.push_back(dim(view, r)); + strides.push_back(constant_index(folder, 1)); continue; } - auto m = map.getSubMap({r}); - auto *min = applyMapToValues(b, loc, m, mins, folder).front(); - auto *max = applyMapToValues(b, loc, m, maxes, folder).front(); // Tiling creates a new slice at the proper index, the slice step is 1 // (i.e. the slice view does not subsample, stepping occurs in the loop). - subViewRangeOperands.push_back( - mlir::linalg::SubViewOp::Range{min, max, constant_index(folder, 1)}); - } - SmallVector subViewOperands; - subViewOperands.reserve(subViewRangeOperands.size() * 3); - for (auto r : subViewRangeOperands) { - subViewOperands.push_back(r.min); - subViewOperands.push_back(r.max); - subViewOperands.push_back(r.step); + auto m = map.getSubMap({r}); + auto *offset = applyMapToValues(b, loc, m, lbs, folder).front(); + offsets.push_back(offset); + auto *size = applyMapToValues(b, loc, m, subViewSizes, folder).front(); + sizes.push_back(size); + strides.push_back(constant_index(folder, 1)); } - res.push_back( - b.create(loc, view, subViewOperands)); + // TODO(b/144419024) Atm std.subview is not guaranteed in-bounds. Depending + // on the semantics we attach to it, we may need to use min(size, dim) here + // and canonicalize later. + res.push_back(b.create(loc, view, offsets, sizes, strides)); } // Traverse the mins/maxes and erase those that don't have uses left. // This is a special type of folding that we only apply when `folder` is // defined. if (folder) { - mins.append(maxes.begin(), maxes.end()); - for (auto *v : mins) + lbs.append(subViewSizes.begin(), subViewSizes.end()); + for (auto *v : lbs) if (v->use_empty()) v->getDefiningOp()->erase(); } diff --git a/mlir/lib/Dialect/Linalg/Utils/Utils.cpp b/mlir/lib/Dialect/Linalg/Utils/Utils.cpp index 20cf183..eb501f9 100644 --- a/mlir/lib/Dialect/Linalg/Utils/Utils.cpp +++ b/mlir/lib/Dialect/Linalg/Utils/Utils.cpp @@ -56,10 +56,10 @@ mlir::edsc::LoopRangeBuilder::LoopRangeBuilder(ValueHandle *iv, enter(body, /*prev=*/1); } -mlir::edsc::LoopRangeBuilder::LoopRangeBuilder( - ValueHandle *iv, mlir::linalg::SubViewOp::Range range) { +mlir::edsc::LoopRangeBuilder::LoopRangeBuilder(ValueHandle *iv, + SubViewOp::Range range) { auto forOp = - OperationHandle::createOp(range.min, range.max, range.step); + OperationHandle::createOp(range.offset, range.size, range.stride); *iv = ValueHandle(forOp.getInductionVar()); auto *body = forOp.getBody(); enter(body, /*prev=*/1); @@ -74,8 +74,7 @@ mlir::edsc::LoopRangeBuilder::operator()(std::function fun) { } mlir::edsc::LoopNestRangeBuilder::LoopNestRangeBuilder( - ArrayRef ivs, - ArrayRef ranges) { + ArrayRef ivs, ArrayRef ranges) { loops.reserve(ranges.size()); for (unsigned i = 0, e = ranges.size(); i < e; ++i) { loops.emplace_back(ivs[i], ranges[i]); diff --git a/mlir/lib/Dialect/StandardOps/Ops.cpp b/mlir/lib/Dialect/StandardOps/Ops.cpp index f152ccf..e70675e 100644 --- a/mlir/lib/Dialect/StandardOps/Ops.cpp +++ b/mlir/lib/Dialect/StandardOps/Ops.cpp @@ -2553,6 +2553,43 @@ void ViewOp::getCanonicalizationPatterns(OwningRewritePatternList &results, // SubViewOp //===----------------------------------------------------------------------===// +// Returns a MemRefType with dynamic sizes and offset and the same stride as the +// `memRefType` passed as argument. +// TODO(andydavis,ntv) Evolve to a more powerful inference that can also keep +// sizes and offset static. +static Type inferSubViewResultType(MemRefType memRefType) { + auto rank = memRefType.getRank(); + int64_t offset; + SmallVector strides; + Type elementType = memRefType.getElementType(); + auto res = getStridesAndOffset(memRefType, strides, offset); + assert(succeeded(res) && "SubViewOp expected strided memref type"); + (void)res; + + // Assume sizes and offset are fully dynamic for now until canonicalization + // occurs on the ranges. Typed strides don't change though. + offset = MemRefType::getDynamicStrideOrOffset(); + // Overwrite strides because verifier will not pass. + // TODO(b/144419106): don't force degrade the strides to fully dynamic. + for (auto &stride : strides) + stride = MemRefType::getDynamicStrideOrOffset(); + auto stridedLayout = + makeStridedLinearLayoutMap(strides, offset, memRefType.getContext()); + SmallVector sizes(rank, ShapedType::kDynamicSize); + return MemRefType::get(sizes, elementType, stridedLayout, + memRefType.getMemorySpace()); +} + +void mlir::SubViewOp::build(Builder *b, OperationState &result, Value *source, + ArrayRef offsets, ArrayRef sizes, + ArrayRef strides, Type resultType, + ArrayRef attrs) { + if (!resultType) + resultType = inferSubViewResultType(source->getType().cast()); + build(b, result, resultType, source, offsets, sizes, strides); + result.addAttributes(attrs); +} + static ParseResult parseSubViewOp(OpAsmParser &parser, OperationState &result) { OpAsmParser::OperandType srcInfo; SmallVector offsetsInfo; @@ -2634,6 +2671,23 @@ static LogicalResult verify(SubViewOp op) { return success(); } +llvm::raw_ostream &mlir::operator<<(llvm::raw_ostream &os, + SubViewOp::Range &range) { + return os << "range " << *range.offset << ":" << *range.size << ":" + << *range.stride; +} + +SmallVector SubViewOp::getRanges() { + SmallVector res; + unsigned rank = getType().getRank(); + res.reserve(rank); + for (unsigned i = 0; i < rank; ++i) + res.emplace_back(Range{*(getDynamicOffsets().begin() + i), + *(getDynamicSizes().begin() + i), + *(getDynamicStrides().begin() + i)}); + return res; +} + //===----------------------------------------------------------------------===// // ZeroExtendIOp //===----------------------------------------------------------------------===// diff --git a/mlir/lib/IR/StandardTypes.cpp b/mlir/lib/IR/StandardTypes.cpp index 54f39a3..3f3677c 100644 --- a/mlir/lib/IR/StandardTypes.cpp +++ b/mlir/lib/IR/StandardTypes.cpp @@ -123,6 +123,8 @@ unsigned Type::getIntOrFloatBitWidth() { //===----------------------------------------------------------------------===// // ShapedType //===----------------------------------------------------------------------===// +constexpr int64_t ShapedType::kDynamicSize; +constexpr int64_t ShapedType::kDynamicStrideOrOffset; Type ShapedType::getElementType() const { return static_cast(impl)->elementType; diff --git a/mlir/test/Conversion/LoopsToGPU/imperfect_linalg.mlir b/mlir/test/Conversion/LoopsToGPU/imperfect_linalg.mlir index cdcaf42..abf8da6 100644 --- a/mlir/test/Conversion/LoopsToGPU/imperfect_linalg.mlir +++ b/mlir/test/Conversion/LoopsToGPU/imperfect_linalg.mlir @@ -1,7 +1,5 @@ // RUN: mlir-opt %s -convert-loop-op-to-gpu -gpu-num-workgroups=2,16 -gpu-workgroup-size=32,4 | FileCheck %s -#map0 = (d0) -> (d0 + 2) -#map1 = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1) module { func @fmul(%arg0: memref, %arg1: memref, %arg2: memref) { %c1 = constant 1 : index @@ -21,24 +19,18 @@ module { // CHECK: store loop.for %arg3 = %c0 to %0 step %c2 { loop.for %arg4 = %c0 to %1 step %c2 { - %2 = affine.apply #map0(%arg3) - %3 = affine.apply #map0(%arg4) - %4 = linalg.subview %arg0[%arg3, %2, %c1, %arg4, %3, %c1] : memref - %5 = affine.apply #map0(%arg3) - %6 = affine.apply #map0(%arg4) - %7 = linalg.subview %arg1[%arg3, %5, %c1, %arg4, %6, %c1] : memref - %8 = affine.apply #map0(%arg3) - %9 = affine.apply #map0(%arg4) - %10 = linalg.subview %arg2[%arg3, %8, %c1, %arg4, %9, %c1] : memref - %11 = dim %4, 0 : memref - %12 = dim %4, 1 : memref + %4 = std.subview %arg0[%arg3, %arg4][%c2, %c2][%c1, %c1] : memref to memref + %7 = std.subview %arg1[%arg3, %arg4][%c2, %c2][%c1, %c1] : memref to memref + %10 = std.subview %arg2[%arg3, %arg4][%c2, %c2][%c1, %c1] : memref to memref + %11 = dim %4, 0 : memref + %12 = dim %4, 1 : memref loop.for %arg5 = %c0 to %11 step %c1 { loop.for %arg6 = %c0 to %12 step %c1 { - %13 = load %4[%arg5, %arg6] : memref - %14 = load %7[%arg5, %arg6] : memref - %15 = load %10[%arg5, %arg6] : memref + %13 = load %4[%arg5, %arg6] : memref + %14 = load %7[%arg5, %arg6] : memref + %15 = load %10[%arg5, %arg6] : memref %16 = mulf %13, %14 : f32 - store %16, %10[%arg5, %arg6] : memref + store %16, %10[%arg5, %arg6] : memref } } } diff --git a/mlir/test/Dialect/Linalg/fusion-2-level.mlir b/mlir/test/Dialect/Linalg/fusion-2-level.mlir index 45dc483..b6a0cab 100644 --- a/mlir/test/Dialect/Linalg/fusion-2-level.mlir +++ b/mlir/test/Dialect/Linalg/fusion-2-level.mlir @@ -1,12 +1,5 @@ // RUN: mlir-opt %s -linalg-fusion | FileCheck %s -#map0 = (d0) -> (d0 + 20) -#map1 = (d0) -> (d0 + 40) -#map2 = (d0) -> (d0 + 30) -#map3 = (d0) -> (d0 + 2) -#map4 = (d0) -> (d0 + 4) -#map5 = (d0) -> (d0 + 3) - func @f1(%A: memref, %B: memref, %C: memref, %D: memref, %E: memref) -> memref { %c1 = constant 1 : index %c0 = constant 0 : index @@ -23,25 +16,19 @@ func @f1(%A: memref, %B: memref - %6 = affine.apply #map2(%arg6) - %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref - %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref - %9 = dim %5, 0 : memref - %10 = dim %5, 1 : memref - %11 = dim %7, 1 : memref + %5 = std.subview %C[%arg5, %arg7][%c20, %c40][%c1, %c1] : memref to memref + %7 = std.subview %D[%arg7, %arg6][%c40, %c30][%c1, %c1]: memref to memref + %8 = std.subview %E[%arg5, %arg6][%c20, %c40][%c1, %c1] : memref to memref + %9 = dim %5, 0 : memref + %10 = dim %5, 1 : memref + %11 = dim %7, 1 : memref loop.for %arg8 = %c0 to %9 step %c2 { loop.for %arg9 = %c0 to %11 step %c3 { - loop.for %B0 = %c0 to %10 step %c4 { - %12 = affine.apply #map3(%arg8) - %13 = affine.apply #map4(%B0) - %14 = linalg.subview %5[%arg8, %12, %c1, %B0, %13, %c1] : memref - %15 = affine.apply #map5(%arg9) - %16 = linalg.subview %7[%B0, %13, %c1, %arg9, %15, %c1] : memref - %17 = linalg.subview %8[%arg8, %12, %c1, %arg9, %15, %c1] : memref - linalg.matmul(%14, %16, %17) : memref, memref, memref + loop.for %arg10 = %c0 to %10 step %c4 { + %14 = std.subview %5[%arg8, %arg10][%c2, %c4][%c1, %c1] : memref to memref + %16 = std.subview %7[%arg10, %arg9][%c4, %c3][%c1, %c1]: memref to memref + %17 = std.subview %8[%arg8, %arg9][%c2, %c4][%c1, %c1] : memref to memref + linalg.matmul(%14, %16, %17) : memref, memref, memref } } } diff --git a/mlir/test/Dialect/Linalg/fusion.mlir b/mlir/test/Dialect/Linalg/fusion.mlir index 5afb991..bd67cc5 100644 --- a/mlir/test/Dialect/Linalg/fusion.mlir +++ b/mlir/test/Dialect/Linalg/fusion.mlir @@ -19,13 +19,10 @@ func @f1(%A: memref, %B: memref - %6 = affine.apply #map2(%arg6) - %7 = linalg.subview %B[%arg7, %4, %c1, %arg6, %6, %c1] : memref - %8 = linalg.subview %C[%arg5, %3, %c1, %arg6, %6, %c1] : memref - linalg.matmul(%5, %7, %8) : memref, memref, memref + %5 = std.subview %A[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref + %7 = std.subview %B[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %8 = std.subview %C[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref + linalg.matmul(%5, %7, %8) : memref, memref, memref } } } @@ -53,12 +50,9 @@ func @f2(%A: memref, %B: memref - %6 = affine.apply #map2(%arg6) - %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref - %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref + %5 = std.subview %C[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref + %7 = std.subview %D[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %8 = std.subview %E[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref linalg.matmul(%5, %7, %8) : memref, memref, memref } } @@ -89,12 +83,9 @@ func @f3(%A: memref, %B: memref - %6 = affine.apply #map2(%arg6) - %7 = linalg.subview %C[%arg7, %4, %c1, %arg6, %6, %c1] : memref - %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref + %5 = std.subview %D[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref + %7 = std.subview %C[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %8 = std.subview %E[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref linalg.matmul(%5, %7, %8) : memref, memref, memref } } @@ -126,12 +117,9 @@ func @f4(%A: memref, %B: memref - %6 = affine.apply #map2(%arg6) - %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref - %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref + %5 = std.subview %C[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref + %7 = std.subview %D[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %8 = std.subview %E[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref linalg.matmul(%5, %7, %8) : memref, memref, memref } } @@ -165,12 +153,9 @@ func @f5(%A: memref, %B: memref - %6 = affine.apply #map2(%arg6) - %7 = linalg.subview %B[%arg7, %4, %c1, %arg6, %6, %c1] : memref - %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref + %5 = std.subview %D[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref + %7 = std.subview %B[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %8 = std.subview %E[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref linalg.matmul(%5, %7, %8) : memref, memref, memref } } @@ -206,10 +191,10 @@ func @f6(%A: memref, %B: memref + %5 = std.subview %C[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref %6 = affine.apply #map2(%arg6) - %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref - %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref + %7 = std.subview %D[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %8 = std.subview %E[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref linalg.matmul(%5, %7, %8) : memref, memref, memref } } @@ -244,12 +229,9 @@ func @f7(%A: memref, %B: memref - %8 = affine.apply #map2(%arg6) - %9 = linalg.subview %C[%arg7, %6, %c1, %arg6, %8, %c1] : memref - %10 = linalg.subview %E[%arg5, %5, %c1, %arg6, %8, %c1] : memref + %7 = std.subview %A[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref + %9 = std.subview %C[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %10 = std.subview %E[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref linalg.matmul(%7, %9, %10) : memref, memref, memref } } @@ -257,12 +239,9 @@ func @f7(%A: memref, %B: memref - %8 = affine.apply #map2(%arg6) - %9 = linalg.subview %D[%arg7, %6, %c1, %arg6, %8, %c1] : memref - %10 = linalg.subview %E[%arg5, %5, %c1, %arg6, %8, %c1] : memref + %7 = std.subview %C[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref + %9 = std.subview %D[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %10 = std.subview %E[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref linalg.matmul(%7, %9, %10) : memref, memref, memref } } @@ -304,10 +283,10 @@ func @f8(%A: memref, %B: memref + %5 = std.subview %A[%arg5, %arg7][%c2, %c4][%c1, %c1] : memref to memref %6 = affine.apply #map2(%arg6) - %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref - %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref + %7 = std.subview %D[%arg7, %arg6][%c4, %c3][%c1, %c1] : memref to memref + %8 = std.subview %E[%arg5, %arg6][%c2, %c3][%c1, %c1] : memref to memref linalg.matmul(%5, %7, %8) : memref, memref, memref } } @@ -342,13 +321,11 @@ func @pointwise(%A: memref, %B: memref, memref, memref %0 = dim %B, 0 : memref %1 = dim %B, 1 : memref - loop.for %E = %c0 to %0 step %c2 { + loop.for %arg4 = %c0 to %0 step %c2 { loop.for %arg5 = %c0 to %1 step %c3 { - %2 = affine.apply #map0(%E) - %3 = affine.apply #map1(%arg5) - %4 = linalg.subview %B[%E, %2, %c1, %arg5, %3, %c1] : memref - %5 = linalg.subview %C[%E, %2, %c1, %arg5, %3, %c1] : memref - %6 = linalg.subview %D[%E, %2, %c1, %arg5, %3, %c1] : memref + %4 = std.subview %B[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref to memref + %5 = std.subview %C[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref to memref + %6 = std.subview %D[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref to memref linalg.generic #pointwise_2d_trait %4, %5, %6 { ^bb0(%arg6: f32, %arg7: f32, %arg8: f32): // no predecessors %7 = mulf %arg6, %arg7 : f32 @@ -367,7 +344,6 @@ func @pointwise(%A: memref, %B: memref, memref, memref %0 = dim %B, 0 : memref %1 = dim %B, 1 : memref - loop.for %e = %c0 to %0 step %c2 { + loop.for %arg4 = %c0 to %0 step %c2 { loop.for %arg5 = %c0 to %1 step %c3 { - %2 = affine.apply #map0(%e) - %3 = affine.apply #map1(%arg5) - %4 = linalg.subview %B[%e, %2, %c1, %arg5, %3, %c1] : memref - %5 = linalg.subview %C[%e, %2, %c1, %arg5, %3, %c1] : memref - %6 = linalg.subview %D[%e, %2, %c1, %arg5, %3, %c1] : memref + %4 = std.subview %B[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref to memref + %5 = std.subview %C[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref to memref + %6 = std.subview %D[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref to memref linalg.generic #pointwise_2d_trait %4, %5, %6 { ^bb0(%arg6: f32, %arg7: f32, %arg8: f32): // no predecessors %7 = mulf %arg6, %arg7 : f32 linalg.yield %7 : f32 - }: memref, memref, memref + }: memref, memref, memref } } return diff --git a/mlir/test/Dialect/Linalg/invalid.mlir b/mlir/test/Dialect/Linalg/invalid.mlir index 3e4c542..57b9f09 100644 --- a/mlir/test/Dialect/Linalg/invalid.mlir +++ b/mlir/test/Dialect/Linalg/invalid.mlir @@ -33,14 +33,6 @@ func @store_number_of_indices(%v : memref) { // ----- -func @subview_number_of_indices(%v : memref(off + M * i + j)>) { - // expected-error @+2 {{expected a strided memref followed by 6 indices specifying a range for each dimension}} - %c0 = constant 0 : index - linalg.subview %v[%c0, %c0] : memref(off + M * i + j)> -} - -// ----- - func @transpose_not_permutation(%v : memref(off + M * i + j)>) { // expected-error @+1 {{expected a permutation map}} linalg.transpose %v (i, j) -> (i, i) : memref(off + M * i + j)> diff --git a/mlir/test/Dialect/Linalg/llvm.mlir b/mlir/test/Dialect/Linalg/llvm.mlir index e354893..7691410 100644 --- a/mlir/test/Dialect/Linalg/llvm.mlir +++ b/mlir/test/Dialect/Linalg/llvm.mlir @@ -56,36 +56,7 @@ func @dot(%arg0: memref, %arg1: memref, !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }*">, !llvm<"{ float*, float*, i64 }*">) -> () -func @subview(%arg0: memref) { - %c0 = constant 0 : index - %0 = linalg.subview %arg0[%c0, %c0, %c0, %c0, %c0, %c0] : memref - return -} -// CHECK-LABEL: func @subview -// -// Subview lowers to range + slice op -// CHECK: llvm.mlir.undef : !llvm<"{ i64, i64, i64 }"> -// CHECK: llvm.mlir.undef : !llvm<"{ i64, i64, i64 }"> -// CHECK: llvm.mlir.undef : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }"> -// -// Select occurs in slice op lowering -// CHECK: llvm.extractvalue %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }"> -// CHECK-NEXT: llvm.icmp "slt" %{{.*}}, %{{.*}} : !llvm.i64 -// CHECK-NEXT: llvm.select %{{.*}}, %{{.*}}, %{{.*}} : !llvm.i1, !llvm.i64 -// CHECK-NEXT: llvm.sub %{{.*}}, %{{.*}} : !llvm.i64 -// CHECK-NEXT: llvm.icmp "slt" %{{.*}}, %{{.*}} : !llvm.i64 -// CHECK-NEXT: llvm.select %{{.*}}, %{{.*}}, %{{.*}} : !llvm.i1, !llvm.i64 -// CHECK-NEXT: llvm.mul %{{.*}}, %{{.*}} : !llvm.i64 -// -// CHECK: llvm.extractvalue %{{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }"> -// CHECK-NEXT: llvm.icmp "slt" %{{.*}}, %{{.*}} : !llvm.i64 -// CHECK-NEXT: llvm.select %{{.*}}, %{{.*}}, %{{.*}} : !llvm.i1, !llvm.i64 -// CHECK-NEXT: llvm.sub %{{.*}}, %{{.*}} : !llvm.i64 -// CHECK-NEXT: llvm.icmp "slt" %{{.*}}, %{{.*}} : !llvm.i64 -// CHECK-NEXT: llvm.select %{{.*}}, %{{.*}}, %{{.*}} : !llvm.i1, !llvm.i64 -// CHECK-NEXT: llvm.mul %{{.*}}, %{{.*}} : !llvm.i64 - -func @view_with_range_and_index(%arg0: memref) { +func @slice_with_range_and_index(%arg0: memref) { %c0 = constant 0 : index %c1 = constant 1 : index %R = linalg.range %c0:%c1:%c1 : !linalg.range @@ -94,7 +65,7 @@ func @view_with_range_and_index(%arg0: memref // CHECK: llvm.extractvalue %{{.*}}[4, 0] : !llvm<"{ double*, double*, i64, [2 x i64], [2 x i64] }"> diff --git a/mlir/test/Dialect/Linalg/promote.mlir b/mlir/test/Dialect/Linalg/promote.mlir index db33e04..61d11f9 100644 --- a/mlir/test/Dialect/Linalg/promote.mlir +++ b/mlir/test/Dialect/Linalg/promote.mlir @@ -8,6 +8,7 @@ // CHECK-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1) // CHECK-DAG: #[[strided2DnoOffset:.*]] = (d0, d1)[s0] -> (d0 * s0 + d1) +// CHECK-DAG: #[[strided2D_dynamic:.*]] = (d0, d1)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2) module { func @matmul(%A: memref, %M: index, %N: index, %K: index) { @@ -25,16 +26,10 @@ module { loop.for %arg4 = %c0 to %6 step %c2 { loop.for %arg5 = %c0 to %8 step %c3 { loop.for %arg6 = %c0 to %7 step %c4 { - %9 = affine.apply #map1(%arg4) - %10 = affine.apply #map2(%arg6) - %11 = linalg.subview %3[%arg4, %9, %c1, %arg6, %10, %c1] : memref - %12 = affine.apply #map2(%arg6) - %13 = affine.apply #map3(%arg5) - %14 = linalg.subview %4[%arg6, %12, %c1, %arg5, %13, %c1] : memref - %15 = affine.apply #map1(%arg4) - %16 = affine.apply #map3(%arg5) - %17 = linalg.subview %5[%arg4, %15, %c1, %arg5, %16, %c1] : memref - linalg.matmul(%11, %14, %17) : memref, memref, memref + %11 = std.subview %3[%arg4, %arg6][%c2, %c4][%c1, %c1] : memref to memref + %14 = std.subview %4[%arg6, %arg5][%c4, %c3][%c1, %c1] : memref to memref + %17 = std.subview %5[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref to memref + linalg.matmul(%11, %14, %17) : memref, memref, memref } } } @@ -46,9 +41,9 @@ module { // CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { // CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { // CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { -// CHECK: %[[vA:.*]] = linalg.subview {{.*}} : memref -// CHECK: %[[vB:.*]] = linalg.subview {{.*}} : memref -// CHECK: %[[vC:.*]] = linalg.subview {{.*}} : memref +// CHECK: %[[vA:.*]] = std.subview {{.*}} : memref +// CHECK: %[[vB:.*]] = std.subview {{.*}} : memref +// CHECK: %[[vC:.*]] = std.subview {{.*}} : memref /// // CHECK: %[[tmpA:.*]] = alloc() : memref<32xi8> // CHECK: %[[fullA:.*]] = std.view %[[tmpA]][][{{.*}}] : memref<32xi8> to memref @@ -68,13 +63,13 @@ module { // CHECK: linalg.fill(%[[fullA]], {{.*}}) : memref, f32 // CHECK: linalg.fill(%[[fullB]], {{.*}}) : memref, f32 // CHECK: linalg.fill(%[[fullC]], {{.*}}) : memref, f32 -// CHECK: linalg.copy(%[[vA]], %[[partialA]]) : memref, memref -// CHECK: linalg.copy(%[[vB]], %[[partialB]]) : memref, memref -// CHECK: linalg.copy(%[[vC]], %[[partialC]]) : memref, memref +// CHECK: linalg.copy(%[[vA]], %[[partialA]]) : memref, memref +// CHECK: linalg.copy(%[[vB]], %[[partialB]]) : memref, memref +// CHECK: linalg.copy(%[[vC]], %[[partialC]]) : memref, memref // // CHECK: linalg.matmul(%[[fullA]], %[[fullB]], %[[fullC]]) : memref, memref, memref // -// CHECK: linalg.copy(%[[partialC]], %[[vC]]) : memref, memref +// CHECK: linalg.copy(%[[partialC]], %[[vC]]) : memref, memref // // CHECK: dealloc %[[tmpA]] : memref<32xi8> // CHECK: dealloc %[[tmpB]] : memref<48xi8> diff --git a/mlir/test/Dialect/Linalg/roundtrip.mlir b/mlir/test/Dialect/Linalg/roundtrip.mlir index bffe599..30704b5 100644 --- a/mlir/test/Dialect/Linalg/roundtrip.mlir +++ b/mlir/test/Dialect/Linalg/roundtrip.mlir @@ -115,16 +115,6 @@ func @conv_view6(%arg0: memref, %{{.*}}: memref, %{{.*}}: memref) { // CHECK: linalg.conv(%{{.*}}, %{{.*}}, %{{.*}}) {dilations = [4, 4, 5, 5], strides = [2, 2, 3, 3]} : memref, memref, memref -func @subview(%arg0: memref, offset: ?, strides: [?, 1]>) { - %c0 = constant 0 : index - %0 = linalg.subview %arg0[%c0, %c0, %c0, %c0, %c0, %c0] : memref, offset: ?, strides: [?, 1]> - return -} -// CHECK-LABEL: func @subview( -// CHECK: %{{.*}}: memref, #[[strided2D]]>) { -// CHECK: constant 0 : index -// CHECK: linalg.subview %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : memref, #[[strided2D]]> - #accesses = [ (i, j, k) -> (j, i), (i, j, k) -> (i, k, i + j) diff --git a/mlir/test/Dialect/Linalg/tile.mlir b/mlir/test/Dialect/Linalg/tile.mlir index 458cd0b..47a3552 100644 --- a/mlir/test/Dialect/Linalg/tile.mlir +++ b/mlir/test/Dialect/Linalg/tile.mlir @@ -3,13 +3,6 @@ // RUN: mlir-opt %s -linalg-tile -linalg-tile-sizes=0,0,2 | FileCheck %s -check-prefix=TILE-002 // RUN: mlir-opt %s -linalg-tile -linalg-tile-sizes=2,3,4 | FileCheck %s -check-prefix=TILE-234 -// TILE-2-DAG: #[[UB0:.*]] = (d0) -> (d0 + 2) -// TILE-02-DAG: #[[UB0:.*]] = (d0) -> (d0 + 2) -// TILE-002-DAG: #[[UB0:.*]] = (d0) -> (d0 + 2) -// TILE-234-DAG: #[[UB0:.*]] = (d0) -> (d0 + 2) -// TILE-234-DAG: #[[UB1:.*]] = (d0) -> (d0 + 3) -// TILE-234-DAG: #[[UB2:.*]] = (d0) -> (d0 + 4) - // TILE-2-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0) // TILE-02-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0) // TILE-002-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0) @@ -20,120 +13,135 @@ // TILE-002-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1) // TILE-234-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1) -// TILE-2-DAG: #[[stride_99_1_layout_map:.*]] = (d0, d1)[s0] -> (d0 * 99 + s0 + d1) -// TILE-02-DAG: #[[stride_99_1_layout_map:.*]] = (d0, d1)[s0] -> (d0 * 99 + s0 + d1) -// TILE-234-DAG: #[[stride_99_1_layout_map:.*]] = (d0, d1)[s0] -> (d0 * 99 + s0 + d1) +// TILE-2-DAG: #[[strided1D_dynamic:.*]] = (d0)[s0, s1] -> (d0 * s1 + s0) +// TILE-02-DAG: #[[strided1D_dynamic:.*]] = (d0)[s0, s1] -> (d0 * s1 + s0) +// T_ILE-002-DAG: #[[strided1D_dynamic:.*]] = (d0)[s0, s1] -> (d0 * s1 + s0) +// TILE-234-DAG: #[[strided1D_dynamic:.*]] = (d0)[s0, s1] -> (d0 * s1 + s0) + +// TILE-2-DAG: #[[strided2D_dynamic:.*]] = (d0, d1)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2) +// TILE-02-DAG: #[[strided2D_dynamic:.*]] = (d0, d1)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2) +// TILE-002-DAG: #[[strided2D_dynamic:.*]] = (d0, d1)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2) +// TILE-234-DAG: #[[strided2D_dynamic:.*]] = (d0, d1)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2) + +// REACTIVATE_ME_TILE-2-DAG: #[[stride_99_1_layout_map:.*]] = (d0, d1)[s0] -> (d0 * 99 + s0 + d1) +// REACTIVATE_ME_TILE-02-DAG: #[[stride_99_1_layout_map:.*]] = (d0, d1)[s0] -> (d0 * 99 + s0 + d1) +// REACTIVATE_ME_TILE-234-DAG: #[[stride_99_1_layout_map:.*]] = (d0, d1)[s0] -> (d0 * 99 + s0 + d1) func @matmul(%arg0: memref, %arg1: memref, %arg2: memref) { linalg.matmul(%arg0, %arg1, %arg2) : memref, memref, memref return } // TILE-2-LABEL: func @matmul( +// TILE-2-DAG: %[[C0:.*]] = constant 0 : index +// TILE-2-DAG: %[[C1:.*]] = constant 1 : index +// TILE-2-DAG: %[[C2:.*]] = constant 2 : index // TILE-2: %[[M:.*]] = dim %{{.*}}, 0 : memref -// TILE-2: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { -// TILE-2: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}}) +// TILE-2: loop.for %[[I:.*]] = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { // TILE-2: %[[K:.*]] = dim %{{.*}}, 1 : memref -// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}, %{{.*}}, %[[K]], %{{.*}}] : memref -// TILE-2: %[[c:.*]] = affine.apply #[[UB0]](%{{.*}}) +// TILE-2: %[[sAi:.*]] = std.subview %{{.*}}[%[[I]], %[[C0]]][%[[C2]], %[[K]]][%[[C1]], %[[C1]]] : memref to memref // TILE-2: %[[N:.*]] = dim %{{.*}}, 1 : memref -// TILE-2: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[c]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : memref -// TILE-2: linalg.matmul(%[[sAi]], %{{.*}}, %[[sCi]]) : memref, memref, memref +// TILE-2: %[[sCi:.*]] = std.subview %{{.*}}[%[[I]], %[[C0]]][%[[C2]], %[[N]]][%[[C1]], %[[C1]]] : memref to memref +// TILE-2: linalg.matmul(%[[sAi]], %{{.*}}, %[[sCi]]) : memref, memref, memref // TILE-02-LABEL: func @matmul( +// TILE-02-DAG: %[[C0:.*]] = constant 0 : index +// TILE-02-DAG: %[[C1:.*]] = constant 1 : index +// TILE-02-DAG: %[[C2:.*]] = constant 2 : index // TILE-02: %[[N:.*]] = dim %arg1, 1 : memref -// TILE-02: loop.for %{{.*}} = %{{.*}} to %[[N]] step %{{.*}} { +// TILE-02: loop.for %[[J:.*]] = %{{.*}} to %[[N]] step %{{.*}} { // TILE-02: %[[K:.*]] = dim %{{.*}}, 0 : memref -// TILE-02: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-02: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[K]], %{{.*}}, %{{.*}}, %[[b]], %{{.*}}] : memref +// TILE-02: %[[sBj:.*]] = std.subview %{{.*}}[%[[C0]], %[[J]]][%[[K]], %[[C2]]][%[[C1]], %[[C1]]] : memref to memref // TILE-02: %[[M:.*]] = dim %{{.*}}, 0 : memref -// TILE-02: %[[c:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-02: %[[sCj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[c]], %{{.*}}] : memref -// TILE-02: linalg.matmul(%{{.*}}, %[[sBj]], %[[sCj]]) : memref, memref, memref +// TILE-02: %[[sCj:.*]] = std.subview %{{.*}}[%[[C0]], %[[J]]][%[[M]], %[[C2]]][%[[C1]], %[[C1]]] : memref to memref +// TILE-02: linalg.matmul(%{{.*}}, %[[sBj]], %[[sCj]]) : memref, memref, memref // TILE-002-LABEL: func @matmul( -// TILE-002: %[[K:.*]] = dim %{{.*}}, 1 : memref -// TILE-002: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} { +// TILE-002-DAG: %[[C0:.*]] = constant 0 : index +// TILE-002-DAG: %[[C1:.*]] = constant 1 : index +// TILE-002-DAG: %[[C2:.*]] = constant 2 : index +// TILE-002: %[[ubK:.*]] = dim %{{.*}}, 1 : memref +// TILE-002: loop.for %[[K:.*]] = %{{.*}}{{.*}} to %[[ubK]] step %{{.*}} { // TILE-002: %[[M:.*]] = dim %{{.*}}, 0 : memref -// TILE-002: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-002: %[[sAj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[a]], %{{.*}}] : memref -// TILE-002: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}}) +// TILE-002: %[[sAj:.*]] = std.subview %{{.*}}[%[[C0]], %[[K]]][%[[M]], %[[C2]]][%[[C1]], %[[C1]]] : memref to memref // TILE-002: %[[N:.*]] = dim %{{.*}}, 1 : memref -// TILE-002: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : memref -// TILE-002: linalg.matmul(%[[sAj]], %[[sBj]], %{{.*}}) : memref, memref, memref +// TILE-002: %[[sBj:.*]] = std.subview %{{.*}}[%[[K]], %[[C0]]][%[[C2]], %[[N]]][%[[C1]], %[[C1]]] : memref to memref +// TILE-002: linalg.matmul(%[[sAj]], %[[sBj]], %{{.*}}) : memref, memref, memref // TILE-234-LABEL: func @matmul( -// TILE-234: %[[M:.*]] = dim %{{.*}}, 0 : memref -// TILE-234: %[[K:.*]] = dim %{{.*}}, 1 : memref -// TILE-234: %[[N:.*]] = dim %{{.*}}, 1 : memref -// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { -// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[N]] step %{{.*}} { -// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} { -// TILE-234: %[[ai:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-234: %[[ak:.*]] = affine.apply #[[UB2]](%{{.*}}) -// TILE-234: %[[sAik:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ai]], %{{.*}}, %{{.*}}, %[[ak]], %{{.*}}] : memref -// TILE-234: %[[bk:.*]] = affine.apply #[[UB2]](%{{.*}}) -// TILE-234: %[[bj:.*]] = affine.apply #[[UB1]](%{{.*}}) -// TILE-234: %[[sBkj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[bk]], %{{.*}}, %{{.*}}, %[[bj]], %{{.*}}] : memref -// TILE-234: %[[ci:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-234: %[[cj:.*]] = affine.apply #[[UB1]](%{{.*}}) -// TILE-234: %[[sCij:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ci]], %{{.*}}, %{{.*}}, %[[cj]], %{{.*}}] : memref +// TILE-234-DAG: %[[C0:.*]] = constant 0 : index +// TILE-234-DAG: %[[C1:.*]] = constant 1 : index +// TILE-234-DAG: %[[C2:.*]] = constant 2 : index +// TILE-234-DAG: %[[C3:.*]] = constant 3 : index +// TILE-234-DAG: %[[C4:.*]] = constant 4 : index +// TILE-234: %[[ubM:.*]] = dim %{{.*}}, 0 : memref +// TILE-234: %[[ubK:.*]] = dim %{{.*}}, 1 : memref +// TILE-234: %[[ubN:.*]] = dim %{{.*}}, 1 : memref +// TILE-234: loop.for %[[I:.*]] = %{{.*}}{{.*}} to %[[ubM]] step %{{.*}} { +// TILE-234: loop.for %[[J:.*]] = %{{.*}}{{.*}} to %[[ubN]] step %{{.*}} { +// TILE-234: loop.for %[[K:.*]] = %{{.*}}{{.*}} to %[[ubK]] step %{{.*}} { +// TILE-234: %[[sAik:.*]] = std.subview %{{.*}}[%[[I]], %[[K]]][%[[C2]], %[[C4]]][%[[C1]], %[[C1]]] : memref to memref +// TILE-234: %[[sBkj:.*]] = std.subview %{{.*}}[%[[K]], %[[J]]][%[[C4]], %[[C3]]][%[[C1]], %[[C1]]] : memref to memref +// TILE-234: %[[sCij:.*]] = std.subview %{{.*}}[%[[I]], %[[J]]][%[[C2]], %[[C3]]][%[[C1]], %[[C1]]] : memref to memref // -// TILE-234: linalg.matmul(%[[sAik]], %[[sBkj]], %[[sCij]]) : memref, memref, memref +// TILE-234: linalg.matmul(%[[sAik]], %[[sBkj]], %[[sCij]]) : memref, memref, memref func @matvec(%arg0: memref, %arg1: memref, %arg2: memref) { linalg.matvec(%arg0, %arg1, %arg2) : memref, memref, memref return } // TILE-2-LABEL: func @matvec( +// TILE-2-DAG: %[[C0:.*]] = constant 0 : index +// TILE-2-DAG: %[[C1:.*]] = constant 1 : index +// TILE-2-DAG: %[[C2:.*]] = constant 2 : index // TILE-2: %[[M:.*]] = dim %{{.*}}, 0 : memref -// TILE-2: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { -// TILE-2: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}}) +// TILE-2: loop.for %[[I]] = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { // TILE-2: %[[N:.*]] = dim %{{.*}}, 1 : memref -// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : memref -// TILE-2: %[[c:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-2: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[c]], %{{.*}}] : memref -// TILE-2: linalg.matvec(%[[sAi]], %{{.*}}, %[[sCi]]) : memref, memref, memref +// TILE-2: %[[sAi:.*]] = std.subview %{{.*}}[%[[I]], %[[C0]]][%[[C2]], %[[N]]][%[[C1]], %[[C1]]] : memref to memref +// TILE-2: %[[sCi:.*]] = std.subview %{{.*}}[%[[I]]][%[[C2]]][%[[C1]]] : memref to memref +// TILE-2: linalg.matvec(%[[sAi]], %{{.*}}, %[[sCi]]) : memref, memref, memref // TILE-02-LABEL: func @matvec( +// TILE-02-DAG: %[[C0:.*]] = constant 0 : index +// TILE-02-DAG: %[[C1:.*]] = constant 1 : index +// TILE-02-DAG: %[[C2:.*]] = constant 2 : index // TILE-02: %[[K:.*]] = dim %{{.*}}, 1 : memref -// TILE-02: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} { +// TILE-02: loop.for %[[J]] = %{{.*}}{{.*}} to %[[K]] step %{{.*}} { // TILE-02: %[[M:.*]] = dim %{{.*}}, 0 : memref -// TILE-02: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-02: %[[sAj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[a]], %{{.*}}] : memref -// TILE-02: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-02: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : memref -// TILE-02: linalg.matvec(%[[sAj]], %[[sBj]], %{{.*}}) : memref, memref, memref +// TILE-02: %[[sAj:.*]] = std.subview %{{.*}}[%[[C0]], %[[J]]][%[[M]], %[[C2]]][%[[C1]], %[[C1]]] : memref to memref +// TILE-02: %[[sBj:.*]] = std.subview %{{.*}}[%[[J]]][%[[C2]]][%[[C1]]] : memref to memref +// TILE-02: linalg.matvec(%[[sAj]], %[[sBj]], %{{.*}}) : memref, memref, memref // TILE-002-LABEL: func @matvec( // TILE-002-NOT: loop.for // TILE-234-LABEL: func @matvec( +// TILE-234-DAG: %[[C0:.*]] = constant 0 : index +// TILE-234-DAG: %[[C1:.*]] = constant 1 : index +// TILE-234-DAG: %[[C2:.*]] = constant 2 : index +// TILE-234-DAG: %[[C3:.*]] = constant 3 : index // TILE-234: %[[M:.*]] = dim %{{.*}}, 0 : memref // TILE-234: %[[K:.*]] = dim %{{.*}}, 1 : memref -// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { -// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} { -// TILE-234: %[[ai:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-234: %[[aj:.*]] = affine.apply #[[UB1]](%{{.*}}) -// TILE-234: %[[sAij:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ai]], %{{.*}}, %{{.*}}, %[[aj]], %{{.*}}] : memref -// TILE-234: %[[bj:.*]] = affine.apply #[[UB1]](%{{.*}}) -// TILE-234: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[bj]], %{{.*}}] : memref -// TILE-234: %[[ci:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-234: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ci]], %{{.*}}] : memref +// TILE-234: loop.for %[[I:.*]] = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { +// TILE-234: loop.for %[[J:.*]] = %{{.*}}{{.*}} to %[[K]] step %{{.*}} { +// TILE-234: %[[sAij:.*]] = std.subview %{{.*}}[%[[I]], %[[J]]][%[[C2]], %[[C3]]][%[[C1]], %[[C1]]] : memref to memref +// TILE-234: %[[sBj:.*]] = std.subview %{{.*}}[%[[J]]][%[[C3]]][%[[C1]]] : memref to memref +// TILE-234: %[[sCi:.*]] = std.subview %{{.*}}[%[[I]]][%[[C2]]][%[[C1]]] : memref to memref // -// TILE-234: linalg.matvec(%[[sAij]], %[[sBj]], %[[sCi]]) : memref, memref, memref +// TILE-234: linalg.matvec(%[[sAij]], %[[sBj]], %[[sCi]]) : memref, memref, memref func @dot(%arg0: memref, %arg1: memref, %arg2: memref) { linalg.dot(%arg0, %arg1, %arg2) : memref, memref, memref return } // TILE-2-LABEL: func @dot( +// TILE-2-DAG: %[[C0:.*]] = constant 0 : index +// TILE-2-DAG: %[[C1:.*]] = constant 1 : index +// TILE-2-DAG: %[[C2:.*]] = constant 2 : index // TILE-2: %[[M:.*]] = dim %{{.*}}, 0 : memref -// TILE-2: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { -// TILE-2: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}] : memref -// TILE-2: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-2: %[[sBi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : memref -// TILE-2: linalg.dot(%[[sAi]], %[[sBi]], {{.*}}) : memref, memref, memref +// TILE-2: loop.for %[[I]] = %{{.*}}{{.*}} to %[[M]] step %{{.*}} { +// TILE-2: %[[sAi:.*]] = std.subview %{{.*}}[%[[I]]][%[[C2]]][%[[C1]]] : memref to memref +// TILE-2: %[[sBi:.*]] = std.subview %{{.*}}[%[[I]]][%[[C2]]][%[[C1]]] : memref to memref +// TILE-2: linalg.dot(%[[sAi]], %[[sBi]], {{.*}}) : memref, memref, memref // TILE-02-LABEL: func @dot( // TILE-02-NOT: loop.for @@ -142,13 +150,14 @@ func @dot(%arg0: memref, %arg1: memref -// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} { -// TILE-234: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-234: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}] : memref -// TILE-234: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-234: %[[sBi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : memref -// TILE-234: linalg.dot(%[[sAi]], %[[sBi]], %{{.*}}) : memref, memref, memref +// TILE-234-DAG: %[[C0:.*]] = constant 0 : index +// TILE-234-DAG: %[[C1:.*]] = constant 1 : index +// TILE-234-DAG: %[[C2:.*]] = constant 2 : index +// TILE-234: %[[ubK:.*]] = dim %{{.*}}, 0 : memref +// TILE-234: loop.for %[[I:.*]] = %{{.*}} to %[[ubK]] step %{{.*}} { +// TILE-234: %[[sAi:.*]] = std.subview %{{.*}}[%[[I]]][%[[C2]]][%[[C1]]] : memref to memref +// TILE-234: %[[sBi:.*]] = std.subview %{{.*}}[%[[I]]][%[[C2]]][%[[C1]]] : memref to memref +// TILE-234: linalg.dot(%[[sAi]], %[[sBi]], %{{.*}}) : memref, memref, memref func @fill_static(%arg0: memref<127x99xf32>, %arg1: f32) { linalg.fill(%arg0, %arg1) : memref<127x99xf32>, f32 @@ -157,14 +166,14 @@ func @fill_static(%arg0: memref<127x99xf32>, %arg1: f32) { // TILE-2-LABEL: func @fill_static // TILE-2: for // TILE-2-NOT: for -// TILE-2: linalg.subview{{.*}} : memref<127x99xf32> -// TILE-2: linalg.fill{{.*}} : memref, f32 +// TILE-2: std.subview{{.*}} : memref<127x99xf32> +// TILE-2: linalg.fill{{.*}} : memref, f32 // TILE-02-LABEL: func @fill_static // TILE-02: for // TILE-02-NOT: for -// TILE-02: linalg.subview{{.*}} : memref<127x99xf32> -// TILE-02: linalg.fill{{.*}} : memref, f32 +// TILE-02: std.subview{{.*}} : memref<127x99xf32> +// TILE-02: linalg.fill{{.*}} : memref, f32 // TILE-002-LABEL: func @fill_static // TILE-002-NOT: for @@ -174,8 +183,8 @@ func @fill_static(%arg0: memref<127x99xf32>, %arg1: f32) { // TILE-234: for // TILE-234: for // TILE-234-NOT: for -// TILE-234: linalg.subview{{.*}} : memref<127x99xf32> -// TILE-234: linalg.fill{{.*}} : memref, f32 +// TILE-234: std.subview{{.*}} : memref<127x99xf32> +// TILE-234: linalg.fill{{.*}} : memref, f32 func @fill(%arg0: memref, %arg1: f32) { diff --git a/mlir/test/Dialect/Linalg/tile_conv.mlir b/mlir/test/Dialect/Linalg/tile_conv.mlir index f1ecacf..64c55cb 100644 --- a/mlir/test/Dialect/Linalg/tile_conv.mlir +++ b/mlir/test/Dialect/Linalg/tile_conv.mlir @@ -1,11 +1,9 @@ // RUN: mlir-opt %s -linalg-tile -linalg-tile-sizes=2,3,0,0,4 | FileCheck %s -check-prefix=TILE-23004 -// TILE-23004-DAG: #[[UB0:.*]] = (d0) -> (d0 + 2) -// TILE-23004-DAG: #[[UB1:.*]] = (d0) -> (d0 + 3) -// TILE-23004-DAG: #[[UB2:.*]] = (d0) -> (d0 + 4) // TILE-23004-DAG: #[[D0x30pS0x10:.*]] = (d0) -> (d0 * 30) -// TILE-23004-DAG: #[[D0x30pS0x10p90:.*]] = (d0)[s0] -> (d0 * 30 + s0 * 10 + 90) +// TILE-23004-DAG: #[[S0x10p90:.*]] = ()[s0] -> (s0 * 10 + 90) // TILE-23004-DAG: #[[strided4D:.*]] = (d0, d1, d2, d3)[s0, s1, s2, s3] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3 + d3) +// TILE-23004-DAG: #[[strided4D_dynamic:.*]] = (d0, d1, d2, d3)[s0, s1, s2, s3, s4] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3 + d3 * s4) func @conv(%arg0: memref, %arg1: memref, %arg2: memref) { linalg.conv(%arg0, %arg1, %arg2) {dilations = [10, 20], strides = [30, 40]} : memref, memref, memref @@ -13,30 +11,30 @@ func @conv(%arg0: memref, %arg1: } // TILE-23004-LABEL: func @conv( // TILE-23004: %{{.*}}: memref, %{{.*}}: memref, %{{.*}}: memref) { +// TILE-23004-DAG: %[[C0:.*]] = constant 0 : index +// TILE-23004-DAG: %[[C1:.*]] = constant 1 : index +// TILE-23004-DAG: %[[C2:.*]] = constant 2 : index +// TILE-23004-DAG: %[[C3:.*]] = constant 3 : index +// TILE-23004-DAG: %[[C4:.*]] = constant 4 : index // TILE-23004: %[[Q:.*]] = dim %{{.*}}, 2 : memref // TILE-23004: %[[B:.*]] = dim %{{.*}}, 0 : memref // TILE-23004: %[[PaddedInput0:.*]] = dim %{{.*}}, 1 : memref // TILE-23004: %[[X0:.*]] = dim %{{.*}}, 1 : memref -// TILE-23004: loop.for %{{.*}} = %{{.*}} to %[[B]] step %{{.*}} { -// TILE-23004: loop.for %{{.*}} = %{{.*}} to %[[X0]] step %{{.*}} { -// TILE-23004: loop.for %{{.*}} = %{{.*}} to %[[Q]] step %{{.*}} { -// TILE-23004: %[[Z0:.*]] = dim %{{.*}}, 0 : memref +// TILE-23004: loop.for %[[ivI:.*]] = %{{.*}} to %[[B]] step %{{.*}} { +// TILE-23004: loop.for %[[ivJ:.*]] = %{{.*}} to %[[X0]] step %{{.*}} { +// TILE-23004: loop.for %[[ivK:.*]] = %{{.*}} to %[[Q]] step %{{.*}} { +// TILE-23004: %[[Z0:.*]] = dim %{{.*}}, 0 : memref // TILE-23004: %[[Z1:.*]] = dim %{{.*}}, 1 : memref -// TILE-23004: %[[I2p4:.*]] = affine.apply #[[UB2]](%{{.*}}) // TILE-23004: %[[K:.*]] = dim %{{.*}}, 3 : memref -// TILE-23004: %[[FilterView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[Z0]], %{{.*}}, %{{.*}}, %[[Z1]], %{{.*}}, %{{.*}}, %[[I2p4]], %{{.*}}, %{{.*}}, %[[K]], %{{.*}}] : memref +// TILE-23004: %[[FilterView:.*]] = std.subview %{{.*}}[%[[C0]], %[[C0]], %[[ivK]], %[[C0]]][%[[Z0]], %[[Z1]], %[[C4]], %[[K]]][%[[C1]], %[[C1]], %[[C1]], %[[C1]]] : memref to memref // -// TILE-23004: %[[I0p3:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-23004: %[[I1:.*]] = affine.apply #[[D0x30pS0x10]](%{{.*}}) -// TILE-23004: %[[I1pStep:.*]] = affine.apply #[[D0x30pS0x10p90]](%{{.*}})[%[[PaddedInput0]]] +// TILE-23004: %[[J1:.*]] = affine.apply #[[D0x30pS0x10]](%[[ivJ]]) +// T__ILE-23004: %[[I1pStep:.*]] = affine.apply #[[S0x10p90]]()[%[[I1]]] // TILE-23004: %[[SZ2:.*]] = dim %{{.*}}, 2 : memref -// TILE-23004: %[[I2p2:.*]] = affine.apply #[[UB2]](%{{.*}}) -// TILE-23004: %[[InputView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[I0p3]], %{{.*}}, %[[I1]], %[[I1pStep]], %{{.*}}, %{{.*}}, %[[SZ2]], %{{.*}}, %{{.*}}, %[[I2p2]], %{{.*}}] : memref +// TILE-23004: %[[InputView:.*]] = std.subview %{{.*}}[%[[ivI]], %[[J1]], %[[C0]], %[[ivK]]][%[[C2]], %{{.*}}, %[[SZ2]], %[[C4]]][%[[C1]], %[[C1]], %[[C1]], %[[C1]]] : memref to memref // -// TILE-23004: %[[B:.*]] = affine.apply #[[UB0]](%{{.*}}) -// TILE-23004: %[[I1p3:.*]] = affine.apply #[[UB1]](%{{.*}}) // TILE-23004: %[[X0:.*]] = dim %{{.*}}, 2 : memref // TILE-23004: %[[X1:.*]] = dim %{{.*}}, 3 : memref -// TILE-23004: %[[OutputView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[B]], %{{.*}}, %{{.*}}, %[[I1p3]], %{{.*}}, %{{.*}}, %[[X0]], %{{.*}}, %{{.*}}, %[[X1]], %{{.*}}] : memref +// TILE-23004: %[[OutputView:.*]] = std.subview %{{.*}}[%[[ivI]], %[[ivJ]], %[[C0]], %[[C0]]][%[[C2]], %[[C3]], %[[X0]], %[[X1]]][%[[C1]], %[[C1]], %[[C1]], %[[C1]]] : memref to memref // -// TILE-23004: linalg.conv(%[[FilterView]], %[[InputView]], %[[OutputView]]) {dilations = [10, 20], strides = [30, 40]} : memref, memref, memref +// TILE-23004: linalg.conv(%[[FilterView]], %[[InputView]], %[[OutputView]]) {dilations = [10, 20], strides = [30, 40]} : memref, memref, memref -- 2.7.4