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 ®ion : regionBranchOp->getRegions()) { 3780e98fb9fSSrishti Srivastava SmallVector<Value> arguments(region.front().getArguments()); 379*aa3c31a8SRenat Idrisov BitVector regionLiveArgs = markLives(arguments, nonLiveSet, la); 3800e98fb9fSSrishti Srivastava liveArgs[®ion] = 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 ®ion : 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(®ion)) { 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 ®ion : regionBranchOp->getRegions()) { 5020e98fb9fSSrishti Srivastava Operation *terminator = region.front().getTerminator(); 5030e98fb9fSSrishti Srivastava for (const RegionSuccessor &successor : getSuccessors(®ion)) { 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 ®ion : regionBranchOp->getRegions()) { 5500e98fb9fSSrishti Srivastava updateOperandsOrTerminatorOperandsToKeep( 5510e98fb9fSSrishti Srivastava terminatorOperandsToKeep[region.back().getTerminator()], 5520e98fb9fSSrishti Srivastava resultsToKeep, argsToKeep, ®ion); 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 ®ion : 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[®ion].flip(); 617*aa3c31a8SRenat Idrisov cl.blocks.push_back({®ion.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 ®ion : 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