aboutsummaryrefslogtreecommitdiff
path: root/mlir/lib/Transforms/LoopInvariantCodeMotion.cpp
diff options
context:
space:
mode:
authorRiver Riddle <riddleriver@gmail.com>2022-01-20 17:32:31 -0800
committerRiver Riddle <riddleriver@gmail.com>2022-01-24 19:25:53 -0800
commita70aa7bb0d9a6066831b339e0a09a2c1bc74fe2b (patch)
tree7e807bcabf3cda9403351e442a3f74b3fae01756 /mlir/lib/Transforms/LoopInvariantCodeMotion.cpp
parent2e2c0738e80e9c2b7c1413ca4719d5be2df4c6b5 (diff)
downloadllvm-a70aa7bb0d9a6066831b339e0a09a2c1bc74fe2b.zip
llvm-a70aa7bb0d9a6066831b339e0a09a2c1bc74fe2b.tar.gz
llvm-a70aa7bb0d9a6066831b339e0a09a2c1bc74fe2b.tar.bz2
[mlir:Transforms] Move out the remaining non-dialect independent transforms and utilities
This has been a major TODO for a very long time, and is necessary for establishing a proper dialect-free dependency layering for the Transforms library. Code was moved to effectively two main locations: * Affine/ There was quite a bit of affine dialect related code in Transforms/ do to historical reasons (of a time way into MLIR's past). The following headers were moved to: Transforms/LoopFusionUtils.h -> Dialect/Affine/LoopFusionUtils.h Transforms/LoopUtils.h -> Dialect/Affine/LoopUtils.h Transforms/Utils.h -> Dialect/Affine/Utils.h The following transforms were also moved: AffineLoopFusion, AffinePipelineDataTransfer, LoopCoalescing * SCF/ Only one SCF pass was in Transforms/ (likely accidentally placed here): ParallelLoopCollapsing The SCF specific utilities in LoopUtils have been moved to SCF/Utils.h * Misc: mlir::moveLoopInvariantCode was also moved to LoopLikeInterface.h given that it is a simple utility defined in terms of LoopLikeOpInterface. Differential Revision: https://reviews.llvm.org/D117848
Diffstat (limited to 'mlir/lib/Transforms/LoopInvariantCodeMotion.cpp')
-rw-r--r--mlir/lib/Transforms/LoopInvariantCodeMotion.cpp79
1 files changed, 1 insertions, 78 deletions
diff --git a/mlir/lib/Transforms/LoopInvariantCodeMotion.cpp b/mlir/lib/Transforms/LoopInvariantCodeMotion.cpp
index 3c8e14a..e4e3c16 100644
--- a/mlir/lib/Transforms/LoopInvariantCodeMotion.cpp
+++ b/mlir/lib/Transforms/LoopInvariantCodeMotion.cpp
@@ -11,13 +11,10 @@
//===----------------------------------------------------------------------===//
#include "PassDetail.h"
-#include "mlir/Transforms/Passes.h"
-
#include "mlir/IR/Builders.h"
-#include "mlir/IR/BuiltinOps.h"
#include "mlir/Interfaces/LoopLikeInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
-#include "mlir/Transforms/LoopUtils.h"
+#include "mlir/Transforms/Passes.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -34,80 +31,6 @@ struct LoopInvariantCodeMotion
};
} // namespace
-// Checks whether the given op can be hoisted by checking that
-// - the op and any of its contained operations do not depend on SSA values
-// defined inside of the loop (by means of calling definedOutside).
-// - the op has no side-effects. If sideEffecting is Never, sideeffects of this
-// op and its nested ops are ignored.
-static bool canBeHoisted(Operation *op,
- function_ref<bool(Value)> definedOutside) {
- // Check that dependencies are defined outside of loop.
- if (!llvm::all_of(op->getOperands(), definedOutside))
- return false;
- // Check whether this op is side-effect free. If we already know that there
- // can be no side-effects because the surrounding op has claimed so, we can
- // (and have to) skip this step.
- if (auto memInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
- if (!memInterface.hasNoEffect())
- return false;
- // If the operation doesn't have side effects and it doesn't recursively
- // have side effects, it can always be hoisted.
- if (!op->hasTrait<OpTrait::HasRecursiveSideEffects>())
- return true;
-
- // Otherwise, if the operation doesn't provide the memory effect interface
- // and it doesn't have recursive side effects we treat it conservatively as
- // side-effecting.
- } else if (!op->hasTrait<OpTrait::HasRecursiveSideEffects>()) {
- return false;
- }
-
- // Recurse into the regions for this op and check whether the contained ops
- // can be hoisted.
- for (auto &region : op->getRegions()) {
- for (auto &block : region) {
- for (auto &innerOp : block)
- if (!canBeHoisted(&innerOp, definedOutside))
- return false;
- }
- }
- return true;
-}
-
-LogicalResult mlir::moveLoopInvariantCode(LoopLikeOpInterface looplike) {
- auto &loopBody = looplike.getLoopBody();
-
- // We use two collections here as we need to preserve the order for insertion
- // and this is easiest.
- SmallPtrSet<Operation *, 8> willBeMovedSet;
- SmallVector<Operation *, 8> opsToMove;
-
- // Helper to check whether an operation is loop invariant wrt. SSA properties.
- auto isDefinedOutsideOfBody = [&](Value value) {
- auto *definingOp = value.getDefiningOp();
- return (definingOp && !!willBeMovedSet.count(definingOp)) ||
- looplike.isDefinedOutsideOfLoop(value);
- };
-
- // Do not use walk here, as we do not want to go into nested regions and hoist
- // operations from there. These regions might have semantics unknown to this
- // rewriting. If the nested regions are loops, they will have been processed.
- for (auto &block : loopBody) {
- for (auto &op : block.without_terminator()) {
- if (canBeHoisted(&op, isDefinedOutsideOfBody)) {
- opsToMove.push_back(&op);
- willBeMovedSet.insert(&op);
- }
- }
- }
-
- // For all instructions that we found to be invariant, move outside of the
- // loop.
- auto result = looplike.moveOutOfLoop(opsToMove);
- LLVM_DEBUG(looplike.print(llvm::dbgs() << "\n\nModified loop:\n"));
- return result;
-}
-
void LoopInvariantCodeMotion::runOnOperation() {
// Walk through all loops in a function in innermost-loop-first order. This
// way, we first LICM from the inner loop, and place the ops in