- Adds default implementations of `isDefinedOutsideOfLoop` and `moveOutOfLoop` since 99% of all implementations of these functions were identical
- `moveOutOfLoop` takes one operation and doesn't return anything anymore. 100% of all implementations of this function would always return `success` and uses would either respond with a pass failure or an `llvm_unreachable`.
mlir::Region &fir::IterWhileOp::getLoopBody() { return getRegion(); }
-bool fir::IterWhileOp::isDefinedOutsideOfLoop(mlir::Value value) {
- return !getRegion().isAncestor(value.getParentRegion());
-}
-
-mlir::LogicalResult
-fir::IterWhileOp::moveOutOfLoop(llvm::ArrayRef<mlir::Operation *> ops) {
- for (auto *op : ops)
- op->moveBefore(*this);
- return success();
-}
-
mlir::BlockArgument fir::IterWhileOp::iterArgToBlockArg(mlir::Value iterArg) {
for (auto i : llvm::enumerate(getInitArgs()))
if (iterArg == i.value())
mlir::Region &fir::DoLoopOp::getLoopBody() { return getRegion(); }
-bool fir::DoLoopOp::isDefinedOutsideOfLoop(mlir::Value value) {
- return !getRegion().isAncestor(value.getParentRegion());
-}
-
-mlir::LogicalResult
-fir::DoLoopOp::moveOutOfLoop(llvm::ArrayRef<mlir::Operation *> ops) {
- for (auto op : ops)
- op->moveBefore(*this);
- return success();
-}
-
/// Translate a value passed as an iter_arg to the corresponding block
/// argument in the body of the loop.
mlir::BlockArgument fir::DoLoopOp::iterArgToBlockArg(mlir::Value iterArg) {
namespace mlir {
/// Move loop invariant code out of a `looplike` operation.
-LogicalResult moveLoopInvariantCode(LoopLikeOpInterface looplike);
+void moveLoopInvariantCode(LoopLikeOpInterface looplike);
} // namespace mlir
#endif // MLIR_INTERFACES_LOOPLIKEINTERFACE_H_
explicit capture of dependencies, an implementation could check whether
the value corresponds to a captured dependency.
}],
- "bool", "isDefinedOutsideOfLoop", (ins "::mlir::Value ":$value)
+ "bool", "isDefinedOutsideOfLoop", (ins "::mlir::Value ":$value), [{}], [{
+ return value.getParentRegion()->isProperAncestor(&$_op.getLoopBody());
+ }]
>,
InterfaceMethod<[{
Returns the region that makes up the body of the loop and should be
"::mlir::Region &", "getLoopBody"
>,
InterfaceMethod<[{
- Moves the given vector of operations out of the loop. The vector is
- sorted topologically.
+ Moves the given loop-invariant operation out of the loop.
}],
- "::mlir::LogicalResult", "moveOutOfLoop", (ins "::mlir::ArrayRef<::mlir::Operation *>":$ops)
+ "void", "moveOutOfLoop",
+ (ins "::mlir::Operation *":$op), [{}], [{
+ op->moveBefore($_op);
+ }]
>,
InterfaceMethod<[{
If there is a single induction variable return it, otherwise return
Region &AffineForOp::getLoopBody() { return region(); }
-bool AffineForOp::isDefinedOutsideOfLoop(Value value) {
- return !region().isAncestor(value.getParentRegion());
-}
-
Optional<Value> AffineForOp::getSingleInductionVar() {
return getInductionVar();
}
return OpFoldResult(b.getI64IntegerAttr(getStep()));
}
-LogicalResult AffineForOp::moveOutOfLoop(ArrayRef<Operation *> ops) {
- for (auto *op : ops)
- op->moveBefore(*this);
- return success();
-}
-
/// Returns true if the provided value is the induction variable of a
/// AffineForOp.
bool mlir::isForInductionVar(Value val) {
Region &AffineParallelOp::getLoopBody() { return region(); }
-bool AffineParallelOp::isDefinedOutsideOfLoop(Value value) {
- return !region().isAncestor(value.getParentRegion());
-}
-
-LogicalResult AffineParallelOp::moveOutOfLoop(ArrayRef<Operation *> ops) {
- for (Operation *op : ops)
- op->moveBefore(*this);
- return success();
-}
-
unsigned AffineParallelOp::getNumDims() { return steps().size(); }
AffineParallelOp::operand_range AffineParallelOp::getLowerBoundsOperands() {
<< "\nInvolving: " << tensorBBArg << "\n");
// If a read slice is present, hoist it.
- if (read.extractSliceOp && failed(forOp.moveOutOfLoop({read.extractSliceOp})))
- llvm_unreachable("Unexpected failure moving extract_slice out of loop");
+ if (read.extractSliceOp)
+ forOp.moveOutOfLoop(read.extractSliceOp);
// Hoist the transfer_read op.
- if (failed(forOp.moveOutOfLoop({read.transferReadOp})))
- llvm_unreachable("Unexpected failure moving transfer read out of loop");
+ forOp.moveOutOfLoop(read.transferReadOp);
// TODO: don't hardcode /*numIvs=*/1.
assert(tensorBBArg.getArgNumber() >= /*numIvs=*/1);
// First move loop invariant ops outside of their loop. This needs to be
// done before as we cannot move ops without interputing the function walk.
func.walk([&](LoopLikeOpInterface loopLike) {
- if (failed(moveLoopInvariantCode(loopLike)))
- llvm_unreachable(
- "Unexpected failure to move invariant code out of loop");
+ moveLoopInvariantCode(loopLike);
});
func.walk([&](vector::TransferReadOp transferRead) {
}
// Hoist read before.
- if (failed(loop.moveOutOfLoop({transferRead})))
- llvm_unreachable(
- "Unexpected failure to move transfer read out of loop");
+ loop.moveOutOfLoop(transferRead);
// Hoist write after.
transferWrite->moveAfter(loop);
return signalPassFailure();
if (options.licm) {
- if (funcOp
- ->walk([&](LoopLikeOpInterface loopLike) {
- if (failed(moveLoopInvariantCode(loopLike)))
- return WalkResult::interrupt();
- return WalkResult::advance();
- })
- .wasInterrupted())
- return signalPassFailure();
+ funcOp->walk([&](LoopLikeOpInterface loopLike) {
+ moveLoopInvariantCode(loopLike);
+ });
}
// Gathers all innermost loops through a post order pruned walk.
Region &ForOp::getLoopBody() { return getRegion(); }
-bool ForOp::isDefinedOutsideOfLoop(Value value) {
- return !getRegion().isAncestor(value.getParentRegion());
-}
-
-LogicalResult ForOp::moveOutOfLoop(ArrayRef<Operation *> ops) {
- for (auto *op : ops)
- op->moveBefore(*this);
- return success();
-}
-
ForOp mlir::scf::getForInductionVarOwner(Value val) {
auto ivArg = val.dyn_cast<BlockArgument>();
if (!ivArg)
Region &ParallelOp::getLoopBody() { return getRegion(); }
-bool ParallelOp::isDefinedOutsideOfLoop(Value value) {
- return !getRegion().isAncestor(value.getParentRegion());
-}
-
-LogicalResult ParallelOp::moveOutOfLoop(ArrayRef<Operation *> ops) {
- for (auto *op : ops)
- op->moveBefore(*this);
- return success();
-}
-
ParallelOp mlir::scf::getParallelForInductionVarOwner(Value val) {
auto ivArg = val.dyn_cast<BlockArgument>();
if (!ivArg)
/// Returns the while loop body.
Region &tosa::WhileOp::getLoopBody() { return body(); }
-bool tosa::WhileOp::isDefinedOutsideOfLoop(Value value) {
- return !body().isAncestor(value.getParentRegion());
-}
-
-LogicalResult WhileOp::moveOutOfLoop(ArrayRef<mlir::Operation *> ops) {
- if (ops.empty())
- return success();
-
- Operation *tosaWhileOp = this->getOperation();
- for (auto *op : ops)
- op->moveBefore(tosaWhileOp);
-
- return success();
-}
-
//===----------------------------------------------------------------------===//
// Tosa dialect initialization.
//===----------------------------------------------------------------------===//
return true;
}
-LogicalResult mlir::moveLoopInvariantCode(LoopLikeOpInterface looplike) {
+void mlir::moveLoopInvariantCode(LoopLikeOpInterface looplike) {
auto &loopBody = looplike.getLoopBody();
// We use two collections here as we need to preserve the order for insertion
// For all instructions that we found to be invariant, move outside of the
// loop.
- LogicalResult result = looplike.moveOutOfLoop(opsToMove);
- LLVM_DEBUG(looplike.print(llvm::dbgs() << "\n\nModified loop:\n"));
- return result;
+ for (Operation *op : opsToMove)
+ looplike.moveOutOfLoop(op);
}
// the outer loop, which in turn can be further LICM'ed.
getOperation()->walk([&](LoopLikeOpInterface loopLike) {
LLVM_DEBUG(loopLike.print(llvm::dbgs() << "\nOriginal loop:\n"));
- if (failed(moveLoopInvariantCode(loopLike)))
- signalPassFailure();
+ moveLoopInvariantCode(loopLike);
});
}
auto loop = fakeRead->getParentOfType<scf::ForOp>();
OpBuilder b(loop);
- (void)loop.moveOutOfLoop({fakeRead});
+ loop.moveOutOfLoop(fakeRead);
fakeWrite->moveAfter(loop);
auto newLoop = cloneWithNewYields(b, loop, fakeRead->getResult(0),
fakeCompute->getResult(0));