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 ®ion : 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(®ion->front(), region->front().begin()); 723628febcSMogball }); 73572fa964SMogball }); 74572fa964SMogball } 75572fa964SMogball 76572fa964SMogball std::unique_ptr<Pass> mlir::createControlFlowSinkPass() { 77572fa964SMogball return std::make_unique<ControlFlowSink>(); 78572fa964SMogball } 79