MLIR 24.0.0git
MoveAccumulatorForContractLoop.cpp
Go to the documentation of this file.
1//===- MoveAccumulatorForContractLoop.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
15
17#include "mlir/IR/Dominance.h"
19#include "llvm/Support/Casting.h"
20
21#include "mlir/Pass/Pass.h"
23
24using namespace mlir;
25using namespace mlir::vector;
26using namespace mlir::x86;
27
28namespace {
29// Transforms vector.contract(A, B, Acc) into vector.contract(A, B, 0) + Acc
30// to decouple the contraction computation from the accumulator update.
31struct MoveAccumulatorForContractLoop
32 : public OpRewritePattern<vector::ContractionOp> {
33 using OpRewritePattern<vector::ContractionOp>::OpRewritePattern;
34
35 LogicalResult matchAndRewrite(vector::ContractionOp contractOp,
36 PatternRewriter &rewriter) const override {
37
38 if (contractOp.getKind() != vector::CombiningKind::ADD)
39 return rewriter.notifyMatchFailure(contractOp,
40 "Expects add combining kind.");
41
42 Operation *accReadOp =
43 traceToVectorReadLikeParentOperation(contractOp.getAcc());
44
45 Value contractValue = contractionUsersAfterYield(contractOp.getResult());
46
47 if (!contractValue)
48 return rewriter.notifyMatchFailure(
49 contractOp, "Final acc write might have multiple users.");
50
51 Operation *resultUserOp = *contractValue.getUsers().begin();
52
53 if (!accReadOp || !resultUserOp)
54 return rewriter.notifyMatchFailure(
55 contractOp, "Read from acc matrix is not by "
56 "transfer_read/load/constant_zero or multiple users of "
57 "contract operation.");
58
59 if (isa<arith::ConstantOp>(accReadOp))
60 return rewriter.notifyMatchFailure(
61 contractOp,
62 "The input acc to contract is already a constant vector.");
63
64 if ((accReadOp->getBlock() == contractOp->getBlock()) ||
65 (resultUserOp->getBlock() == contractOp->getBlock()))
66 return rewriter.notifyMatchFailure(
67 contractOp, "Acc read/write should be in a separate block.");
68
69 // Replace acc of a contraction operation with vector constant.
70 Value accValue = accReadOp->getResult(0);
71 if (!accValue.hasOneUse())
72 return rewriter.notifyMatchFailure(
73 contractOp, "The input accumulator has multiple users.");
74
75 Operation *firstUser = *accValue.getUsers().begin();
76 rewriter.setInsertionPoint(firstUser);
77
78 auto vecTy = dyn_cast<VectorType>(accValue.getType());
79 if (!vecTy)
80 return rewriter.notifyMatchFailure(contractOp, "Expects vector type.");
81
82 Location loc = accReadOp->getLoc();
83 Type elemTy = vecTy.getElementType();
84
85 Value zeroVec = arith::ConstantOp::create(
86 rewriter, loc,
87 DenseElementsAttr::get(vecTy, rewriter.getZeroAttr(elemTy)));
88
89 rewriter.replaceAllUsesWith(accValue, zeroVec);
90
91 // Adds the initial acc value with contract results before storing to acc
92 // matrix.
93 rewriter.setInsertionPoint(resultUserOp);
94 Location locUser = resultUserOp->getLoc();
95
96 Value addition;
97
98 if (isa<FloatType>(elemTy)) {
99 addition =
100 arith::AddFOp::create(rewriter, locUser, contractValue, accValue);
101 } else if (isa<IntegerType>(elemTy)) {
102 addition =
103 arith::AddIOp::create(rewriter, locUser, contractValue, accValue);
104 } else {
105 llvm_unreachable("expected floating-point or integer element type");
106 }
107
108 rewriter.modifyOpInPlace(resultUserOp, [&]() {
109 resultUserOp->replaceUsesOfWith(contractValue, addition);
110 });
111 return success();
112 }
113};
114
115} // namespace
116
118 RewritePatternSet &patterns) {
119 patterns.add<MoveAccumulatorForContractLoop>(patterns.getContext());
120}
return success()
TypedAttr getZeroAttr(Type type)
Definition Builders.cpp:333
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Definition Builders.h:401
void replaceUsesOfWith(Value from, Value to)
Replace any uses of 'from' with 'to' within this operation.
Block * getBlock()
Returns the operation block that contains this operation.
Definition Operation.h:230
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:432
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
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.
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.
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
Type getType() const
Return the type of this value.
Definition Value.h:105
user_range getUsers() const
Definition Value.h:218
bool hasOneUse() const
Returns true if this value has exactly one use.
Definition Value.h:197
Value contractionUsersAfterYield(Value v)
Definition X86Utils.cpp:149
Operation * traceToVectorReadLikeParentOperation(Value v)
Definition X86Utils.cpp:173
void populateMoveAccumulatorForContractLoopPatterns(RewritePatternSet &patterns)
Include the generated interface declarations.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...