30 #include "llvm/ADT/DenseMap.h"
31 #include "llvm/ADT/DenseSet.h"
32 #include "llvm/ADT/SmallPtrSet.h"
33 #include "llvm/Support/CommandLine.h"
34 #include "llvm/Support/Debug.h"
35 #include "llvm/Support/raw_ostream.h"
39 #define GEN_PASS_DEF_AFFINELOOPINVARIANTCODEMOTION
40 #include "mlir/Dialect/Affine/Passes.h.inc"
44 #define DEBUG_TYPE "licm"
55 struct LoopInvariantCodeMotion
56 :
public affine::impl::AffineLoopInvariantCodeMotionBase<
57 LoopInvariantCodeMotion> {
58 void runOnOperation()
override;
59 void runOnAffineForOp(AffineForOp forOp);
65 SmallPtrSetImpl<Operation *> &opsWithUsers,
66 SmallPtrSetImpl<Operation *> &opsToHoist);
68 SmallPtrSetImpl<Operation *> &opsWithUsers,
69 SmallPtrSetImpl<Operation *> &opsToHoist);
74 SmallPtrSetImpl<Operation *> &opsWithUsers,
75 SmallPtrSetImpl<Operation *> &opsToHoist);
79 SmallPtrSetImpl<Operation *> &opsWithUsers,
80 SmallPtrSetImpl<Operation *> &opsToHoist) {
81 LLVM_DEBUG(llvm::dbgs() <<
"iterating on op: " << op;);
83 if (
auto ifOp = dyn_cast<AffineIfOp>(op)) {
87 }
else if (
auto forOp = dyn_cast<AffineForOp>(op)) {
89 opsWithUsers, opsToHoist))
91 }
else if (
auto parOp = dyn_cast<AffineParallelOp>(op)) {
93 opsWithUsers, opsToHoist))
96 !isa<AffineReadOpInterface, AffineWriteOpInterface,
97 AffinePrefetchOp>(&op)) {
103 opsWithUsers.insert(&op);
104 if (isa<AffineReadOpInterface, AffineWriteOpInterface>(op)) {
105 auto read = dyn_cast<AffineReadOpInterface>(op);
106 Value memref = read ? read.getMemRef()
107 : cast<AffineWriteOpInterface>(op).getMemRef();
108 for (
auto *user : memref.
getUsers()) {
111 if (isa<AffineDmaStartOp, AffineDmaWaitOp>(user))
116 if (isa<AffineWriteOpInterface>(user) ||
117 (isa<AffineReadOpInterface>(user) &&
118 isa<AffineWriteOpInterface>(op))) {
131 LLVM_DEBUG(llvm::dbgs() <<
"Non-constant op with 0 operands\n");
145 LLVM_DEBUG(llvm::dbgs() <<
"Loop IV is the operand\n");
150 if (llvm::is_contained(iterArgs, op.
getOperand(i))) {
151 LLVM_DEBUG(llvm::dbgs() <<
"One of the iter_args is the operand\n");
156 LLVM_DEBUG(llvm::dbgs() << *operandSrc <<
"Iterating on operand src\n");
161 if (opsWithUsers.count(operandSrc) && opsToHoist.count(operandSrc) == 0)
167 opsToHoist.insert(&op);
175 SmallPtrSetImpl<Operation *> &opsWithUsers,
176 SmallPtrSetImpl<Operation *> &opsToHoist) {
178 for (
auto &b : blockList) {
191 SmallPtrSetImpl<Operation *> &opsWithUsers,
192 SmallPtrSetImpl<Operation *> &opsToHoist) {
194 opsWithUsers, opsToHoist))
198 opsWithUsers, opsToHoist))
204 void LoopInvariantCodeMotion::runOnAffineForOp(AffineForOp forOp) {
205 auto *loopBody = forOp.getBody();
206 auto indVar = forOp.getInductionVar();
207 ValueRange iterArgs = forOp.getRegionIterArgs();
216 for (
auto &op : *loopBody) {
221 opsWithUsers.insert(&op);
222 if (!isa<AffineYieldOp>(op)) {
224 opsToMove.push_back(&op);
231 for (
auto *op : opsToMove) {
235 LLVM_DEBUG(forOp->print(llvm::dbgs() <<
"Modified loop\n"));
238 void LoopInvariantCodeMotion::runOnOperation() {
242 getOperation().walk([&](AffineForOp op) {
243 LLVM_DEBUG(op->
print(llvm::dbgs() <<
"\nOriginal loop\n"));
244 runOnAffineForOp(op);
248 std::unique_ptr<OperationPass<func::FuncOp>>
250 return std::make_unique<LoopInvariantCodeMotion>();
static bool isOpLoopInvariant(Operation &op, Value indVar, ValueRange iterArgs, SmallPtrSetImpl< Operation * > &opsWithUsers, SmallPtrSetImpl< Operation * > &opsToHoist)
static bool areAllOpsInTheBlockListInvariant(Region &blockList, Value indVar, ValueRange iterArgs, SmallPtrSetImpl< Operation * > &opsWithUsers, SmallPtrSetImpl< Operation * > &opsToHoist)
static bool checkInvarianceOfNestedIfOps(AffineIfOp ifOp, Value indVar, ValueRange iterArgs, SmallPtrSetImpl< Operation * > &opsWithUsers, SmallPtrSetImpl< Operation * > &opsToHoist)
This class helps build Operations.
Operation is the basic unit of execution within MLIR.
bool use_empty()
Returns true if this operation has no uses.
Value getOperand(unsigned idx)
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
unsigned getNumOperands()
void moveBefore(Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
void print(raw_ostream &os) const
user_range getUsers() const
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
std::unique_ptr< OperationPass< func::FuncOp > > createAffineLoopInvariantCodeMotionPass()
Creates a loop invariant code motion pass that hoists loop invariant operations out of affine loops.
AffineForOp getForInductionVarOwner(Value val)
Returns the loop parent of an induction variable.
void getAffineForIVs(Operation &op, SmallVectorImpl< AffineForOp > *loops)
Populates 'loops' with IVs of the affine.for ops surrounding 'op' ordered from the outermost 'affine....
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
bool isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.