xref: /llvm-project/mlir/lib/Transforms/SymbolDCE.cpp (revision e8bcc37fff5bda7dd9326903a2c31e6703b4fe68)
1b276dec5SRiver Riddle //===- SymbolDCE.cpp - Pass to delete dead symbols ------------------------===//
2b276dec5SRiver Riddle //
3b276dec5SRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b276dec5SRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5b276dec5SRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b276dec5SRiver Riddle //
7b276dec5SRiver Riddle //===----------------------------------------------------------------------===//
8b276dec5SRiver Riddle //
9b276dec5SRiver Riddle // This file implements an algorithm for eliminating symbol operations that are
10b276dec5SRiver Riddle // known to be dead.
11b276dec5SRiver Riddle //
12b276dec5SRiver Riddle //===----------------------------------------------------------------------===//
13b276dec5SRiver Riddle 
14039b969bSMichele Scuttari #include "mlir/Transforms/Passes.h"
152be8af8fSMichele Scuttari 
1667d0d7acSMichele Scuttari #include "mlir/IR/SymbolTable.h"
1767d0d7acSMichele Scuttari 
1867d0d7acSMichele Scuttari namespace mlir {
1967d0d7acSMichele Scuttari #define GEN_PASS_DEF_SYMBOLDCE
2067d0d7acSMichele Scuttari #include "mlir/Transforms/Passes.h.inc"
2167d0d7acSMichele Scuttari } // namespace mlir
2267d0d7acSMichele Scuttari 
23b276dec5SRiver Riddle using namespace mlir;
24b276dec5SRiver Riddle 
25b276dec5SRiver Riddle namespace {
2667d0d7acSMichele Scuttari struct SymbolDCE : public impl::SymbolDCEBase<SymbolDCE> {
27b276dec5SRiver Riddle   void runOnOperation() override;
28b276dec5SRiver Riddle 
29b276dec5SRiver Riddle   /// Compute the liveness of the symbols within the given symbol table.
30b276dec5SRiver Riddle   /// `symbolTableIsHidden` is true if this symbol table is known to be
31b276dec5SRiver Riddle   /// unaccessible from operations in its parent regions.
32b276dec5SRiver Riddle   LogicalResult computeLiveness(Operation *symbolTableOp,
337bc7d0acSRiver Riddle                                 SymbolTableCollection &symbolTable,
34b276dec5SRiver Riddle                                 bool symbolTableIsHidden,
35b276dec5SRiver Riddle                                 DenseSet<Operation *> &liveSymbols);
36b276dec5SRiver Riddle };
37be0a7e9fSMehdi Amini } // namespace
38b276dec5SRiver Riddle 
runOnOperation()39039b969bSMichele Scuttari void SymbolDCE::runOnOperation() {
40b276dec5SRiver Riddle   Operation *symbolTableOp = getOperation();
41b276dec5SRiver Riddle 
42b276dec5SRiver Riddle   // SymbolDCE should only be run on operations that define a symbol table.
43b276dec5SRiver Riddle   if (!symbolTableOp->hasTrait<OpTrait::SymbolTable>()) {
44b276dec5SRiver Riddle     symbolTableOp->emitOpError()
45b276dec5SRiver Riddle         << " was scheduled to run under SymbolDCE, but does not define a "
46b276dec5SRiver Riddle            "symbol table";
47b276dec5SRiver Riddle     return signalPassFailure();
48b276dec5SRiver Riddle   }
49b276dec5SRiver Riddle 
50b276dec5SRiver Riddle   // A flag that signals if the top level symbol table is hidden, i.e. not
51b276dec5SRiver Riddle   // accessible from parent scopes.
52b276dec5SRiver Riddle   bool symbolTableIsHidden = true;
537c221a7dSRiver Riddle   SymbolOpInterface symbol = dyn_cast<SymbolOpInterface>(symbolTableOp);
547c221a7dSRiver Riddle   if (symbolTableOp->getParentOp() && symbol)
557c221a7dSRiver Riddle     symbolTableIsHidden = symbol.isPrivate();
56b276dec5SRiver Riddle 
57b276dec5SRiver Riddle   // Compute the set of live symbols within the symbol table.
58b276dec5SRiver Riddle   DenseSet<Operation *> liveSymbols;
597bc7d0acSRiver Riddle   SymbolTableCollection symbolTable;
607bc7d0acSRiver Riddle   if (failed(computeLiveness(symbolTableOp, symbolTable, symbolTableIsHidden,
617bc7d0acSRiver Riddle                              liveSymbols)))
62b276dec5SRiver Riddle     return signalPassFailure();
63b276dec5SRiver Riddle 
64b276dec5SRiver Riddle   // After computing the liveness, delete all of the symbols that were found to
65b276dec5SRiver Riddle   // be dead.
66b276dec5SRiver Riddle   symbolTableOp->walk([&](Operation *nestedSymbolTable) {
67b276dec5SRiver Riddle     if (!nestedSymbolTable->hasTrait<OpTrait::SymbolTable>())
68b276dec5SRiver Riddle       return;
69b276dec5SRiver Riddle     for (auto &block : nestedSymbolTable->getRegion(0)) {
70973ddb7dSMehdi Amini       for (Operation &op : llvm::make_early_inc_range(block)) {
711ebf1afbSNandor Licker         if (isa<SymbolOpInterface>(&op) && !liveSymbols.count(&op)) {
72b276dec5SRiver Riddle           op.erase();
731ebf1afbSNandor Licker           ++numDCE;
741ebf1afbSNandor Licker         }
75b276dec5SRiver Riddle       }
76b276dec5SRiver Riddle     }
77b276dec5SRiver Riddle   });
78b276dec5SRiver Riddle }
79b276dec5SRiver Riddle 
80b276dec5SRiver Riddle /// Compute the liveness of the symbols within the given symbol table.
81b276dec5SRiver Riddle /// `symbolTableIsHidden` is true if this symbol table is known to be
82b276dec5SRiver Riddle /// unaccessible from operations in its parent regions.
computeLiveness(Operation * symbolTableOp,SymbolTableCollection & symbolTable,bool symbolTableIsHidden,DenseSet<Operation * > & liveSymbols)83039b969bSMichele Scuttari LogicalResult SymbolDCE::computeLiveness(Operation *symbolTableOp,
84039b969bSMichele Scuttari                                          SymbolTableCollection &symbolTable,
85039b969bSMichele Scuttari                                          bool symbolTableIsHidden,
86039b969bSMichele Scuttari                                          DenseSet<Operation *> &liveSymbols) {
87b276dec5SRiver Riddle   // A worklist of live operations to propagate uses from.
88b276dec5SRiver Riddle   SmallVector<Operation *, 16> worklist;
89b276dec5SRiver Riddle 
90b276dec5SRiver Riddle   // Walk the symbols within the current symbol table, marking the symbols that
91b276dec5SRiver Riddle   // are known to be live.
92b276dec5SRiver Riddle   for (auto &block : symbolTableOp->getRegion(0)) {
937c221a7dSRiver Riddle     // Add all non-symbols or symbols that can't be discarded.
94973ddb7dSMehdi Amini     for (Operation &op : block) {
957c221a7dSRiver Riddle       SymbolOpInterface symbol = dyn_cast<SymbolOpInterface>(&op);
967c221a7dSRiver Riddle       if (!symbol) {
97b276dec5SRiver Riddle         worklist.push_back(&op);
98b276dec5SRiver Riddle         continue;
99b276dec5SRiver Riddle       }
1007c221a7dSRiver Riddle       bool isDiscardable = (symbolTableIsHidden || symbol.isPrivate()) &&
1017c221a7dSRiver Riddle                            symbol.canDiscardOnUseEmpty();
1027c221a7dSRiver Riddle       if (!isDiscardable && liveSymbols.insert(&op).second)
103b276dec5SRiver Riddle         worklist.push_back(&op);
104b276dec5SRiver Riddle     }
105b276dec5SRiver Riddle   }
106b276dec5SRiver Riddle 
107b276dec5SRiver Riddle   // Process the set of symbols that were known to be live, adding new symbols
108b276dec5SRiver Riddle   // that are referenced within.
109b276dec5SRiver Riddle   while (!worklist.empty()) {
110b276dec5SRiver Riddle     Operation *op = worklist.pop_back_val();
111b276dec5SRiver Riddle 
112b276dec5SRiver Riddle     // If this is a symbol table, recursively compute its liveness.
113b276dec5SRiver Riddle     if (op->hasTrait<OpTrait::SymbolTable>()) {
114b276dec5SRiver Riddle       // The internal symbol table is hidden if the parent is, if its not a
115b276dec5SRiver Riddle       // symbol, or if it is a private symbol.
1167c221a7dSRiver Riddle       SymbolOpInterface symbol = dyn_cast<SymbolOpInterface>(op);
1177c221a7dSRiver Riddle       bool symIsHidden = symbolTableIsHidden || !symbol || symbol.isPrivate();
1187bc7d0acSRiver Riddle       if (failed(computeLiveness(op, symbolTable, symIsHidden, liveSymbols)))
119b276dec5SRiver Riddle         return failure();
120b276dec5SRiver Riddle     }
121b276dec5SRiver Riddle 
122b276dec5SRiver Riddle     // Collect the uses held by this operation.
123*e8bcc37fSRamkumar Ramachandra     std::optional<SymbolTable::UseRange> uses = SymbolTable::getSymbolUses(op);
124b276dec5SRiver Riddle     if (!uses) {
125b276dec5SRiver Riddle       return op->emitError()
126b276dec5SRiver Riddle              << "operation contains potentially unknown symbol table, "
127b276dec5SRiver Riddle                 "meaning that we can't reliable compute symbol uses";
128b276dec5SRiver Riddle     }
129b276dec5SRiver Riddle 
130b276dec5SRiver Riddle     SmallVector<Operation *, 4> resolvedSymbols;
131b276dec5SRiver Riddle     for (const SymbolTable::SymbolUse &use : *uses) {
132b276dec5SRiver Riddle       // Lookup the symbols referenced by this use.
133b276dec5SRiver Riddle       resolvedSymbols.clear();
1347bc7d0acSRiver Riddle       if (failed(symbolTable.lookupSymbolIn(
1354ca5e95cSMogball               op->getParentOp(), use.getSymbolRef(), resolvedSymbols)))
1364ca5e95cSMogball         // Ignore references to unknown symbols.
1374ca5e95cSMogball         continue;
138b276dec5SRiver Riddle 
139b276dec5SRiver Riddle       // Mark each of the resolved symbols as live.
140b276dec5SRiver Riddle       for (Operation *resolvedSymbol : resolvedSymbols)
141b276dec5SRiver Riddle         if (liveSymbols.insert(resolvedSymbol).second)
142b276dec5SRiver Riddle           worklist.push_back(resolvedSymbol);
143b276dec5SRiver Riddle     }
144b276dec5SRiver Riddle   }
145b276dec5SRiver Riddle 
146b276dec5SRiver Riddle   return success();
147b276dec5SRiver Riddle }
148039b969bSMichele Scuttari 
createSymbolDCEPass()149039b969bSMichele Scuttari std::unique_ptr<Pass> mlir::createSymbolDCEPass() {
150039b969bSMichele Scuttari   return std::make_unique<SymbolDCE>();
151039b969bSMichele Scuttari }
152