[Mlir-commits] [mlir] Enable LICM for ops with only read side effects in scf.for (PR #120302)
donald chen
llvmlistbot at llvm.org
Thu Dec 26 04:43:48 PST 2024
================
@@ -56,48 +56,117 @@ static bool canBeHoisted(Operation *op,
op, [&](OpOperand &operand) { return definedOutside(operand.get()); });
}
+static bool dependsOnGuarded(Operation *op,
+ function_ref<bool(OpOperand &)> condition) {
+ auto walkFn = [&](Operation *child) {
+ for (OpOperand &operand : child->getOpOperands()) {
+ if (!condition(operand))
+ return WalkResult::interrupt();
+ }
+ return WalkResult::advance();
+ };
+ return op->walk(walkFn).wasInterrupted();
+}
+
+static bool dependsOnGuarded(Operation *op,
+ function_ref<bool(Value)> definedOutsideGuard) {
+ return dependsOnGuarded(op, [&](OpOperand &operand) {
+ return definedOutsideGuard(operand.get());
+ });
+}
+
+static bool loopSideEffectFreeOrHasOnlyReadEffect(Operation *loop) {
+ for (Region ®ion : loop->getRegions()) {
+ for (Block &block : region.getBlocks()) {
+ for (Operation &op : block.getOperations()) {
+ if (!isMemoryEffectFree(&op) && !hasOnlyReadEffect(&op))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
size_t mlir::moveLoopInvariantCode(
ArrayRef<Region *> regions,
function_ref<bool(Value, Region *)> isDefinedOutsideRegion,
function_ref<bool(Operation *, Region *)> shouldMoveOutOfRegion,
- function_ref<void(Operation *, Region *)> moveOutOfRegion) {
+ function_ref<FailureOr<std::pair<Operation *, Region *>>()> wrapInGuard,
+ function_ref<void(Operation *, Region *)> moveOutOfRegion,
+ function_ref<LogicalResult()> unwrapGuard) {
size_t numMoved = 0;
for (Region *region : regions) {
LLVM_DEBUG(llvm::dbgs() << "Original loop:\n"
<< *region->getParentOp() << "\n");
+ auto loopSideEffectFreeOrHasOnlyReadSideEffect =
+ loopSideEffectFreeOrHasOnlyReadEffect(region->getParentOp());
+
+ size_t numMovedWithoutGuard = 0;
+
+ FailureOr<std::pair<Operation *, Region *>> ifOpAndRegion = wrapInGuard();
+ Region *loopRegion = region;
+ auto isLoopWrapped = false;
+ if (succeeded(ifOpAndRegion)) {
+ loopRegion = ifOpAndRegion->second;
+ isLoopWrapped = true;
+ }
+
std::queue<Operation *> worklist;
// Add top-level operations in the loop body to the worklist.
- for (Operation &op : region->getOps())
+ for (Operation &op : loopRegion->getOps())
worklist.push(&op);
auto definedOutside = [&](Value value) {
- return isDefinedOutsideRegion(value, region);
+ return isDefinedOutsideRegion(value, loopRegion);
+ };
+
+ auto definedOutsideGuard = [&](Value value) {
+ return isDefinedOutsideRegion(value, loopRegion->getParentRegion());
};
while (!worklist.empty()) {
Operation *op = worklist.front();
worklist.pop();
// Skip ops that have already been moved. Check if the op can be hoisted.
- if (op->getParentRegion() != region)
+ if (op->getParentRegion() != loopRegion)
continue;
LLVM_DEBUG(llvm::dbgs() << "Checking op: " << *op << "\n");
- if (!shouldMoveOutOfRegion(op, region) ||
+
+ if (!shouldMoveOutOfRegion(op, loopRegion) ||
!canBeHoisted(op, definedOutside))
continue;
+ // Can only hoist pure ops (side-effect free) when there is an op with
+ // write and/or unknown side effects in the loop.
+ if (!loopSideEffectFreeOrHasOnlyReadSideEffect && !isMemoryEffectFree(op))
+ continue;
LLVM_DEBUG(llvm::dbgs() << "Moving loop-invariant op: " << *op << "\n");
- moveOutOfRegion(op, region);
+
+ auto moveWithoutGuard = isMemoryEffectFree(op) &&
----------------
cxy-1993 wrote:
why auto
https://github.com/llvm/llvm-project/pull/120302
More information about the Mlir-commits
mailing list