In #173438 I added a FIR specific loop invariant code motion pass. During the review, Tom pointed out certain limitations about OpenMP dialect operations that should be taken into consideration during transformations such as LICM: https://github.com/llvm/llvm-project/pull/173438#discussion_r2657612148 I also found issues with hoisting operations out of `acc.loop` operations in certain conditions (see the added test in `licm.fir`). I am proposing a new operation interface that will allow to control movement of operations during MLIR transformations. In particular, I propose two methods (there might be more): * op.canMoveOutOf(cand) - returns true, if it is allowed to move 'cand' operation out of 'op'. * op.canMoveFromDescendant(descendant, cand) - return true, if it is allowed to move 'cand' out of 'descendant' and into 'op'. I used the new interface to get rid of explicit OpenMP interfaces checks in Flang's LICM, and I also used it for `acc.loop` operation (though, I provided conservative initial implementation). The new interface is part of FIR dialect, but I think it would better fit into the core MLIR set of interfaces so that the checks that I make in Flang's LICM are actually done in `mlir::moveLoopInvariantCode`. Moreover, other code movement transformations that may appear in MLIR may also need to use such an interface. I would like to get some feedback on whether it is reasonable to move the interface to core MLIR.
50 lines
1.8 KiB
C++
50 lines
1.8 KiB
C++
//===-- FIROperationMoveOpInterface.cpp -----------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "flang/Optimizer/Dialect/FIROperationMoveOpInterface.h"
|
|
|
|
#include "flang/Optimizer/Dialect/FIROperationMoveOpInterface.cpp.inc"
|
|
|
|
llvm::LogicalResult
|
|
fir::detail::verifyOperationMoveOpInterface(mlir::Operation *op) {
|
|
// It does not make sense to use this interface for operations
|
|
// without any regions.
|
|
if (op->getNumRegions() == 0)
|
|
return op->emitOpError("must contain at least one region");
|
|
return llvm::success();
|
|
}
|
|
|
|
bool fir::canMoveFromDescendant(mlir::Operation *op,
|
|
mlir::Operation *descendant,
|
|
mlir::Operation *candidate) {
|
|
// Perform some sanity checks.
|
|
assert(op->isProperAncestor(descendant) &&
|
|
"op must be an ancestor of descendant");
|
|
if (candidate)
|
|
assert(descendant->isProperAncestor(candidate) &&
|
|
"descendant must be an ancestor of candidate");
|
|
if (auto iface = mlir::dyn_cast<OperationMoveOpInterface>(op))
|
|
return iface.canMoveFromDescendant(descendant, candidate);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool fir::canMoveOutOf(mlir::Operation *op, mlir::Operation *candidate) {
|
|
if (candidate)
|
|
assert(op->isProperAncestor(candidate) &&
|
|
"op must be an ancestor of candidate");
|
|
if (auto iface = mlir::dyn_cast<OperationMoveOpInterface>(op))
|
|
return iface.canMoveOutOf(candidate);
|
|
|
|
return true;
|
|
}
|