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 accValue.replaceAllUsesWith(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 resultUserOp->replaceUsesOfWith(contractValue, addition);
109 return success();
110 }
111};
112
113} // namespace
114
116 RewritePatternSet &patterns) {
117 patterns.add<MoveAccumulatorForContractLoop>(patterns.getContext());
118}
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,...
Type getType() const
Return the type of this value.
Definition Value.h:105
void replaceAllUsesWith(Value newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
Definition Value.h:149
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...