1572fa964SMogball //===- ControlFlowSink.cpp - Code to perform control-flow sinking ---------===//
2572fa964SMogball //
3572fa964SMogball // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4572fa964SMogball // See https://llvm.org/LICENSE.txt for license information.
5572fa964SMogball // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6572fa964SMogball //
7572fa964SMogball //===----------------------------------------------------------------------===//
8572fa964SMogball //
9572fa964SMogball // This file implements a basic control-flow sink pass. Control-flow sinking
10572fa964SMogball // moves operations whose only uses are in conditionally-executed blocks in to
11572fa964SMogball // those blocks so that they aren't executed on paths where their results are
12572fa964SMogball // not needed.
13572fa964SMogball //
14572fa964SMogball //===----------------------------------------------------------------------===//
15572fa964SMogball 
16572fa964SMogball #include "PassDetail.h"
17572fa964SMogball #include "mlir/IR/Dominance.h"
18572fa964SMogball #include "mlir/Interfaces/ControlFlowInterfaces.h"
19*36d3efeaSRiver Riddle #include "mlir/Interfaces/SideEffectInterfaces.h"
20a70aa7bbSRiver Riddle #include "mlir/Transforms/ControlFlowSinkUtils.h"
21572fa964SMogball #include "mlir/Transforms/Passes.h"
22572fa964SMogball 
23572fa964SMogball using namespace mlir;
24572fa964SMogball 
25572fa964SMogball namespace {
263628febcSMogball /// A control-flow sink pass.
27572fa964SMogball struct ControlFlowSink : public ControlFlowSinkBase<ControlFlowSink> {
28572fa964SMogball   void runOnOperation() override;
29572fa964SMogball };
30572fa964SMogball } // end anonymous namespace
31572fa964SMogball 
32572fa964SMogball /// Returns true if the given operation is side-effect free as are all of its
33572fa964SMogball /// nested operations.
34572fa964SMogball static bool isSideEffectFree(Operation *op) {
35572fa964SMogball   if (auto memInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
36572fa964SMogball     // If the op has side-effects, it cannot be moved.
37572fa964SMogball     if (!memInterface.hasNoEffect())
38572fa964SMogball       return false;
39572fa964SMogball     // If the op does not have recursive side effects, then it can be moved.
40572fa964SMogball     if (!op->hasTrait<OpTrait::HasRecursiveSideEffects>())
41572fa964SMogball       return true;
42572fa964SMogball   } else if (!op->hasTrait<OpTrait::HasRecursiveSideEffects>()) {
43572fa964SMogball     // Otherwise, if the op does not implement the memory effect interface and
44572fa964SMogball     // it does not have recursive side effects, then it cannot be known that the
45572fa964SMogball     // op is moveable.
46572fa964SMogball     return false;
47572fa964SMogball   }
48572fa964SMogball 
49572fa964SMogball   // Recurse into the regions and ensure that all nested ops can also be moved.
50572fa964SMogball   for (Region &region : op->getRegions())
51572fa964SMogball     for (Operation &op : region.getOps())
52572fa964SMogball       if (!isSideEffectFree(&op))
53572fa964SMogball         return false;
54572fa964SMogball   return true;
55572fa964SMogball }
56572fa964SMogball 
57572fa964SMogball void ControlFlowSink::runOnOperation() {
58572fa964SMogball   auto &domInfo = getAnalysis<DominanceInfo>();
59572fa964SMogball   getOperation()->walk([&](RegionBranchOpInterface branch) {
60572fa964SMogball     SmallVector<Region *> regionsToSink;
613628febcSMogball     // Get the regions are that known to be executed at most once.
62572fa964SMogball     getSinglyExecutedRegionsToSink(branch, regionsToSink);
633628febcSMogball     // Sink side-effect free operations.
64b73f1d2cSMogball     numSunk = controlFlowSink(
65b73f1d2cSMogball         regionsToSink, domInfo,
66b73f1d2cSMogball         [](Operation *op, Region *) { return isSideEffectFree(op); },
67b73f1d2cSMogball         [](Operation *op, Region *region) {
68b73f1d2cSMogball           // Move the operation to the beginning of the region's entry block.
69b73f1d2cSMogball           // This guarantees the preservation of SSA dominance of all of the
70b73f1d2cSMogball           // operation's uses are in the region.
71b73f1d2cSMogball           op->moveBefore(&region->front(), region->front().begin());
723628febcSMogball         });
73572fa964SMogball   });
74572fa964SMogball }
75572fa964SMogball 
76572fa964SMogball std::unique_ptr<Pass> mlir::createControlFlowSinkPass() {
77572fa964SMogball   return std::make_unique<ControlFlowSink>();
78572fa964SMogball }
79