This patch takes the first step towards a more principled modeling of undefined behavior in MLIR as discussed in the following discourse threads: 1. https://discourse.llvm.org/t/semantics-modeling-undefined-behavior-and-side-effects/4812 2. https://discourse.llvm.org/t/rfc-mark-tensor-dim-and-memref-dim-as-side-effecting/65729 This patch in particular does the following: 1. Introduces a ConditionallySpeculatable OpInterface that dynamically determines whether an Operation can be speculated. 2. Re-defines `NoSideEffect` to allow undefined behavior, making it necessary but not sufficient for speculation. Also renames it to `NoMemoryEffect`. 3. Makes LICM respect the above semantics. 4. Changes all ops tagged with `NoSideEffect` today to additionally implement ConditionallySpeculatable and mark themselves as always speculatable. This combined trait is named `Pure`. This makes this change NFC. For out of tree dialects: 1. Replace `NoSideEffect` with `Pure` if the operation does not have any memory effects, undefined behavior or infinite loops. 2. Replace `NoSideEffect` with `NoSideEffect` otherwise. The next steps in this process are (I'm proposing to do these in upcoming patches): 1. Update operations like `tensor.dim`, `memref.dim`, `scf.for`, `affine.for` to implement a correct hook for `ConditionallySpeculatable`. I'm also happy to update ops in other dialects if the respective dialect owners would like to and can give me some pointers. 2. Update other passes that speculate operations to consult `ConditionallySpeculatable` in addition to `NoMemoryEffect`. I could not find any other than LICM on a quick skim, but I could have missed some. 3. Add some documentation / FAQs detailing the differences between side effects, undefined behavior, speculatabilty. Reviewed By: rriddle, mehdi_amini Differential Revision: https://reviews.llvm.org/D135505
60 lines
2.2 KiB
C++
60 lines
2.2 KiB
C++
//===- ControlFlowSink.cpp - Code to perform control-flow sinking ---------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements a basic control-flow sink pass. Control-flow sinking
|
|
// moves operations whose only uses are in conditionally-executed blocks in to
|
|
// those blocks so that they aren't executed on paths where their results are
|
|
// not needed.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/Transforms/Passes.h"
|
|
|
|
#include "mlir/IR/Dominance.h"
|
|
#include "mlir/Interfaces/ControlFlowInterfaces.h"
|
|
#include "mlir/Interfaces/SideEffectInterfaces.h"
|
|
#include "mlir/Transforms/ControlFlowSinkUtils.h"
|
|
#include "mlir/Transforms/SideEffectUtils.h"
|
|
|
|
namespace mlir {
|
|
#define GEN_PASS_DEF_CONTROLFLOWSINK
|
|
#include "mlir/Transforms/Passes.h.inc"
|
|
} // namespace mlir
|
|
|
|
using namespace mlir;
|
|
|
|
namespace {
|
|
/// A control-flow sink pass.
|
|
struct ControlFlowSink : public impl::ControlFlowSinkBase<ControlFlowSink> {
|
|
void runOnOperation() override;
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
void ControlFlowSink::runOnOperation() {
|
|
auto &domInfo = getAnalysis<DominanceInfo>();
|
|
getOperation()->walk([&](RegionBranchOpInterface branch) {
|
|
SmallVector<Region *> regionsToSink;
|
|
// Get the regions are that known to be executed at most once.
|
|
getSinglyExecutedRegionsToSink(branch, regionsToSink);
|
|
// Sink side-effect free operations.
|
|
numSunk = controlFlowSink(
|
|
regionsToSink, domInfo,
|
|
[](Operation *op, Region *) { return isMemoryEffectFree(op); },
|
|
[](Operation *op, Region *region) {
|
|
// Move the operation to the beginning of the region's entry block.
|
|
// This guarantees the preservation of SSA dominance of all of the
|
|
// operation's uses are in the region.
|
|
op->moveBefore(®ion->front(), region->front().begin());
|
|
});
|
|
});
|
|
}
|
|
|
|
std::unique_ptr<Pass> mlir::createControlFlowSinkPass() {
|
|
return std::make_unique<ControlFlowSink>();
|
|
}
|