xref: /llvm-project/mlir/lib/Transforms/RemoveDeadValues.cpp (revision aa3c31a86f39552d11f0d5bae8b50541d73aa442)
10e98fb9fSSrishti Srivastava //===- RemoveDeadValues.cpp - Remove Dead Values --------------------------===//
20e98fb9fSSrishti Srivastava //
30e98fb9fSSrishti Srivastava // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40e98fb9fSSrishti Srivastava // See https://llvm.org/LICENSE.txt for license information.
50e98fb9fSSrishti Srivastava // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60e98fb9fSSrishti Srivastava //
70e98fb9fSSrishti Srivastava //===----------------------------------------------------------------------===//
80e98fb9fSSrishti Srivastava //
90e98fb9fSSrishti Srivastava // The goal of this pass is optimization (reducing runtime) by removing
100e98fb9fSSrishti Srivastava // unnecessary instructions. Unlike other passes that rely on local information
110e98fb9fSSrishti Srivastava // gathered from patterns to accomplish optimization, this pass uses a full
120e98fb9fSSrishti Srivastava // analysis of the IR, specifically, liveness analysis, and is thus more
130e98fb9fSSrishti Srivastava // powerful.
140e98fb9fSSrishti Srivastava //
150e98fb9fSSrishti Srivastava // Currently, this pass performs the following optimizations:
160e98fb9fSSrishti Srivastava // (A) Removes function arguments that are not live,
170e98fb9fSSrishti Srivastava // (B) Removes function return values that are not live across all callers of
180e98fb9fSSrishti Srivastava // the function,
190e98fb9fSSrishti Srivastava // (C) Removes unneccesary operands, results, region arguments, and region
200e98fb9fSSrishti Srivastava // terminator operands of region branch ops, and,
210e98fb9fSSrishti Srivastava // (D) Removes simple and region branch ops that have all non-live results and
220e98fb9fSSrishti Srivastava // don't affect memory in any way,
230e98fb9fSSrishti Srivastava //
240e98fb9fSSrishti Srivastava // iff
250e98fb9fSSrishti Srivastava //
260e98fb9fSSrishti Srivastava // the IR doesn't have any non-function symbol ops, non-call symbol user ops and
270e98fb9fSSrishti Srivastava // branch ops.
280e98fb9fSSrishti Srivastava //
290e98fb9fSSrishti Srivastava // Here, a "simple op" refers to an op that isn't a symbol op, symbol-user op,
300e98fb9fSSrishti Srivastava // region branch op, branch op, region branch terminator op, or return-like.
310e98fb9fSSrishti Srivastava //
320e98fb9fSSrishti Srivastava //===----------------------------------------------------------------------===//
330e98fb9fSSrishti Srivastava 
340e98fb9fSSrishti Srivastava #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
350e98fb9fSSrishti Srivastava #include "mlir/Analysis/DataFlow/LivenessAnalysis.h"
360e98fb9fSSrishti Srivastava #include "mlir/IR/Attributes.h"
370e98fb9fSSrishti Srivastava #include "mlir/IR/Builders.h"
380e98fb9fSSrishti Srivastava #include "mlir/IR/BuiltinAttributes.h"
390e98fb9fSSrishti Srivastava #include "mlir/IR/Dialect.h"
400e98fb9fSSrishti Srivastava #include "mlir/IR/IRMapping.h"
410e98fb9fSSrishti Srivastava #include "mlir/IR/OperationSupport.h"
420e98fb9fSSrishti Srivastava #include "mlir/IR/SymbolTable.h"
430e98fb9fSSrishti Srivastava #include "mlir/IR/Value.h"
440e98fb9fSSrishti Srivastava #include "mlir/IR/ValueRange.h"
450e98fb9fSSrishti Srivastava #include "mlir/IR/Visitors.h"
460e98fb9fSSrishti Srivastava #include "mlir/Interfaces/CallInterfaces.h"
470e98fb9fSSrishti Srivastava #include "mlir/Interfaces/ControlFlowInterfaces.h"
4834a35a8bSMartin Erhart #include "mlir/Interfaces/FunctionInterfaces.h"
490e98fb9fSSrishti Srivastava #include "mlir/Interfaces/SideEffectInterfaces.h"
500e98fb9fSSrishti Srivastava #include "mlir/Pass/Pass.h"
510e98fb9fSSrishti Srivastava #include "mlir/Support/LLVM.h"
520e98fb9fSSrishti Srivastava #include "mlir/Transforms/FoldUtils.h"
530e98fb9fSSrishti Srivastava #include "mlir/Transforms/Passes.h"
540e98fb9fSSrishti Srivastava #include "llvm/ADT/STLExtras.h"
550e98fb9fSSrishti Srivastava #include <cassert>
560e98fb9fSSrishti Srivastava #include <cstddef>
570e98fb9fSSrishti Srivastava #include <memory>
580e98fb9fSSrishti Srivastava #include <optional>
590e98fb9fSSrishti Srivastava #include <vector>
600e98fb9fSSrishti Srivastava 
610e98fb9fSSrishti Srivastava namespace mlir {
620e98fb9fSSrishti Srivastava #define GEN_PASS_DEF_REMOVEDEADVALUES
630e98fb9fSSrishti Srivastava #include "mlir/Transforms/Passes.h.inc"
640e98fb9fSSrishti Srivastava } // namespace mlir
650e98fb9fSSrishti Srivastava 
660e98fb9fSSrishti Srivastava using namespace mlir;
670e98fb9fSSrishti Srivastava using namespace mlir::dataflow;
680e98fb9fSSrishti Srivastava 
690e98fb9fSSrishti Srivastava //===----------------------------------------------------------------------===//
700e98fb9fSSrishti Srivastava // RemoveDeadValues Pass
710e98fb9fSSrishti Srivastava //===----------------------------------------------------------------------===//
720e98fb9fSSrishti Srivastava 
730e98fb9fSSrishti Srivastava namespace {
740e98fb9fSSrishti Srivastava 
75*aa3c31a8SRenat Idrisov // Set of structures below to be filled with operations and arguments to erase.
76*aa3c31a8SRenat Idrisov // This is done to separate analysis and tree modification phases,
77*aa3c31a8SRenat Idrisov // otherwise analysis is operating on half-deleted tree which is incorrect.
78*aa3c31a8SRenat Idrisov 
79*aa3c31a8SRenat Idrisov struct FunctionToCleanUp {
80*aa3c31a8SRenat Idrisov   FunctionOpInterface funcOp;
81*aa3c31a8SRenat Idrisov   BitVector nonLiveArgs;
82*aa3c31a8SRenat Idrisov   BitVector nonLiveRets;
83*aa3c31a8SRenat Idrisov };
84*aa3c31a8SRenat Idrisov 
85*aa3c31a8SRenat Idrisov struct OperationToCleanup {
86*aa3c31a8SRenat Idrisov   Operation *op;
87*aa3c31a8SRenat Idrisov   BitVector nonLive;
88*aa3c31a8SRenat Idrisov };
89*aa3c31a8SRenat Idrisov 
90*aa3c31a8SRenat Idrisov struct BlockArgsToCleanup {
91*aa3c31a8SRenat Idrisov   Block *b;
92*aa3c31a8SRenat Idrisov   BitVector nonLiveArgs;
93*aa3c31a8SRenat Idrisov };
94*aa3c31a8SRenat Idrisov 
95*aa3c31a8SRenat Idrisov struct SuccessorOperandsToCleanup {
96*aa3c31a8SRenat Idrisov   BranchOpInterface branch;
97*aa3c31a8SRenat Idrisov   unsigned successorIndex;
98*aa3c31a8SRenat Idrisov   BitVector nonLiveOperands;
99*aa3c31a8SRenat Idrisov };
100*aa3c31a8SRenat Idrisov 
101*aa3c31a8SRenat Idrisov struct RDVFinalCleanupList {
102*aa3c31a8SRenat Idrisov   SmallVector<Operation *> operations;
103*aa3c31a8SRenat Idrisov   SmallVector<Value> values;
104*aa3c31a8SRenat Idrisov   SmallVector<FunctionToCleanUp> functions;
105*aa3c31a8SRenat Idrisov   SmallVector<OperationToCleanup> operands;
106*aa3c31a8SRenat Idrisov   SmallVector<OperationToCleanup> results;
107*aa3c31a8SRenat Idrisov   SmallVector<BlockArgsToCleanup> blocks;
108*aa3c31a8SRenat Idrisov   SmallVector<SuccessorOperandsToCleanup> successorOperands;
109*aa3c31a8SRenat Idrisov };
110*aa3c31a8SRenat Idrisov 
1110e98fb9fSSrishti Srivastava // Some helper functions...
1120e98fb9fSSrishti Srivastava 
1130e98fb9fSSrishti Srivastava /// Return true iff at least one value in `values` is live, given the liveness
1140e98fb9fSSrishti Srivastava /// information in `la`.
115*aa3c31a8SRenat Idrisov static bool hasLive(ValueRange values, const DenseSet<Value> &nonLiveSet,
116*aa3c31a8SRenat Idrisov                     RunLivenessAnalysis &la) {
1170e98fb9fSSrishti Srivastava   for (Value value : values) {
118*aa3c31a8SRenat Idrisov     if (nonLiveSet.contains(value))
1190e98fb9fSSrishti Srivastava       continue;
1200e98fb9fSSrishti Srivastava 
1210e98fb9fSSrishti Srivastava     const Liveness *liveness = la.getLiveness(value);
1220e98fb9fSSrishti Srivastava     if (!liveness || liveness->isLive)
1230e98fb9fSSrishti Srivastava       return true;
1240e98fb9fSSrishti Srivastava   }
1250e98fb9fSSrishti Srivastava   return false;
1260e98fb9fSSrishti Srivastava }
1270e98fb9fSSrishti Srivastava 
1280e98fb9fSSrishti Srivastava /// Return a BitVector of size `values.size()` where its i-th bit is 1 iff the
1290e98fb9fSSrishti Srivastava /// i-th value in `values` is live, given the liveness information in `la`.
130*aa3c31a8SRenat Idrisov static BitVector markLives(ValueRange values, const DenseSet<Value> &nonLiveSet,
131*aa3c31a8SRenat Idrisov                            RunLivenessAnalysis &la) {
1320e98fb9fSSrishti Srivastava   BitVector lives(values.size(), true);
1330e98fb9fSSrishti Srivastava 
1340e98fb9fSSrishti Srivastava   for (auto [index, value] : llvm::enumerate(values)) {
135*aa3c31a8SRenat Idrisov     if (nonLiveSet.contains(value)) {
1360e98fb9fSSrishti Srivastava       lives.reset(index);
1370e98fb9fSSrishti Srivastava       continue;
1380e98fb9fSSrishti Srivastava     }
1390e98fb9fSSrishti Srivastava 
1400e98fb9fSSrishti Srivastava     const Liveness *liveness = la.getLiveness(value);
1410e98fb9fSSrishti Srivastava     // It is important to note that when `liveness` is null, we can't tell if
1420e98fb9fSSrishti Srivastava     // `value` is live or not. So, the safe option is to consider it live. Also,
1430e98fb9fSSrishti Srivastava     // the execution of this pass might create new SSA values when erasing some
1440e98fb9fSSrishti Srivastava     // of the results of an op and we know that these new values are live
1450e98fb9fSSrishti Srivastava     // (because they weren't erased) and also their liveness is null because
1460e98fb9fSSrishti Srivastava     // liveness analysis ran before their creation.
1470e98fb9fSSrishti Srivastava     if (liveness && !liveness->isLive)
1480e98fb9fSSrishti Srivastava       lives.reset(index);
1490e98fb9fSSrishti Srivastava   }
1500e98fb9fSSrishti Srivastava 
1510e98fb9fSSrishti Srivastava   return lives;
1520e98fb9fSSrishti Srivastava }
1530e98fb9fSSrishti Srivastava 
154*aa3c31a8SRenat Idrisov /// Collects values marked as "non-live" in the provided range and inserts them
155*aa3c31a8SRenat Idrisov /// into the nonLiveSet. A value is considered "non-live" if the corresponding
156*aa3c31a8SRenat Idrisov /// index in the `nonLive` bit vector is set.
157*aa3c31a8SRenat Idrisov static void collectNonLiveValues(DenseSet<Value> &nonLiveSet, ValueRange range,
158*aa3c31a8SRenat Idrisov                                  const BitVector &nonLive) {
159*aa3c31a8SRenat Idrisov   for (auto [index, result] : llvm::enumerate(range)) {
160*aa3c31a8SRenat Idrisov     if (!nonLive[index])
161*aa3c31a8SRenat Idrisov       continue;
162*aa3c31a8SRenat Idrisov     nonLiveSet.insert(result);
163*aa3c31a8SRenat Idrisov   }
164*aa3c31a8SRenat Idrisov }
165*aa3c31a8SRenat Idrisov 
1660e98fb9fSSrishti Srivastava /// Drop the uses of the i-th result of `op` and then erase it iff toErase[i]
1670e98fb9fSSrishti Srivastava /// is 1.
1680e98fb9fSSrishti Srivastava static void dropUsesAndEraseResults(Operation *op, BitVector toErase) {
1690e98fb9fSSrishti Srivastava   assert(op->getNumResults() == toErase.size() &&
1700e98fb9fSSrishti Srivastava          "expected the number of results in `op` and the size of `toErase` to "
1710e98fb9fSSrishti Srivastava          "be the same");
1720e98fb9fSSrishti Srivastava 
1730e98fb9fSSrishti Srivastava   std::vector<Type> newResultTypes;
1740e98fb9fSSrishti Srivastava   for (OpResult result : op->getResults())
1750e98fb9fSSrishti Srivastava     if (!toErase[result.getResultNumber()])
1760e98fb9fSSrishti Srivastava       newResultTypes.push_back(result.getType());
1770e98fb9fSSrishti Srivastava   OpBuilder builder(op);
1780e98fb9fSSrishti Srivastava   builder.setInsertionPointAfter(op);
1790e98fb9fSSrishti Srivastava   OperationState state(op->getLoc(), op->getName().getStringRef(),
1800e98fb9fSSrishti Srivastava                        op->getOperands(), newResultTypes, op->getAttrs());
1810e98fb9fSSrishti Srivastava   for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i)
1820e98fb9fSSrishti Srivastava     state.addRegion();
1830e98fb9fSSrishti Srivastava   Operation *newOp = builder.create(state);
1840e98fb9fSSrishti Srivastava   for (const auto &[index, region] : llvm::enumerate(op->getRegions())) {
1850e98fb9fSSrishti Srivastava     Region &newRegion = newOp->getRegion(index);
186b6bab6dbSSrishti Srivastava     // Move all blocks of `region` into `newRegion`.
187b6bab6dbSSrishti Srivastava     Block *temp = new Block();
188b6bab6dbSSrishti Srivastava     newRegion.push_back(temp);
189b6bab6dbSSrishti Srivastava     while (!region.empty())
190b6bab6dbSSrishti Srivastava       region.front().moveBefore(temp);
191b6bab6dbSSrishti Srivastava     temp->erase();
1920e98fb9fSSrishti Srivastava   }
1930e98fb9fSSrishti Srivastava 
1940e98fb9fSSrishti Srivastava   unsigned indexOfNextNewCallOpResultToReplace = 0;
1950e98fb9fSSrishti Srivastava   for (auto [index, result] : llvm::enumerate(op->getResults())) {
1960e98fb9fSSrishti Srivastava     assert(result && "expected result to be non-null");
1970e98fb9fSSrishti Srivastava     if (toErase[index]) {
1980e98fb9fSSrishti Srivastava       result.dropAllUses();
1990e98fb9fSSrishti Srivastava     } else {
2000e98fb9fSSrishti Srivastava       result.replaceAllUsesWith(
2010e98fb9fSSrishti Srivastava           newOp->getResult(indexOfNextNewCallOpResultToReplace++));
2020e98fb9fSSrishti Srivastava     }
2030e98fb9fSSrishti Srivastava   }
2040e98fb9fSSrishti Srivastava   op->erase();
2050e98fb9fSSrishti Srivastava }
2060e98fb9fSSrishti Srivastava 
2070e98fb9fSSrishti Srivastava /// Convert a list of `Operand`s to a list of `OpOperand`s.
2080e98fb9fSSrishti Srivastava static SmallVector<OpOperand *> operandsToOpOperands(OperandRange operands) {
2090e98fb9fSSrishti Srivastava   OpOperand *values = operands.getBase();
2100e98fb9fSSrishti Srivastava   SmallVector<OpOperand *> opOperands;
2110e98fb9fSSrishti Srivastava   for (unsigned i = 0, e = operands.size(); i < e; i++)
2120e98fb9fSSrishti Srivastava     opOperands.push_back(&values[i]);
2130e98fb9fSSrishti Srivastava   return opOperands;
2140e98fb9fSSrishti Srivastava }
2150e98fb9fSSrishti Srivastava 
216*aa3c31a8SRenat Idrisov /// Process a simple operation `op` using the liveness analysis `la`.
217*aa3c31a8SRenat Idrisov /// If the operation has no memory effects and none of its results are live:
218*aa3c31a8SRenat Idrisov ///   1. Add the operation to a list for future removal, and
219*aa3c31a8SRenat Idrisov ///   2. Mark all its results as non-live values
2200e98fb9fSSrishti Srivastava ///
221*aa3c31a8SRenat Idrisov /// The operation `op` is assumed to be simple. A simple operation is one that
222*aa3c31a8SRenat Idrisov /// is NOT:
223*aa3c31a8SRenat Idrisov ///   - Function-like
224*aa3c31a8SRenat Idrisov ///   - Call-like
225*aa3c31a8SRenat Idrisov ///   - A region branch operation
226*aa3c31a8SRenat Idrisov ///   - A branch operation
227*aa3c31a8SRenat Idrisov ///   - A region branch terminator
228*aa3c31a8SRenat Idrisov ///   - Return-like
229*aa3c31a8SRenat Idrisov static void processSimpleOp(Operation *op, RunLivenessAnalysis &la,
230*aa3c31a8SRenat Idrisov                             DenseSet<Value> &nonLiveSet,
231*aa3c31a8SRenat Idrisov                             RDVFinalCleanupList &cl) {
232*aa3c31a8SRenat Idrisov   if (!isMemoryEffectFree(op) || hasLive(op->getResults(), nonLiveSet, la))
2330e98fb9fSSrishti Srivastava     return;
2340e98fb9fSSrishti Srivastava 
235*aa3c31a8SRenat Idrisov   cl.operations.push_back(op);
236*aa3c31a8SRenat Idrisov   collectNonLiveValues(nonLiveSet, op->getResults(),
237*aa3c31a8SRenat Idrisov                        BitVector(op->getNumResults(), true));
2380e98fb9fSSrishti Srivastava }
2390e98fb9fSSrishti Srivastava 
240*aa3c31a8SRenat Idrisov /// Process a function-like operation `funcOp` using the liveness analysis `la`
241*aa3c31a8SRenat Idrisov /// and the IR in `module`. If it is not public or external:
242*aa3c31a8SRenat Idrisov ///   (1) Adding its non-live arguments to a list for future removal.
243*aa3c31a8SRenat Idrisov ///   (2) Marking their corresponding operands in its callers for removal.
244*aa3c31a8SRenat Idrisov ///   (3) Identifying and enqueueing unnecessary terminator operands
245*aa3c31a8SRenat Idrisov ///       (return values that are non-live across all callers) for removal.
246*aa3c31a8SRenat Idrisov ///   (4) Enqueueing the non-live arguments and return values for removal.
247*aa3c31a8SRenat Idrisov ///   (5) Collecting the uses of these return values in its callers for future
248*aa3c31a8SRenat Idrisov ///       removal.
249*aa3c31a8SRenat Idrisov ///   (6) Marking all its results as non-live values.
250*aa3c31a8SRenat Idrisov static void processFuncOp(FunctionOpInterface funcOp, Operation *module,
251*aa3c31a8SRenat Idrisov                           RunLivenessAnalysis &la, DenseSet<Value> &nonLiveSet,
252*aa3c31a8SRenat Idrisov                           RDVFinalCleanupList &cl) {
253e08e5e2cSLongsheng Mou   if (funcOp.isPublic() || funcOp.isExternal())
2540e98fb9fSSrishti Srivastava     return;
2550e98fb9fSSrishti Srivastava 
2560e98fb9fSSrishti Srivastava   // Get the list of unnecessary (non-live) arguments in `nonLiveArgs`.
2570e98fb9fSSrishti Srivastava   SmallVector<Value> arguments(funcOp.getArguments());
258*aa3c31a8SRenat Idrisov   BitVector nonLiveArgs = markLives(arguments, nonLiveSet, la);
2590e98fb9fSSrishti Srivastava   nonLiveArgs = nonLiveArgs.flip();
2600e98fb9fSSrishti Srivastava 
2610e98fb9fSSrishti Srivastava   // Do (1).
2620e98fb9fSSrishti Srivastava   for (auto [index, arg] : llvm::enumerate(arguments))
263*aa3c31a8SRenat Idrisov     if (arg && nonLiveArgs[index]) {
264*aa3c31a8SRenat Idrisov       cl.values.push_back(arg);
265*aa3c31a8SRenat Idrisov       nonLiveSet.insert(arg);
266*aa3c31a8SRenat Idrisov     }
2670e98fb9fSSrishti Srivastava 
2680e98fb9fSSrishti Srivastava   // Do (2).
2690e98fb9fSSrishti Srivastava   SymbolTable::UseRange uses = *funcOp.getSymbolUses(module);
2700e98fb9fSSrishti Srivastava   for (SymbolTable::SymbolUse use : uses) {
2710e98fb9fSSrishti Srivastava     Operation *callOp = use.getUser();
2720e98fb9fSSrishti Srivastava     assert(isa<CallOpInterface>(callOp) && "expected a call-like user");
2730e98fb9fSSrishti Srivastava     // The number of operands in the call op may not match the number of
2740e98fb9fSSrishti Srivastava     // arguments in the func op.
2750e98fb9fSSrishti Srivastava     BitVector nonLiveCallOperands(callOp->getNumOperands(), false);
2760e98fb9fSSrishti Srivastava     SmallVector<OpOperand *> callOpOperands =
2770e98fb9fSSrishti Srivastava         operandsToOpOperands(cast<CallOpInterface>(callOp).getArgOperands());
2780e98fb9fSSrishti Srivastava     for (int index : nonLiveArgs.set_bits())
2790e98fb9fSSrishti Srivastava       nonLiveCallOperands.set(callOpOperands[index]->getOperandNumber());
280*aa3c31a8SRenat Idrisov     cl.operands.push_back({callOp, nonLiveCallOperands});
2810e98fb9fSSrishti Srivastava   }
2820e98fb9fSSrishti Srivastava 
283*aa3c31a8SRenat Idrisov   // Do (3).
2840e98fb9fSSrishti Srivastava   // Get the list of unnecessary terminator operands (return values that are
2850e98fb9fSSrishti Srivastava   // non-live across all callers) in `nonLiveRets`. There is a very important
2860e98fb9fSSrishti Srivastava   // subtlety here. Unnecessary terminator operands are NOT the operands of the
2870e98fb9fSSrishti Srivastava   // terminator that are non-live. Instead, these are the return values of the
2880e98fb9fSSrishti Srivastava   // callers such that a given return value is non-live across all callers. Such
2890e98fb9fSSrishti Srivastava   // corresponding operands in the terminator could be live. An example to
2900e98fb9fSSrishti Srivastava   // demonstrate this:
2910e98fb9fSSrishti Srivastava   //  func.func private @f(%arg0: memref<i32>) -> (i32, i32) {
2920e98fb9fSSrishti Srivastava   //    %c0_i32 = arith.constant 0 : i32
2930e98fb9fSSrishti Srivastava   //    %0 = arith.addi %c0_i32, %c0_i32 : i32
2940e98fb9fSSrishti Srivastava   //    memref.store %0, %arg0[] : memref<i32>
2950e98fb9fSSrishti Srivastava   //    return %c0_i32, %0 : i32, i32
2960e98fb9fSSrishti Srivastava   //  }
2970e98fb9fSSrishti Srivastava   //  func.func @main(%arg0: i32, %arg1: memref<i32>) -> (i32) {
2980e98fb9fSSrishti Srivastava   //    %1:2 = call @f(%arg1) : (memref<i32>) -> i32
2990e98fb9fSSrishti Srivastava   //    return %1#0 : i32
3000e98fb9fSSrishti Srivastava   //  }
3010e98fb9fSSrishti Srivastava   // Here, we can see that %1#1 is never used. It is non-live. Thus, @f doesn't
3020e98fb9fSSrishti Srivastava   // need to return %0. But, %0 is live. And, still, we want to stop it from
3030e98fb9fSSrishti Srivastava   // being returned, in order to optimize our IR. So, this demonstrates how we
3040e98fb9fSSrishti Srivastava   // can make our optimization strong by even removing a live return value (%0),
3050e98fb9fSSrishti Srivastava   // since it forwards only to non-live value(s) (%1#1).
3060e98fb9fSSrishti Srivastava   Operation *lastReturnOp = funcOp.back().getTerminator();
3070e98fb9fSSrishti Srivastava   size_t numReturns = lastReturnOp->getNumOperands();
3080e98fb9fSSrishti Srivastava   BitVector nonLiveRets(numReturns, true);
3090e98fb9fSSrishti Srivastava   for (SymbolTable::SymbolUse use : uses) {
3100e98fb9fSSrishti Srivastava     Operation *callOp = use.getUser();
3110e98fb9fSSrishti Srivastava     assert(isa<CallOpInterface>(callOp) && "expected a call-like user");
312*aa3c31a8SRenat Idrisov     BitVector liveCallRets = markLives(callOp->getResults(), nonLiveSet, la);
3130e98fb9fSSrishti Srivastava     nonLiveRets &= liveCallRets.flip();
3140e98fb9fSSrishti Srivastava   }
3150e98fb9fSSrishti Srivastava 
3160e98fb9fSSrishti Srivastava   // Note that in the absence of control flow ops forcing the control to go from
3170e98fb9fSSrishti Srivastava   // the entry (first) block to the other blocks, the control never reaches any
3180e98fb9fSSrishti Srivastava   // block other than the entry block, because every block has a terminator.
3190e98fb9fSSrishti Srivastava   for (Block &block : funcOp.getBlocks()) {
3200e98fb9fSSrishti Srivastava     Operation *returnOp = block.getTerminator();
3210e98fb9fSSrishti Srivastava     if (returnOp && returnOp->getNumOperands() == numReturns)
322*aa3c31a8SRenat Idrisov       cl.operands.push_back({returnOp, nonLiveRets});
3230e98fb9fSSrishti Srivastava   }
324*aa3c31a8SRenat Idrisov 
325*aa3c31a8SRenat Idrisov   // Do (4).
326*aa3c31a8SRenat Idrisov   cl.functions.push_back({funcOp, nonLiveArgs, nonLiveRets});
3270e98fb9fSSrishti Srivastava 
3280e98fb9fSSrishti Srivastava   // Do (5) and (6).
3290e98fb9fSSrishti Srivastava   for (SymbolTable::SymbolUse use : uses) {
3300e98fb9fSSrishti Srivastava     Operation *callOp = use.getUser();
3310e98fb9fSSrishti Srivastava     assert(isa<CallOpInterface>(callOp) && "expected a call-like user");
332*aa3c31a8SRenat Idrisov     cl.results.push_back({callOp, nonLiveRets});
333*aa3c31a8SRenat Idrisov     collectNonLiveValues(nonLiveSet, callOp->getResults(), nonLiveRets);
3340e98fb9fSSrishti Srivastava   }
3350e98fb9fSSrishti Srivastava }
3360e98fb9fSSrishti Srivastava 
337*aa3c31a8SRenat Idrisov /// Process a region branch operation `regionBranchOp` using the liveness
338*aa3c31a8SRenat Idrisov /// information in `la`. The processing involves two scenarios:
339*aa3c31a8SRenat Idrisov ///
340*aa3c31a8SRenat Idrisov /// Scenario 1: If the operation has no memory effects and none of its results
341*aa3c31a8SRenat Idrisov /// are live:
342*aa3c31a8SRenat Idrisov ///   (1') Enqueue all its uses for deletion.
343*aa3c31a8SRenat Idrisov ///   (2') Enqueue the branch itself for deletion.
344*aa3c31a8SRenat Idrisov ///
345*aa3c31a8SRenat Idrisov /// Scenario 2: Otherwise:
346*aa3c31a8SRenat Idrisov ///   (1) Collect its unnecessary operands (operands forwarded to unnecessary
347*aa3c31a8SRenat Idrisov ///       results or arguments).
348*aa3c31a8SRenat Idrisov ///   (2) Process each of its regions.
349*aa3c31a8SRenat Idrisov ///   (3) Collect the uses of its unnecessary results (results forwarded from
350*aa3c31a8SRenat Idrisov ///       unnecessary operands
351*aa3c31a8SRenat Idrisov ///       or terminator operands).
352*aa3c31a8SRenat Idrisov ///   (4) Add these results to the deletion list.
353*aa3c31a8SRenat Idrisov ///
354*aa3c31a8SRenat Idrisov /// Processing a region includes:
355*aa3c31a8SRenat Idrisov ///   (a) Collecting the uses of its unnecessary arguments (arguments forwarded
356*aa3c31a8SRenat Idrisov ///       from unnecessary operands
357*aa3c31a8SRenat Idrisov ///       or terminator operands).
358*aa3c31a8SRenat Idrisov ///   (b) Collecting these unnecessary arguments.
359*aa3c31a8SRenat Idrisov ///   (c) Collecting its unnecessary terminator operands (terminator operands
360*aa3c31a8SRenat Idrisov ///       forwarded to unnecessary results
361*aa3c31a8SRenat Idrisov ///       or arguments).
362*aa3c31a8SRenat Idrisov ///
363*aa3c31a8SRenat Idrisov /// Value Flow Note: In this operation, values flow as follows:
364*aa3c31a8SRenat Idrisov /// - From operands and terminator operands (successor operands)
365*aa3c31a8SRenat Idrisov /// - To arguments and results (successor inputs).
366*aa3c31a8SRenat Idrisov static void processRegionBranchOp(RegionBranchOpInterface regionBranchOp,
367*aa3c31a8SRenat Idrisov                                   RunLivenessAnalysis &la,
368*aa3c31a8SRenat Idrisov                                   DenseSet<Value> &nonLiveSet,
369*aa3c31a8SRenat Idrisov                                   RDVFinalCleanupList &cl) {
3700e98fb9fSSrishti Srivastava   // Mark live results of `regionBranchOp` in `liveResults`.
3710e98fb9fSSrishti Srivastava   auto markLiveResults = [&](BitVector &liveResults) {
372*aa3c31a8SRenat Idrisov     liveResults = markLives(regionBranchOp->getResults(), nonLiveSet, la);
3730e98fb9fSSrishti Srivastava   };
3740e98fb9fSSrishti Srivastava 
3750e98fb9fSSrishti Srivastava   // Mark live arguments in the regions of `regionBranchOp` in `liveArgs`.
3760e98fb9fSSrishti Srivastava   auto markLiveArgs = [&](DenseMap<Region *, BitVector> &liveArgs) {
3770e98fb9fSSrishti Srivastava     for (Region &region : regionBranchOp->getRegions()) {
3780e98fb9fSSrishti Srivastava       SmallVector<Value> arguments(region.front().getArguments());
379*aa3c31a8SRenat Idrisov       BitVector regionLiveArgs = markLives(arguments, nonLiveSet, la);
3800e98fb9fSSrishti Srivastava       liveArgs[&region] = regionLiveArgs;
3810e98fb9fSSrishti Srivastava     }
3820e98fb9fSSrishti Srivastava   };
3830e98fb9fSSrishti Srivastava 
3840e98fb9fSSrishti Srivastava   // Return the successors of `region` if the latter is not null. Else return
3850e98fb9fSSrishti Srivastava   // the successors of `regionBranchOp`.
3860e98fb9fSSrishti Srivastava   auto getSuccessors = [&](Region *region = nullptr) {
3874dd744acSMarkus Böck     auto point = region ? region : RegionBranchPoint::parent();
3880e98fb9fSSrishti Srivastava     SmallVector<Attribute> operandAttributes(regionBranchOp->getNumOperands(),
3890e98fb9fSSrishti Srivastava                                              nullptr);
3900e98fb9fSSrishti Srivastava     SmallVector<RegionSuccessor> successors;
3914dd744acSMarkus Böck     regionBranchOp.getSuccessorRegions(point, successors);
3920e98fb9fSSrishti Srivastava     return successors;
3930e98fb9fSSrishti Srivastava   };
3940e98fb9fSSrishti Srivastava 
3950e98fb9fSSrishti Srivastava   // Return the operands of `terminator` that are forwarded to `successor` if
3960e98fb9fSSrishti Srivastava   // the former is not null. Else return the operands of `regionBranchOp`
3970e98fb9fSSrishti Srivastava   // forwarded to `successor`.
3980e98fb9fSSrishti Srivastava   auto getForwardedOpOperands = [&](const RegionSuccessor &successor,
3990e98fb9fSSrishti Srivastava                                     Operation *terminator = nullptr) {
4000e98fb9fSSrishti Srivastava     OperandRange operands =
4010e98fb9fSSrishti Srivastava         terminator ? cast<RegionBranchTerminatorOpInterface>(terminator)
4024dd744acSMarkus Böck                          .getSuccessorOperands(successor)
4034dd744acSMarkus Böck                    : regionBranchOp.getEntrySuccessorOperands(successor);
4040e98fb9fSSrishti Srivastava     SmallVector<OpOperand *> opOperands = operandsToOpOperands(operands);
4050e98fb9fSSrishti Srivastava     return opOperands;
4060e98fb9fSSrishti Srivastava   };
4070e98fb9fSSrishti Srivastava 
4080e98fb9fSSrishti Srivastava   // Mark the non-forwarded operands of `regionBranchOp` in
4090e98fb9fSSrishti Srivastava   // `nonForwardedOperands`.
4100e98fb9fSSrishti Srivastava   auto markNonForwardedOperands = [&](BitVector &nonForwardedOperands) {
4110e98fb9fSSrishti Srivastava     nonForwardedOperands.resize(regionBranchOp->getNumOperands(), true);
4120e98fb9fSSrishti Srivastava     for (const RegionSuccessor &successor : getSuccessors()) {
4130e98fb9fSSrishti Srivastava       for (OpOperand *opOperand : getForwardedOpOperands(successor))
4140e98fb9fSSrishti Srivastava         nonForwardedOperands.reset(opOperand->getOperandNumber());
4150e98fb9fSSrishti Srivastava     }
4160e98fb9fSSrishti Srivastava   };
4170e98fb9fSSrishti Srivastava 
4180e98fb9fSSrishti Srivastava   // Mark the non-forwarded terminator operands of the various regions of
4190e98fb9fSSrishti Srivastava   // `regionBranchOp` in `nonForwardedRets`.
4200e98fb9fSSrishti Srivastava   auto markNonForwardedReturnValues =
4210e98fb9fSSrishti Srivastava       [&](DenseMap<Operation *, BitVector> &nonForwardedRets) {
4220e98fb9fSSrishti Srivastava         for (Region &region : regionBranchOp->getRegions()) {
4230e98fb9fSSrishti Srivastava           Operation *terminator = region.front().getTerminator();
4240e98fb9fSSrishti Srivastava           nonForwardedRets[terminator] =
4250e98fb9fSSrishti Srivastava               BitVector(terminator->getNumOperands(), true);
4260e98fb9fSSrishti Srivastava           for (const RegionSuccessor &successor : getSuccessors(&region)) {
4270e98fb9fSSrishti Srivastava             for (OpOperand *opOperand :
4280e98fb9fSSrishti Srivastava                  getForwardedOpOperands(successor, terminator))
4290e98fb9fSSrishti Srivastava               nonForwardedRets[terminator].reset(opOperand->getOperandNumber());
4300e98fb9fSSrishti Srivastava           }
4310e98fb9fSSrishti Srivastava         }
4320e98fb9fSSrishti Srivastava       };
4330e98fb9fSSrishti Srivastava 
4340e98fb9fSSrishti Srivastava   // Update `valuesToKeep` (which is expected to correspond to operands or
4350e98fb9fSSrishti Srivastava   // terminator operands) based on `resultsToKeep` and `argsToKeep`, given
4360e98fb9fSSrishti Srivastava   // `region`. When `valuesToKeep` correspond to operands, `region` is null.
4370e98fb9fSSrishti Srivastava   // Else, `region` is the parent region of the terminator.
4380e98fb9fSSrishti Srivastava   auto updateOperandsOrTerminatorOperandsToKeep =
4390e98fb9fSSrishti Srivastava       [&](BitVector &valuesToKeep, BitVector &resultsToKeep,
4400e98fb9fSSrishti Srivastava           DenseMap<Region *, BitVector> &argsToKeep, Region *region = nullptr) {
4410e98fb9fSSrishti Srivastava         Operation *terminator =
4420e98fb9fSSrishti Srivastava             region ? region->front().getTerminator() : nullptr;
4430e98fb9fSSrishti Srivastava 
4440e98fb9fSSrishti Srivastava         for (const RegionSuccessor &successor : getSuccessors(region)) {
4450e98fb9fSSrishti Srivastava           Region *successorRegion = successor.getSuccessor();
4460e98fb9fSSrishti Srivastava           for (auto [opOperand, input] :
4470e98fb9fSSrishti Srivastava                llvm::zip(getForwardedOpOperands(successor, terminator),
4480e98fb9fSSrishti Srivastava                          successor.getSuccessorInputs())) {
4490e98fb9fSSrishti Srivastava             size_t operandNum = opOperand->getOperandNumber();
4500e98fb9fSSrishti Srivastava             bool updateBasedOn =
4510e98fb9fSSrishti Srivastava                 successorRegion
4520e98fb9fSSrishti Srivastava                     ? argsToKeep[successorRegion]
4530e98fb9fSSrishti Srivastava                                 [cast<BlockArgument>(input).getArgNumber()]
4540e98fb9fSSrishti Srivastava                     : resultsToKeep[cast<OpResult>(input).getResultNumber()];
4550e98fb9fSSrishti Srivastava             valuesToKeep[operandNum] = valuesToKeep[operandNum] | updateBasedOn;
4560e98fb9fSSrishti Srivastava           }
4570e98fb9fSSrishti Srivastava         }
4580e98fb9fSSrishti Srivastava       };
4590e98fb9fSSrishti Srivastava 
4600e98fb9fSSrishti Srivastava   // Recompute `resultsToKeep` and `argsToKeep` based on `operandsToKeep` and
4610e98fb9fSSrishti Srivastava   // `terminatorOperandsToKeep`. Store true in `resultsOrArgsToKeepChanged` if a
4620e98fb9fSSrishti Srivastava   // value is modified, else, false.
4630e98fb9fSSrishti Srivastava   auto recomputeResultsAndArgsToKeep =
4640e98fb9fSSrishti Srivastava       [&](BitVector &resultsToKeep, DenseMap<Region *, BitVector> &argsToKeep,
4650e98fb9fSSrishti Srivastava           BitVector &operandsToKeep,
4660e98fb9fSSrishti Srivastava           DenseMap<Operation *, BitVector> &terminatorOperandsToKeep,
4670e98fb9fSSrishti Srivastava           bool &resultsOrArgsToKeepChanged) {
4680e98fb9fSSrishti Srivastava         resultsOrArgsToKeepChanged = false;
4690e98fb9fSSrishti Srivastava 
4700e98fb9fSSrishti Srivastava         // Recompute `resultsToKeep` and `argsToKeep` based on `operandsToKeep`.
4710e98fb9fSSrishti Srivastava         for (const RegionSuccessor &successor : getSuccessors()) {
4720e98fb9fSSrishti Srivastava           Region *successorRegion = successor.getSuccessor();
4730e98fb9fSSrishti Srivastava           for (auto [opOperand, input] :
4740e98fb9fSSrishti Srivastava                llvm::zip(getForwardedOpOperands(successor),
4750e98fb9fSSrishti Srivastava                          successor.getSuccessorInputs())) {
4760e98fb9fSSrishti Srivastava             bool recomputeBasedOn =
4770e98fb9fSSrishti Srivastava                 operandsToKeep[opOperand->getOperandNumber()];
4780e98fb9fSSrishti Srivastava             bool toRecompute =
4790e98fb9fSSrishti Srivastava                 successorRegion
4800e98fb9fSSrishti Srivastava                     ? argsToKeep[successorRegion]
4810e98fb9fSSrishti Srivastava                                 [cast<BlockArgument>(input).getArgNumber()]
4820e98fb9fSSrishti Srivastava                     : resultsToKeep[cast<OpResult>(input).getResultNumber()];
4830e98fb9fSSrishti Srivastava             if (!toRecompute && recomputeBasedOn)
4840e98fb9fSSrishti Srivastava               resultsOrArgsToKeepChanged = true;
4850e98fb9fSSrishti Srivastava             if (successorRegion) {
4860e98fb9fSSrishti Srivastava               argsToKeep[successorRegion][cast<BlockArgument>(input)
4870e98fb9fSSrishti Srivastava                                               .getArgNumber()] =
4880e98fb9fSSrishti Srivastava                   argsToKeep[successorRegion]
4890e98fb9fSSrishti Srivastava                             [cast<BlockArgument>(input).getArgNumber()] |
4900e98fb9fSSrishti Srivastava                   recomputeBasedOn;
4910e98fb9fSSrishti Srivastava             } else {
4920e98fb9fSSrishti Srivastava               resultsToKeep[cast<OpResult>(input).getResultNumber()] =
4930e98fb9fSSrishti Srivastava                   resultsToKeep[cast<OpResult>(input).getResultNumber()] |
4940e98fb9fSSrishti Srivastava                   recomputeBasedOn;
4950e98fb9fSSrishti Srivastava             }
4960e98fb9fSSrishti Srivastava           }
4970e98fb9fSSrishti Srivastava         }
4980e98fb9fSSrishti Srivastava 
4990e98fb9fSSrishti Srivastava         // Recompute `resultsToKeep` and `argsToKeep` based on
5000e98fb9fSSrishti Srivastava         // `terminatorOperandsToKeep`.
5010e98fb9fSSrishti Srivastava         for (Region &region : regionBranchOp->getRegions()) {
5020e98fb9fSSrishti Srivastava           Operation *terminator = region.front().getTerminator();
5030e98fb9fSSrishti Srivastava           for (const RegionSuccessor &successor : getSuccessors(&region)) {
5040e98fb9fSSrishti Srivastava             Region *successorRegion = successor.getSuccessor();
5050e98fb9fSSrishti Srivastava             for (auto [opOperand, input] :
5060e98fb9fSSrishti Srivastava                  llvm::zip(getForwardedOpOperands(successor, terminator),
5070e98fb9fSSrishti Srivastava                            successor.getSuccessorInputs())) {
5080e98fb9fSSrishti Srivastava               bool recomputeBasedOn =
5090e98fb9fSSrishti Srivastava                   terminatorOperandsToKeep[region.back().getTerminator()]
5100e98fb9fSSrishti Srivastava                                           [opOperand->getOperandNumber()];
5110e98fb9fSSrishti Srivastava               bool toRecompute =
5120e98fb9fSSrishti Srivastava                   successorRegion
5130e98fb9fSSrishti Srivastava                       ? argsToKeep[successorRegion]
5140e98fb9fSSrishti Srivastava                                   [cast<BlockArgument>(input).getArgNumber()]
5150e98fb9fSSrishti Srivastava                       : resultsToKeep[cast<OpResult>(input).getResultNumber()];
5160e98fb9fSSrishti Srivastava               if (!toRecompute && recomputeBasedOn)
5170e98fb9fSSrishti Srivastava                 resultsOrArgsToKeepChanged = true;
5180e98fb9fSSrishti Srivastava               if (successorRegion) {
5190e98fb9fSSrishti Srivastava                 argsToKeep[successorRegion][cast<BlockArgument>(input)
5200e98fb9fSSrishti Srivastava                                                 .getArgNumber()] =
5210e98fb9fSSrishti Srivastava                     argsToKeep[successorRegion]
5220e98fb9fSSrishti Srivastava                               [cast<BlockArgument>(input).getArgNumber()] |
5230e98fb9fSSrishti Srivastava                     recomputeBasedOn;
5240e98fb9fSSrishti Srivastava               } else {
5250e98fb9fSSrishti Srivastava                 resultsToKeep[cast<OpResult>(input).getResultNumber()] =
5260e98fb9fSSrishti Srivastava                     resultsToKeep[cast<OpResult>(input).getResultNumber()] |
5270e98fb9fSSrishti Srivastava                     recomputeBasedOn;
5280e98fb9fSSrishti Srivastava               }
5290e98fb9fSSrishti Srivastava             }
5300e98fb9fSSrishti Srivastava           }
5310e98fb9fSSrishti Srivastava         }
5320e98fb9fSSrishti Srivastava       };
5330e98fb9fSSrishti Srivastava 
5340e98fb9fSSrishti Srivastava   // Mark the values that we want to keep in `resultsToKeep`, `argsToKeep`,
5350e98fb9fSSrishti Srivastava   // `operandsToKeep`, and `terminatorOperandsToKeep`.
5360e98fb9fSSrishti Srivastava   auto markValuesToKeep =
5370e98fb9fSSrishti Srivastava       [&](BitVector &resultsToKeep, DenseMap<Region *, BitVector> &argsToKeep,
5380e98fb9fSSrishti Srivastava           BitVector &operandsToKeep,
5390e98fb9fSSrishti Srivastava           DenseMap<Operation *, BitVector> &terminatorOperandsToKeep) {
5400e98fb9fSSrishti Srivastava         bool resultsOrArgsToKeepChanged = true;
5410e98fb9fSSrishti Srivastava         // We keep updating and recomputing the values until we reach a point
5420e98fb9fSSrishti Srivastava         // where they stop changing.
5430e98fb9fSSrishti Srivastava         while (resultsOrArgsToKeepChanged) {
5440e98fb9fSSrishti Srivastava           // Update the operands that need to be kept.
5450e98fb9fSSrishti Srivastava           updateOperandsOrTerminatorOperandsToKeep(operandsToKeep,
5460e98fb9fSSrishti Srivastava                                                    resultsToKeep, argsToKeep);
5470e98fb9fSSrishti Srivastava 
5480e98fb9fSSrishti Srivastava           // Update the terminator operands that need to be kept.
5490e98fb9fSSrishti Srivastava           for (Region &region : regionBranchOp->getRegions()) {
5500e98fb9fSSrishti Srivastava             updateOperandsOrTerminatorOperandsToKeep(
5510e98fb9fSSrishti Srivastava                 terminatorOperandsToKeep[region.back().getTerminator()],
5520e98fb9fSSrishti Srivastava                 resultsToKeep, argsToKeep, &region);
5530e98fb9fSSrishti Srivastava           }
5540e98fb9fSSrishti Srivastava 
5550e98fb9fSSrishti Srivastava           // Recompute the results and arguments that need to be kept.
5560e98fb9fSSrishti Srivastava           recomputeResultsAndArgsToKeep(
5570e98fb9fSSrishti Srivastava               resultsToKeep, argsToKeep, operandsToKeep,
5580e98fb9fSSrishti Srivastava               terminatorOperandsToKeep, resultsOrArgsToKeepChanged);
5590e98fb9fSSrishti Srivastava         }
5600e98fb9fSSrishti Srivastava       };
5610e98fb9fSSrishti Srivastava 
562*aa3c31a8SRenat Idrisov   // Scenario 1. This is the only case where the entire `regionBranchOp`
5630e98fb9fSSrishti Srivastava   // is removed. It will not happen in any other scenario. Note that in this
5640e98fb9fSSrishti Srivastava   // case, a non-forwarded operand of `regionBranchOp` could be live/non-live.
5650e98fb9fSSrishti Srivastava   // It could never be live because of this op but its liveness could have been
5660e98fb9fSSrishti Srivastava   // attributed to something else.
567*aa3c31a8SRenat Idrisov   // Do (1') and (2').
5680e98fb9fSSrishti Srivastava   if (isMemoryEffectFree(regionBranchOp.getOperation()) &&
569*aa3c31a8SRenat Idrisov       !hasLive(regionBranchOp->getResults(), nonLiveSet, la)) {
570*aa3c31a8SRenat Idrisov     cl.operations.push_back(regionBranchOp.getOperation());
5710e98fb9fSSrishti Srivastava     return;
5720e98fb9fSSrishti Srivastava   }
5730e98fb9fSSrishti Srivastava 
574*aa3c31a8SRenat Idrisov   // Scenario 2.
5750e98fb9fSSrishti Srivastava   // At this point, we know that every non-forwarded operand of `regionBranchOp`
5760e98fb9fSSrishti Srivastava   // is live.
5770e98fb9fSSrishti Srivastava 
5780e98fb9fSSrishti Srivastava   // Stores the results of `regionBranchOp` that we want to keep.
5790e98fb9fSSrishti Srivastava   BitVector resultsToKeep;
5800e98fb9fSSrishti Srivastava   // Stores the mapping from regions of `regionBranchOp` to their arguments that
5810e98fb9fSSrishti Srivastava   // we want to keep.
5820e98fb9fSSrishti Srivastava   DenseMap<Region *, BitVector> argsToKeep;
5830e98fb9fSSrishti Srivastava   // Stores the operands of `regionBranchOp` that we want to keep.
5840e98fb9fSSrishti Srivastava   BitVector operandsToKeep;
5850e98fb9fSSrishti Srivastava   // Stores the mapping from region terminators in `regionBranchOp` to their
5860e98fb9fSSrishti Srivastava   // operands that we want to keep.
5870e98fb9fSSrishti Srivastava   DenseMap<Operation *, BitVector> terminatorOperandsToKeep;
5880e98fb9fSSrishti Srivastava 
5890e98fb9fSSrishti Srivastava   // Initializing the above variables...
5900e98fb9fSSrishti Srivastava 
5910e98fb9fSSrishti Srivastava   // The live results of `regionBranchOp` definitely need to be kept.
5920e98fb9fSSrishti Srivastava   markLiveResults(resultsToKeep);
5930e98fb9fSSrishti Srivastava   // Similarly, the live arguments of the regions in `regionBranchOp` definitely
5940e98fb9fSSrishti Srivastava   // need to be kept.
5950e98fb9fSSrishti Srivastava   markLiveArgs(argsToKeep);
5960e98fb9fSSrishti Srivastava   // The non-forwarded operands of `regionBranchOp` definitely need to be kept.
5970e98fb9fSSrishti Srivastava   // A live forwarded operand can be removed but no non-forwarded operand can be
5980e98fb9fSSrishti Srivastava   // removed since it "controls" the flow of data in this control flow op.
5990e98fb9fSSrishti Srivastava   markNonForwardedOperands(operandsToKeep);
6000e98fb9fSSrishti Srivastava   // Similarly, the non-forwarded terminator operands of the regions in
6010e98fb9fSSrishti Srivastava   // `regionBranchOp` definitely need to be kept.
6020e98fb9fSSrishti Srivastava   markNonForwardedReturnValues(terminatorOperandsToKeep);
6030e98fb9fSSrishti Srivastava 
6040e98fb9fSSrishti Srivastava   // Mark the values (results, arguments, operands, and terminator operands)
6050e98fb9fSSrishti Srivastava   // that we want to keep.
6060e98fb9fSSrishti Srivastava   markValuesToKeep(resultsToKeep, argsToKeep, operandsToKeep,
6070e98fb9fSSrishti Srivastava                    terminatorOperandsToKeep);
6080e98fb9fSSrishti Srivastava 
6090e98fb9fSSrishti Srivastava   // Do (1).
610*aa3c31a8SRenat Idrisov   cl.operands.push_back({regionBranchOp, operandsToKeep.flip()});
6110e98fb9fSSrishti Srivastava 
6120e98fb9fSSrishti Srivastava   // Do (2.a) and (2.b).
6130e98fb9fSSrishti Srivastava   for (Region &region : regionBranchOp->getRegions()) {
6140e98fb9fSSrishti Srivastava     assert(!region.empty() && "expected a non-empty region in an op "
6150e98fb9fSSrishti Srivastava                               "implementing `RegionBranchOpInterface`");
616*aa3c31a8SRenat Idrisov     BitVector argsToRemove = argsToKeep[&region].flip();
617*aa3c31a8SRenat Idrisov     cl.blocks.push_back({&region.front(), argsToRemove});
618*aa3c31a8SRenat Idrisov     collectNonLiveValues(nonLiveSet, region.front().getArguments(),
619*aa3c31a8SRenat Idrisov                          argsToRemove);
6200e98fb9fSSrishti Srivastava   }
6210e98fb9fSSrishti Srivastava 
6220e98fb9fSSrishti Srivastava   // Do (2.c).
6230e98fb9fSSrishti Srivastava   for (Region &region : regionBranchOp->getRegions()) {
6240e98fb9fSSrishti Srivastava     Operation *terminator = region.front().getTerminator();
625*aa3c31a8SRenat Idrisov     cl.operands.push_back(
626*aa3c31a8SRenat Idrisov         {terminator, terminatorOperandsToKeep[terminator].flip()});
6270e98fb9fSSrishti Srivastava   }
6280e98fb9fSSrishti Srivastava 
6290e98fb9fSSrishti Srivastava   // Do (3) and (4).
630*aa3c31a8SRenat Idrisov   BitVector resultsToRemove = resultsToKeep.flip();
631*aa3c31a8SRenat Idrisov   collectNonLiveValues(nonLiveSet, regionBranchOp.getOperation()->getResults(),
632*aa3c31a8SRenat Idrisov                        resultsToRemove);
633*aa3c31a8SRenat Idrisov   cl.results.push_back({regionBranchOp.getOperation(), resultsToRemove});
6340e98fb9fSSrishti Srivastava }
6350e98fb9fSSrishti Srivastava 
636*aa3c31a8SRenat Idrisov /// Steps to process a `BranchOpInterface` operation:
637*aa3c31a8SRenat Idrisov /// Iterate through each successor block of `branchOp`.
638*aa3c31a8SRenat Idrisov /// (1) For each successor block, gather all operands from all successors.
639*aa3c31a8SRenat Idrisov /// (2) Fetch their associated liveness analysis data and collect for future
640*aa3c31a8SRenat Idrisov ///     removal.
641*aa3c31a8SRenat Idrisov /// (3) Identify and collect the dead operands from the successor block
642*aa3c31a8SRenat Idrisov ///     as well as their corresponding arguments.
6430629e9e3SRenat Idrisov 
644*aa3c31a8SRenat Idrisov static void processBranchOp(BranchOpInterface branchOp, RunLivenessAnalysis &la,
645*aa3c31a8SRenat Idrisov                             DenseSet<Value> &nonLiveSet,
646*aa3c31a8SRenat Idrisov                             RDVFinalCleanupList &cl) {
6470629e9e3SRenat Idrisov   unsigned numSuccessors = branchOp->getNumSuccessors();
6480629e9e3SRenat Idrisov 
6490629e9e3SRenat Idrisov   for (unsigned succIdx = 0; succIdx < numSuccessors; ++succIdx) {
6500629e9e3SRenat Idrisov     Block *successorBlock = branchOp->getSuccessor(succIdx);
6510629e9e3SRenat Idrisov 
652*aa3c31a8SRenat Idrisov     // Do (1)
6530629e9e3SRenat Idrisov     SuccessorOperands successorOperands =
6540629e9e3SRenat Idrisov         branchOp.getSuccessorOperands(succIdx);
6550629e9e3SRenat Idrisov     SmallVector<Value> operandValues;
6560629e9e3SRenat Idrisov     for (unsigned operandIdx = 0; operandIdx < successorOperands.size();
6570629e9e3SRenat Idrisov          ++operandIdx) {
6580629e9e3SRenat Idrisov       operandValues.push_back(successorOperands[operandIdx]);
6590629e9e3SRenat Idrisov     }
6600629e9e3SRenat Idrisov 
661*aa3c31a8SRenat Idrisov     // Do (2)
662*aa3c31a8SRenat Idrisov     BitVector successorNonLive =
663*aa3c31a8SRenat Idrisov         markLives(operandValues, nonLiveSet, la).flip();
664*aa3c31a8SRenat Idrisov     collectNonLiveValues(nonLiveSet, successorBlock->getArguments(),
665*aa3c31a8SRenat Idrisov                          successorNonLive);
6660629e9e3SRenat Idrisov 
6670629e9e3SRenat Idrisov     // Do (3)
668*aa3c31a8SRenat Idrisov     cl.blocks.push_back({successorBlock, successorNonLive});
669*aa3c31a8SRenat Idrisov     cl.successorOperands.push_back({branchOp, succIdx, successorNonLive});
670*aa3c31a8SRenat Idrisov   }
6710629e9e3SRenat Idrisov }
6720629e9e3SRenat Idrisov 
673*aa3c31a8SRenat Idrisov /// Removes dead values collected in RDVFinalCleanupList.
674*aa3c31a8SRenat Idrisov /// To be run once when all dead values have been collected.
675*aa3c31a8SRenat Idrisov static void cleanUpDeadVals(RDVFinalCleanupList &list) {
676*aa3c31a8SRenat Idrisov   // 1. Operations
677*aa3c31a8SRenat Idrisov   for (auto &op : list.operations) {
678*aa3c31a8SRenat Idrisov     op->dropAllUses();
679*aa3c31a8SRenat Idrisov     op->erase();
6800629e9e3SRenat Idrisov   }
681*aa3c31a8SRenat Idrisov 
682*aa3c31a8SRenat Idrisov   // 2. Values
683*aa3c31a8SRenat Idrisov   for (auto &v : list.values) {
684*aa3c31a8SRenat Idrisov     v.dropAllUses();
685*aa3c31a8SRenat Idrisov   }
686*aa3c31a8SRenat Idrisov 
687*aa3c31a8SRenat Idrisov   // 3. Functions
688*aa3c31a8SRenat Idrisov   for (auto &f : list.functions) {
689*aa3c31a8SRenat Idrisov     f.funcOp.eraseArguments(f.nonLiveArgs);
690*aa3c31a8SRenat Idrisov     f.funcOp.eraseResults(f.nonLiveRets);
691*aa3c31a8SRenat Idrisov   }
692*aa3c31a8SRenat Idrisov 
693*aa3c31a8SRenat Idrisov   // 4. Operands
694*aa3c31a8SRenat Idrisov   for (auto &o : list.operands) {
695*aa3c31a8SRenat Idrisov     o.op->eraseOperands(o.nonLive);
696*aa3c31a8SRenat Idrisov   }
697*aa3c31a8SRenat Idrisov 
698*aa3c31a8SRenat Idrisov   // 5. Results
699*aa3c31a8SRenat Idrisov   for (auto &r : list.results) {
700*aa3c31a8SRenat Idrisov     dropUsesAndEraseResults(r.op, r.nonLive);
701*aa3c31a8SRenat Idrisov   }
702*aa3c31a8SRenat Idrisov 
703*aa3c31a8SRenat Idrisov   // 6. Blocks
704*aa3c31a8SRenat Idrisov   for (auto &b : list.blocks) {
705*aa3c31a8SRenat Idrisov     // blocks that are accessed via multiple codepaths processed once
706*aa3c31a8SRenat Idrisov     if (b.b->getNumArguments() != b.nonLiveArgs.size())
707*aa3c31a8SRenat Idrisov       continue;
708*aa3c31a8SRenat Idrisov     // it iterates backwards because erase invalidates all successor indexes
709*aa3c31a8SRenat Idrisov     for (int i = b.nonLiveArgs.size() - 1; i >= 0; --i) {
710*aa3c31a8SRenat Idrisov       if (!b.nonLiveArgs[i])
711*aa3c31a8SRenat Idrisov         continue;
712*aa3c31a8SRenat Idrisov       b.b->getArgument(i).dropAllUses();
713*aa3c31a8SRenat Idrisov       b.b->eraseArgument(i);
714*aa3c31a8SRenat Idrisov     }
715*aa3c31a8SRenat Idrisov   }
716*aa3c31a8SRenat Idrisov 
717*aa3c31a8SRenat Idrisov   // 7. Successor Operands
718*aa3c31a8SRenat Idrisov   for (auto &op : list.successorOperands) {
719*aa3c31a8SRenat Idrisov     SuccessorOperands successorOperands =
720*aa3c31a8SRenat Idrisov         op.branch.getSuccessorOperands(op.successorIndex);
721*aa3c31a8SRenat Idrisov     // blocks that are accessed via multiple codepaths processed once
722*aa3c31a8SRenat Idrisov     if (successorOperands.size() != op.nonLiveOperands.size())
723*aa3c31a8SRenat Idrisov       continue;
724*aa3c31a8SRenat Idrisov     // it iterates backwards because erase invalidates all successor indexes
725*aa3c31a8SRenat Idrisov     for (int i = successorOperands.size() - 1; i >= 0; --i) {
726*aa3c31a8SRenat Idrisov       if (!op.nonLiveOperands[i])
727*aa3c31a8SRenat Idrisov         continue;
728*aa3c31a8SRenat Idrisov       successorOperands.erase(i);
7290629e9e3SRenat Idrisov     }
7300629e9e3SRenat Idrisov   }
7310629e9e3SRenat Idrisov }
7320629e9e3SRenat Idrisov 
7330e98fb9fSSrishti Srivastava struct RemoveDeadValues : public impl::RemoveDeadValuesBase<RemoveDeadValues> {
7340e98fb9fSSrishti Srivastava   void runOnOperation() override;
7350e98fb9fSSrishti Srivastava };
7360e98fb9fSSrishti Srivastava } // namespace
7370e98fb9fSSrishti Srivastava 
7380e98fb9fSSrishti Srivastava void RemoveDeadValues::runOnOperation() {
7390e98fb9fSSrishti Srivastava   auto &la = getAnalysis<RunLivenessAnalysis>();
7400e98fb9fSSrishti Srivastava   Operation *module = getOperation();
7410e98fb9fSSrishti Srivastava 
742*aa3c31a8SRenat Idrisov   // Tracks values eligible for erasure - complements liveness analysis to
743*aa3c31a8SRenat Idrisov   // identify "droppable" values.
744*aa3c31a8SRenat Idrisov   DenseSet<Value> deadVals;
745*aa3c31a8SRenat Idrisov 
746*aa3c31a8SRenat Idrisov   // Maintains a list of Ops, values, branches, etc., slated for cleanup at the
747*aa3c31a8SRenat Idrisov   // end of this pass.
748*aa3c31a8SRenat Idrisov   RDVFinalCleanupList finalCleanupList;
749*aa3c31a8SRenat Idrisov 
7500e98fb9fSSrishti Srivastava   module->walk([&](Operation *op) {
7510e98fb9fSSrishti Srivastava     if (auto funcOp = dyn_cast<FunctionOpInterface>(op)) {
752*aa3c31a8SRenat Idrisov       processFuncOp(funcOp, module, la, deadVals, finalCleanupList);
7530e98fb9fSSrishti Srivastava     } else if (auto regionBranchOp = dyn_cast<RegionBranchOpInterface>(op)) {
754*aa3c31a8SRenat Idrisov       processRegionBranchOp(regionBranchOp, la, deadVals, finalCleanupList);
7550629e9e3SRenat Idrisov     } else if (auto branchOp = dyn_cast<BranchOpInterface>(op)) {
756*aa3c31a8SRenat Idrisov       processBranchOp(branchOp, la, deadVals, finalCleanupList);
75765fd0551SDmitriy Smirnov     } else if (op->hasTrait<::mlir::OpTrait::IsTerminator>()) {
75865fd0551SDmitriy Smirnov       // Nothing to do here because this is a terminator op and it should be
75965fd0551SDmitriy Smirnov       // honored with respect to its parent
7600e98fb9fSSrishti Srivastava     } else if (isa<CallOpInterface>(op)) {
7610e98fb9fSSrishti Srivastava       // Nothing to do because this op is associated with a function op and gets
7620e98fb9fSSrishti Srivastava       // cleaned when the latter is cleaned.
7630e98fb9fSSrishti Srivastava     } else {
764*aa3c31a8SRenat Idrisov       processSimpleOp(op, la, deadVals, finalCleanupList);
7650e98fb9fSSrishti Srivastava     }
7660e98fb9fSSrishti Srivastava   });
767*aa3c31a8SRenat Idrisov 
768*aa3c31a8SRenat Idrisov   cleanUpDeadVals(finalCleanupList);
7690e98fb9fSSrishti Srivastava }
7700e98fb9fSSrishti Srivastava 
7710e98fb9fSSrishti Srivastava std::unique_ptr<Pass> mlir::createRemoveDeadValuesPass() {
7720e98fb9fSSrishti Srivastava   return std::make_unique<RemoveDeadValues>();
7730e98fb9fSSrishti Srivastava }
774