21#define GEN_PASS_DEF_AFFINELOOPINVARIANTCODEMOTION
22#include "mlir/Dialect/Affine/Passes.h.inc"
26#define DEBUG_TYPE "affine-licm"
41struct LoopInvariantCodeMotion
43 LoopInvariantCodeMotion> {
44 void runOnOperation()
override;
45 void runOnAffineForOp(AffineForOp forOp);
66 Value iv = loop.getInductionVar();
68 if (
auto ifOp = dyn_cast<AffineIfOp>(op)) {
71 }
else if (
auto forOp = dyn_cast<AffineForOp>(op)) {
75 }
else if (
auto parOp = dyn_cast<AffineParallelOp>(op)) {
80 !isa<AffineReadOpInterface, AffineWriteOpInterface>(&op)) {
84 }
else if (isa<AffineReadOpInterface, AffineWriteOpInterface>(op)) {
86 opsWithUsers.insert(&op);
88 auto read = dyn_cast<AffineReadOpInterface>(op);
90 read ? read.getMemRef() : cast<AffineWriteOpInterface>(op).getMemRef();
91 for (
auto *user :
memref.getUsers()) {
100 isa<AffineWriteOpInterface>(op))) {
104 if (llvm::is_contained(userIVs, loop))
111 ValueRange iterArgs = loop.getRegionIterArgs();
120 if (llvm::is_contained(iterArgs, op.
getOperand(i)))
127 if (opsWithUsers.count(operandSrc) && opsToHoist.count(operandSrc) == 0)
133 opsToHoist.insert(&op);
143 for (
auto &
b : blockList) {
159 opsWithUsers, opsToHoist))
163 opsWithUsers, opsToHoist))
169void LoopInvariantCodeMotion::runOnAffineForOp(AffineForOp forOp) {
171 OpBuilder
b(forOp.getOperation());
173 SmallPtrSet<Operation *, 8> opsToHoist;
174 SmallVector<Operation *, 8> opsToMove;
175 SmallPtrSet<Operation *, 8> opsWithUsers;
177 for (Operation &op : *forOp.getBody()) {
182 opsWithUsers.insert(&op);
183 if (!isa<AffineYieldOp>(op)) {
185 opsToMove.push_back(&op);
192 for (
auto *op : opsToMove) {
193 op->moveBefore(forOp);
197void LoopInvariantCodeMotion::runOnOperation() {
201 getOperation().walk([&](AffineForOp op) { runOnAffineForOp(op); });
204std::unique_ptr<OperationPass<func::FuncOp>>
206 return std::make_unique<LoopInvariantCodeMotion>();
static bool isOpLoopInvariant(Operation &op, AffineForOp loop, SmallPtrSetImpl< Operation * > &opsWithUsers, SmallPtrSetImpl< Operation * > &opsToHoist)
Returns true if op is invariant on loop.
static bool areAllOpsInTheBlockListInvariant(Region &blockList, AffineForOp loop, SmallPtrSetImpl< Operation * > &opsWithUsers, SmallPtrSetImpl< Operation * > &opsToHoist)
static bool checkInvarianceOfNestedIfOps(AffineIfOp ifOp, AffineForOp loop, SmallPtrSetImpl< Operation * > &opsWithUsers, SmallPtrSetImpl< Operation * > &opsToHoist)
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
unsigned getNumOperands()
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...
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.
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 isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
bool hasEffect(Operation *op)
Returns "true" if op has an effect of type EffectTy.