22#define GEN_PASS_DEF_AFFINELOOPINVARIANTCODEMOTION
23#include "mlir/Dialect/Affine/Transforms/Passes.h.inc"
27#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;
181 auto tripCount = forOp.getStaticTripCount();
182 bool guaranteedToExecute =
183 tripCount.has_value() && tripCount->getZExtValue() > 0;
185 for (Operation &op : *forOp.getBody()) {
190 opsWithUsers.insert(&op);
191 if (!isa<AffineYieldOp>(op)) {
194 if (!guaranteedToExecute && !
isPure(&op))
197 opsToMove.push_back(&op);
204 for (
auto *op : opsToMove) {
205 op->moveBefore(forOp);
209void LoopInvariantCodeMotion::runOnOperation() {
213 getOperation().walk([&](AffineForOp op) { runOnAffineForOp(op); });
216std::unique_ptr<OperationPass<func::FuncOp>>
218 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 isPure(Operation *op)
Returns true if the given operation is pure, i.e., is speculatable that does not touch memory.
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.