diff --git a/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h b/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h --- a/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h +++ b/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h @@ -234,6 +234,20 @@ } }; +/// Creates a new buffer using the `allocationFn` provided. The size of this +/// buffer is the smallest constant bounding size along each dimension that can +/// be computed for the size of the result of `subView`. Returns the allocated +/// buffer as `fullLocalView` and the view that matches the size of the result +/// of subview operation as `partialLocalView`. +struct PromotionInfo { + Value fullLocalView; + Value partialLocalView; +}; +Optional +promoteSubviewAsNewBuffer(OpBuilder &b, Location loc, SubViewOp subView, + AllocBufferCallbackFn allocationFn, + OperationFolder *folder = nullptr); + /// Promotes the `subViews` into a new buffer allocated at the insertion point /// `b`. Promotion occurs in 3 steps: /// 1. Create a new buffer for a full tile (i.e. not clipped at the boundary). diff --git a/mlir/include/mlir/Dialect/Linalg/Utils/Utils.h b/mlir/include/mlir/Dialect/Linalg/Utils/Utils.h --- a/mlir/include/mlir/Dialect/Linalg/Utils/Utils.h +++ b/mlir/include/mlir/Dialect/Linalg/Utils/Utils.h @@ -17,6 +17,7 @@ #include "mlir/Dialect/StandardOps/EDSC/Intrinsics.h" #include "mlir/Dialect/StandardOps/IR/Ops.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" using mlir::edsc::intrinsics::AffineIndexedValue; @@ -82,6 +83,13 @@ bool isFusableInto(const LinalgDependenceGraph &graph, LinalgOp consumer, Value consumedView, LinalgOp producer); +using FusableOpDependencesTy = llvm::MapVector< + Operation *, + SmallVector>; +FusableOpDependencesTy +findAllFusableDependences(ArrayRef ops, + const LinalgDependenceGraph &dependenceGraph); + /// Fuses producer into consumer if the producer is structurally feasible and /// the fusion would not violate dependencies. /// Implements the fusion part of the "tileAndFuse on buffers" diff --git a/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp b/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp --- a/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp +++ b/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp @@ -542,10 +542,6 @@ return getProjectedMap(map, projectedDims); } -using FusableOpDependencesTy = llvm::MapVector< - Operation *, - SmallVector>; - /// Returns the mapping from iterations in the consumer that write to the same /// location as the iterations in the producer. To do so use /// - indexing map of the fused view in the consumer : consumerIndexMap @@ -729,10 +725,9 @@ return fusableLoops; } -/// Find all dependences that are to be fusable. -static FusableOpDependencesTy -findAllFusableDependences(ArrayRef ops, - const LinalgDependenceGraph &dependenceGraph) { +/// Find all dependences that are fusable. +FusableOpDependencesTy mlir::linalg::findAllFusableDependences( + ArrayRef ops, const LinalgDependenceGraph &dependenceGraph) { FusableOpDependencesTy fusableDependences; // TODO: Currently fusion would not be legal if the fusable dependence is to // the same producer but different indexing map in the consumer. Fix this, but @@ -836,6 +831,7 @@ fusedLoopsAndRanges[loop] = getRangeFromOperandShape( builder, tiledOp.getLoc(), shapeDim.shape, shapeDim.dimension); } + SmallVector fusedOps(fusionCandidates.size()); for (auto candidate : enumerate(llvm::reverse(fusionCandidates))) { LinalgOp fusedOp = fuse(builder, candidate.value(), fusedLoopsAndRanges); diff --git a/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp b/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp --- a/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp +++ b/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp @@ -166,11 +166,6 @@ /// Alignment of promoted buffer. Optional alignment; }; - -struct PromotionInfo { - Value fullLocalView; - Value partialLocalView; -}; } // namespace LinalgOpInstancePromotionOptions::LinalgOpInstancePromotionOptions( @@ -233,10 +228,10 @@ // To account for general boundary effects, padding must be performed on the // boundary tiles. For now this is done with an unconditional `fill` op followed // by a partial `copy` op. -static Optional -promoteSubviewAsNewBuffer(OpBuilder &b, Location loc, SubViewOp subView, - LinalgOpInstancePromotionOptions const &options, - OperationFolder *folder) { +Optional mlir::linalg::promoteSubviewAsNewBuffer( + OpBuilder &b, Location loc, SubViewOp subView, + AllocBufferCallbackFn allocationFn, OperationFolder *folder) { + ScopedContext scopedContext(b, loc); auto viewType = subView.getType(); auto rank = viewType.getRank(); SmallVector fullSizes, partialSizes; @@ -254,8 +249,7 @@ SmallVector dynSizes(fullSizes.size(), -1); // If a callback is not specified, then use the default implementation for // allocating the promoted buffer. - Optional fullLocalView = - options.allocationFn(b, subView, fullSizes, folder); + Optional fullLocalView = allocationFn(b, subView, fullSizes, folder); if (!fullLocalView) return {}; auto zero = folded_std_constant_index(folder, 0); @@ -279,8 +273,8 @@ for (auto v : options.subViews) { SubViewOp subView = cast(v.second.getDefiningOp()); - Optional promotionInfo = - promoteSubviewAsNewBuffer(b, loc, subView, options, folder); + Optional promotionInfo = promoteSubviewAsNewBuffer( + b, loc, subView, options.allocationFn, folder); if (!promotionInfo) return {}; promotionInfoMap[v.first] = *promotionInfo;