18#include "llvm/ADT/SmallVector.h"
23#define GEN_PASS_DEF_LINALGBLOCKPACKMATMUL
24#include "mlir/Dialect/Linalg/Passes.h.inc"
33 if (!stride || *stride != 1)
41 return (*size - *offset);
48 if (dims.size() != tiles.size() || tiles.empty())
51 FailureOr<ContractionDimensions> contractDims =
53 if (failed(contractDims))
55 unsigned batchDimsOffset = contractDims->batch.size();
60 for (
int64_t &offsetDim : offsetDims)
61 offsetDim += batchDimsOffset;
63 auto tileOp = cast<TilingInterface>(linalgOp.getOperation());
68 for (
auto dim : llvm::enumerate(offsetDims)) {
69 if (dim.value() >=
static_cast<int64_t>(iterationDomain.size()))
73 std::optional<int64_t> rangeOnDim =
78 if (!tileSize || !rangeOnDim)
82 if (*rangeOnDim % *tileSize != 0)
90static FailureOr<PackTransposeResult>
92 linalg::PackOp packOp,
AffineMap operandMap,
94 bool transposeOuterBlocks,
bool transposeInnerBlocks) {
96 if (!packOp.hasPureTensorSemantics())
100 "expected at least 4D prepacked matmul");
101 assert(blocksStartDimPos.size() >= 2 &&
102 "expected starting outer and inner block positions");
112 bool isOuterTransposed =
113 operandMap.
getDimPosition(outerBlockPos) != blocksStartDimPos.end()[-2];
114 bool isInnerTransposed =
115 operandMap.
getDimPosition(innerBlockPos) != blocksStartDimPos.back();
120 if (isInnerTransposed != transposeInnerBlocks)
123 if (isOuterTransposed != transposeOuterBlocks)
129 for (
auto i : llvm::seq(0u, outerBlockPos))
130 offsetPerms.push_back(i);
131 for (
auto perm : outerPerm)
132 offsetPerms.push_back(perm + outerBlockPos);
133 outerPerm = offsetPerms;
135 FailureOr<PackTransposeResult> packTransposedMatmul =
137 nullptr, outerPerm, innerPerm);
139 return packTransposedMatmul;
148 if (
auto *batchMatmulOp = dyn_cast<linalg::BatchMatmulOp>(&linalgOp)) {
149 if (batchMatmulOp->hasUserDefinedMaps()) {
152 "only batch_matmul ops with non-extended semantics are supported");
156 if (linalgOp.hasPureBufferSemantics())
159 std::optional<BlockPackMatmulOptions>
options = controlPackMatmul(linalgOp);
163 if (
options->blockFactors.size() != 3)
166 bool hasScalable = !
options->scalableBlockFactors.empty();
167 if (hasScalable &&
options->scalableBlockFactors.size() != 3)
169 linalgOp,
"scalableBlockFactors must be empty or have 3 elements");
174 if (!
options->allowPadding && hasScalable)
176 linalgOp,
"scalable block factors require padding");
179 for (
auto [idx, factor] : llvm::enumerate(
options->blockFactors)) {
180 bool isScalable = hasScalable &&
options->scalableBlockFactors[idx];
187 Value vscale = vector::VectorScaleOp::create(rewriter, linalgOp.getLoc(),
190 arith::MulIOp::create(rewriter, linalgOp.getLoc(), cst, vscale)
198 "expect packing full tiles only");
210 rewriter, linalgOp, mnkTiles,
options->mnkPaddedSizesNextMultipleOf,
212 if (failed(packedMatmul))
215 assert(packedMatmul->packOps.size() == 3 &&
216 "invalid number of pack ops after matmul packing");
217 assert(packedMatmul->unPackOps.size() == 1 &&
218 "invalid number of unpack ops after matmul packing");
220 FailureOr<ContractionDimensions> contractDims =
222 if (failed(contractDims))
226 dyn_cast<linalg::GenericOp>(packedMatmul->packedLinalgOp.getOperation());
231 rewriter, packedMatmul->packedLinalgOp, packedMatmul->packOps[0], maps[0],
232 contractDims->m,
options->lhsTransposeOuterBlocks,
233 options->lhsTransposeInnerBlocks);
234 if (failed(packedLhs))
238 packedMatmul->packOps[0] = packedLhs->transposedPackOp;
239 packedMatmul->packedLinalgOp = packedLhs->transposedLinalgOp;
243 rewriter, packedMatmul->packedLinalgOp, packedMatmul->packOps[1], maps[1],
244 contractDims->k,
options->rhsTransposeOuterBlocks,
245 options->rhsTransposeInnerBlocks);
246 if (failed(packedRhs))
250 packedMatmul->packOps[1] = packedRhs->transposedPackOp;
251 packedMatmul->packedLinalgOp = packedRhs->transposedLinalgOp;
257template <
typename OpTy>
263 LogicalResult matchAndRewrite(OpTy linalgOp,
265 FailureOr<PackResult> packedMatmul =
267 if (failed(packedMatmul))
277struct BlockPackMatmul<
linalg::GenericOp>
280 PatternBenefit benefit = 1)
281 : OpRewritePattern<linalg::GenericOp>(context, benefit),
282 controlFn(std::move(fun)) {}
284 LogicalResult matchAndRewrite(linalg::GenericOp linalgOp,
285 PatternRewriter &rewriter)
const override {
291 using MapList = ArrayRef<ArrayRef<AffineExpr>>;
292 auto infer = [&](MapList m) {
297 bindDims(linalgOp->getContext(), i, j, k);
298 SmallVector<AffineMap> maps = linalgOp.getIndexingMapsArray();
301 if (!(maps == infer({{i, k}, {k, j}, {i, j}}) ||
302 maps == infer({{k, i}, {k, j}, {i, j}}) ||
303 maps == infer({{i, k}, {j, k}, {i, j}}))) {
307 FailureOr<PackResult> packedMatmul =
319struct LinalgBlockPackMatmul
321 using LinalgBlockPackMatmulBase::LinalgBlockPackMatmulBase;
323 void runOnOperation()
override {
324 Operation *op = getOperation();
328 [&](linalg::LinalgOp op) -> BlockPackMatmulOptions {
329 BlockPackMatmulOptions
options;
333 for (
const std::string &blockFactor : *blockFactors) {
334 StringRef factor(blockFactor);
335 if (factor.starts_with(
"[") && factor.ends_with(
"]")) {
337 factor.drop_front().drop_back().getAsInteger(10, val);
338 options.blockFactors.push_back(val);
339 options.scalableBlockFactors.push_back(
true);
342 factor.getAsInteger(10, val);
343 options.blockFactors.push_back(val);
344 options.scalableBlockFactors.push_back(
false);
349 if (llvm::none_of(
options.scalableBlockFactors, [](
bool b) { return b; }))
350 options.scalableBlockFactors.clear();
352 options.allowPadding = allowPadding;
353 options.mnkPaddedSizesNextMultipleOf =
354 SmallVector<int64_t>{*mnkPaddedSizesNextMultipleOf};
355 if (!mnkOrder.empty())
356 options.mnkOrder = SmallVector<int64_t>{*mnkOrder};
357 options.lhsTransposeOuterBlocks = lhsTransposeOuterBlocks;
358 options.lhsTransposeInnerBlocks = lhsTransposeInnerBlocks;
359 options.rhsTransposeOuterBlocks = rhsTransposeOuterBlocks;
373 patterns.
add<BlockPackMatmul<linalg::GenericOp>,
374 BlockPackMatmul<linalg::MatmulOp>,
375 BlockPackMatmul<linalg::BatchMatmulOp>>(patterns.
getContext(),
static FailureOr< PackTransposeResult > transposePackedMatmul(RewriterBase &rewriter, linalg::LinalgOp linalgOp, linalg::PackOp packOp, AffineMap operandMap, ArrayRef< unsigned > blocksStartDimPos, bool transposeOuterBlocks, bool transposeInnerBlocks)
Return failure or packed matmul with one of its operands transposed.
static bool validateFullTilesOnDims(linalg::LinalgOp linalgOp, ArrayRef< OpFoldResult > tiles, ArrayRef< int64_t > dims)
Return true if all dimensions are fully divisible by the respective tiles.
static std::optional< int64_t > getConstantRange(const Range &range)
Return constant range span or nullopt, otherwise.
static llvm::ManagedStatic< PassManagerOptions > options
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
unsigned getDimPosition(unsigned idx) const
Extracts the position of the dimensional expression at the given result, when the caller knows it is ...
unsigned getNumDims() const
unsigned getNumResults() const
static SmallVector< AffineMap, 4 > inferFromExprList(ArrayRef< ArrayRef< AffineExpr > > exprsList, MLIRContext *context)
Returns a vector of AffineMaps; each with as many results as exprs.size(), as many dims as the larges...
IntegerAttr getIndexAttr(int64_t value)
MLIRContext is the top-level object for a collection of MLIR operations.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
void signalPassFailure()
Signal that some invariant was broken when running.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
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,...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
::mlir::Pass::Option< bool > rhsTransposeInnerBlocks
void populateBlockPackMatmulPatterns(RewritePatternSet &patterns, const ControlBlockPackMatmulFn &controlFn)
Patterns to block pack Linalg matmul ops.
FailureOr< PackTransposeResult > packTranspose(RewriterBase &rewriter, linalg::PackOp packOp, linalg::LinalgOp linalgOp, linalg::UnPackOp maybeUnPackOp, ArrayRef< int64_t > outerPerm, ArrayRef< int64_t > innerPerm)
Transpose a single PackOp -> LinalgOp -> UnPackOp chain and return the transposed PackOp -> LinalgOp ...
std::function< std::optional< BlockPackMatmulOptions >(linalg::LinalgOp)> ControlBlockPackMatmulFn
Function type which is used to control matmul packing.
FailureOr< PackResult > blockPackMatmul(RewriterBase &rewriter, linalg::LinalgOp linalgOp, const ControlBlockPackMatmulFn &controlPackMatmul)
Pack a matmul operation into blocked 4D layout.
FailureOr< ContractionDimensions > inferContractionDims(LinalgOp linalgOp)
Find at least 2 parallel (m and n) and 1 reduction (k) dimension candidates that form a matmul subcom...
FailureOr< PackResult > packMatmulGreedily(RewriterBase &rewriter, LinalgOp linalgOp, ArrayRef< OpFoldResult > mnkPackedSizes, ArrayRef< int64_t > mnkPaddedSizesNextMultipleOf, ArrayRef< int64_t > mnkOrder)
Pack a LinalgOp by greedily inferring matmul dimensions (m, n, k) where m and n are proper parallel d...
bool isaContractionOpInterface(LinalgOp linalgOp)
Checks whether linalgOp conforms to ContractionOpInterface.
Include the generated interface declarations.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...