1927b7074SRiver Riddle //===- SymbolTable.cpp - MLIR Symbol Table Class --------------------------===//
2927b7074SRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6927b7074SRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8927b7074SRiver Riddle 
9927b7074SRiver Riddle #include "mlir/IR/SymbolTable.h"
108b5a3e46SRahul Joshi #include "mlir/IR/Builders.h"
118b5a3e46SRahul Joshi #include "mlir/IR/OpImplementation.h"
126fca03f0SRiver Riddle #include "llvm/ADT/SetVector.h"
136fca03f0SRiver Riddle #include "llvm/ADT/SmallPtrSet.h"
14ee8e8b55SRiver Riddle #include "llvm/ADT/SmallString.h"
159b92e4fbSRiver Riddle #include "llvm/ADT/StringSwitch.h"
16927b7074SRiver Riddle 
17927b7074SRiver Riddle using namespace mlir;
18927b7074SRiver Riddle 
19b3a6ae83SRiver Riddle /// Return true if the given operation is unknown and may potentially define a
20b3a6ae83SRiver Riddle /// symbol table.
isPotentiallyUnknownSymbolTable(Operation * op)21b3a6ae83SRiver Riddle static bool isPotentiallyUnknownSymbolTable(Operation *op) {
2273547b08SRiver Riddle   return op->getNumRegions() == 1 && !op->getDialect();
23b3a6ae83SRiver Riddle }
24b3a6ae83SRiver Riddle 
2541d4aa7dSChris Lattner /// Returns the string name of the given symbol, or null if this is not a
266fca03f0SRiver Riddle /// symbol.
getNameIfSymbol(Operation * op)2741d4aa7dSChris Lattner static StringAttr getNameIfSymbol(Operation *op) {
2841d4aa7dSChris Lattner   return op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
296fca03f0SRiver Riddle }
getNameIfSymbol(Operation * op,StringAttr symbolAttrNameId)30195730a6SRiver Riddle static StringAttr getNameIfSymbol(Operation *op, StringAttr symbolAttrNameId) {
3141d4aa7dSChris Lattner   return op->getAttrOfType<StringAttr>(symbolAttrNameId);
32eda450bbSRiver Riddle }
336fca03f0SRiver Riddle 
346fca03f0SRiver Riddle /// Computes the nested symbol reference attribute for the symbol 'symbolName'
356fca03f0SRiver Riddle /// that are usable within the symbol table operations from 'symbol' as far up
366fca03f0SRiver Riddle /// to the given operation 'within', where 'within' is an ancestor of 'symbol'.
376fca03f0SRiver Riddle /// Returns success if all references up to 'within' could be computed.
386fca03f0SRiver Riddle static LogicalResult
collectValidReferencesFor(Operation * symbol,StringAttr symbolName,Operation * within,SmallVectorImpl<SymbolRefAttr> & results)3941d4aa7dSChris Lattner collectValidReferencesFor(Operation *symbol, StringAttr symbolName,
406fca03f0SRiver Riddle                           Operation *within,
416fca03f0SRiver Riddle                           SmallVectorImpl<SymbolRefAttr> &results) {
426fca03f0SRiver Riddle   assert(within->isAncestor(symbol) && "expected 'within' to be an ancestor");
436fca03f0SRiver Riddle   MLIRContext *ctx = symbol->getContext();
446fca03f0SRiver Riddle 
4541d4aa7dSChris Lattner   auto leafRef = FlatSymbolRefAttr::get(symbolName);
466fca03f0SRiver Riddle   results.push_back(leafRef);
476fca03f0SRiver Riddle 
486fca03f0SRiver Riddle   // Early exit for when 'within' is the parent of 'symbol'.
496fca03f0SRiver Riddle   Operation *symbolTableOp = symbol->getParentOp();
506fca03f0SRiver Riddle   if (within == symbolTableOp)
516fca03f0SRiver Riddle     return success();
526fca03f0SRiver Riddle 
536fca03f0SRiver Riddle   // Collect references until 'symbolTableOp' reaches 'within'.
546fca03f0SRiver Riddle   SmallVector<FlatSymbolRefAttr, 1> nestedRefs(1, leafRef);
55195730a6SRiver Riddle   StringAttr symbolNameId =
56195730a6SRiver Riddle       StringAttr::get(ctx, SymbolTable::getSymbolAttrName());
576fca03f0SRiver Riddle   do {
586fca03f0SRiver Riddle     // Each parent of 'symbol' should define a symbol table.
596fca03f0SRiver Riddle     if (!symbolTableOp->hasTrait<OpTrait::SymbolTable>())
606fca03f0SRiver Riddle       return failure();
616fca03f0SRiver Riddle     // Each parent of 'symbol' should also be a symbol.
6241d4aa7dSChris Lattner     StringAttr symbolTableName = getNameIfSymbol(symbolTableOp, symbolNameId);
636fca03f0SRiver Riddle     if (!symbolTableName)
646fca03f0SRiver Riddle       return failure();
6541d4aa7dSChris Lattner     results.push_back(SymbolRefAttr::get(symbolTableName, nestedRefs));
666fca03f0SRiver Riddle 
676fca03f0SRiver Riddle     symbolTableOp = symbolTableOp->getParentOp();
686fca03f0SRiver Riddle     if (symbolTableOp == within)
696fca03f0SRiver Riddle       break;
706fca03f0SRiver Riddle     nestedRefs.insert(nestedRefs.begin(),
7141d4aa7dSChris Lattner                       FlatSymbolRefAttr::get(symbolTableName));
726fca03f0SRiver Riddle   } while (true);
736fca03f0SRiver Riddle   return success();
746fca03f0SRiver Riddle }
756fca03f0SRiver Riddle 
7671eeb5ecSRiver Riddle /// Walk all of the operations within the given set of regions, without
7771eeb5ecSRiver Riddle /// traversing into any nested symbol tables. Stops walking if the result of the
7871eeb5ecSRiver Riddle /// callback is anything other than `WalkResult::advance`.
7971eeb5ecSRiver Riddle static Optional<WalkResult>
walkSymbolTable(MutableArrayRef<Region> regions,function_ref<Optional<WalkResult> (Operation *)> callback)8071eeb5ecSRiver Riddle walkSymbolTable(MutableArrayRef<Region> regions,
8171eeb5ecSRiver Riddle                 function_ref<Optional<WalkResult>(Operation *)> callback) {
8271eeb5ecSRiver Riddle   SmallVector<Region *, 1> worklist(llvm::make_pointer_range(regions));
8371eeb5ecSRiver Riddle   while (!worklist.empty()) {
8471eeb5ecSRiver Riddle     for (Operation &op : worklist.pop_back_val()->getOps()) {
8571eeb5ecSRiver Riddle       Optional<WalkResult> result = callback(&op);
8671eeb5ecSRiver Riddle       if (result != WalkResult::advance())
8771eeb5ecSRiver Riddle         return result;
8871eeb5ecSRiver Riddle 
8971eeb5ecSRiver Riddle       // If this op defines a new symbol table scope, we can't traverse. Any
9071eeb5ecSRiver Riddle       // symbol references nested within 'op' are different semantically.
9171eeb5ecSRiver Riddle       if (!op.hasTrait<OpTrait::SymbolTable>()) {
9271eeb5ecSRiver Riddle         for (Region &region : op.getRegions())
9371eeb5ecSRiver Riddle           worklist.push_back(&region);
9471eeb5ecSRiver Riddle       }
9571eeb5ecSRiver Riddle     }
9671eeb5ecSRiver Riddle   }
9771eeb5ecSRiver Riddle   return WalkResult::advance();
9871eeb5ecSRiver Riddle }
9971eeb5ecSRiver Riddle 
100*01eedbc7SRiver Riddle /// Walk all of the operations nested under, and including, the given operation,
101*01eedbc7SRiver Riddle /// without traversing into any nested symbol tables. Stops walking if the
102*01eedbc7SRiver Riddle /// result of the callback is anything other than `WalkResult::advance`.
103*01eedbc7SRiver Riddle static Optional<WalkResult>
walkSymbolTable(Operation * op,function_ref<Optional<WalkResult> (Operation *)> callback)104*01eedbc7SRiver Riddle walkSymbolTable(Operation *op,
105*01eedbc7SRiver Riddle                 function_ref<Optional<WalkResult>(Operation *)> callback) {
106*01eedbc7SRiver Riddle   Optional<WalkResult> result = callback(op);
107*01eedbc7SRiver Riddle   if (result != WalkResult::advance() || op->hasTrait<OpTrait::SymbolTable>())
108*01eedbc7SRiver Riddle     return result;
109*01eedbc7SRiver Riddle   return walkSymbolTable(op->getRegions(), callback);
110*01eedbc7SRiver Riddle }
111*01eedbc7SRiver Riddle 
112b3a6ae83SRiver Riddle //===----------------------------------------------------------------------===//
113b3a6ae83SRiver Riddle // SymbolTable
114b3a6ae83SRiver Riddle //===----------------------------------------------------------------------===//
115b3a6ae83SRiver Riddle 
116ee8e8b55SRiver Riddle /// Build a symbol table with the symbols within the given operation.
SymbolTable(Operation * symbolTableOp)117b8cd0c14STres Popp SymbolTable::SymbolTable(Operation *symbolTableOp)
118b8cd0c14STres Popp     : symbolTableOp(symbolTableOp) {
119b8cd0c14STres Popp   assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>() &&
120ee8e8b55SRiver Riddle          "expected operation to have SymbolTable trait");
121b8cd0c14STres Popp   assert(symbolTableOp->getNumRegions() == 1 &&
122ee8e8b55SRiver Riddle          "expected operation to have a single region");
123204c3b55SRiver Riddle   assert(llvm::hasSingleElement(symbolTableOp->getRegion(0)) &&
124b8cd0c14STres Popp          "expected operation to have a single block");
125ee8e8b55SRiver Riddle 
126195730a6SRiver Riddle   StringAttr symbolNameId = StringAttr::get(symbolTableOp->getContext(),
127195730a6SRiver Riddle                                             SymbolTable::getSymbolAttrName());
128b8cd0c14STres Popp   for (auto &op : symbolTableOp->getRegion(0).front()) {
12941d4aa7dSChris Lattner     StringAttr name = getNameIfSymbol(&op, symbolNameId);
1306fca03f0SRiver Riddle     if (!name)
131ee8e8b55SRiver Riddle       continue;
132ee8e8b55SRiver Riddle 
13341d4aa7dSChris Lattner     auto inserted = symbolTable.insert({name, &op});
1348c47e2edSRiver Riddle     (void)inserted;
1358c47e2edSRiver Riddle     assert(inserted.second &&
136ee8e8b55SRiver Riddle            "expected region to contain uniquely named symbol operations");
137ee8e8b55SRiver Riddle   }
1388c47e2edSRiver Riddle }
1398c47e2edSRiver Riddle 
140927b7074SRiver Riddle /// Look up a symbol with the specified name, returning null if no such name
141927b7074SRiver Riddle /// exists. Names never include the @ on them.
lookup(StringRef name) const142ee8e8b55SRiver Riddle Operation *SymbolTable::lookup(StringRef name) const {
14341d4aa7dSChris Lattner   return lookup(StringAttr::get(symbolTableOp->getContext(), name));
14441d4aa7dSChris Lattner }
lookup(StringAttr name) const14541d4aa7dSChris Lattner Operation *SymbolTable::lookup(StringAttr name) const {
146e7d594bbSRiver Riddle   return symbolTable.lookup(name);
147927b7074SRiver Riddle }
148927b7074SRiver Riddle 
149927b7074SRiver Riddle /// Erase the given symbol from the table.
erase(Operation * symbol)150ee8e8b55SRiver Riddle void SymbolTable::erase(Operation *symbol) {
15141d4aa7dSChris Lattner   StringAttr name = getNameIfSymbol(symbol);
1526fca03f0SRiver Riddle   assert(name && "expected valid 'name' attribute");
153b8cd0c14STres Popp   assert(symbol->getParentOp() == symbolTableOp &&
154b8cd0c14STres Popp          "expected this operation to be inside of the operation with this "
155b8cd0c14STres Popp          "SymbolTable");
156ee8e8b55SRiver Riddle 
15741d4aa7dSChris Lattner   auto it = symbolTable.find(name);
158b8cd0c14STres Popp   if (it != symbolTable.end() && it->second == symbol) {
159927b7074SRiver Riddle     symbolTable.erase(it);
160b8cd0c14STres Popp     symbol->erase();
161b8cd0c14STres Popp   }
162927b7074SRiver Riddle }
163927b7074SRiver Riddle 
164f43e67ccSTres Popp // TODO: Consider if this should be renamed to something like insertOrUpdate
165f43e67ccSTres Popp /// Insert a new symbol into the table and associated operation if not already
166feec2d90SAlex Zinenko /// there and rename it as necessary to avoid collisions. Return the name of
167feec2d90SAlex Zinenko /// the symbol after insertion as attribute.
insert(Operation * symbol,Block::iterator insertPt)168feec2d90SAlex Zinenko StringAttr SymbolTable::insert(Operation *symbol, Block::iterator insertPt) {
169f43e67ccSTres Popp   // The symbol cannot be the child of another op and must be the child of the
170f43e67ccSTres Popp   // symbolTableOp after this.
171f43e67ccSTres Popp   //
172f43e67ccSTres Popp   // TODO: consider if SymbolTable's constructor should behave the same.
173f43e67ccSTres Popp   if (!symbol->getParentOp()) {
174b8cd0c14STres Popp     auto &body = symbolTableOp->getRegion(0).front();
175973ddb7dSMehdi Amini     if (insertPt == Block::iterator()) {
176973ddb7dSMehdi Amini       insertPt = Block::iterator(body.end());
177973ddb7dSMehdi Amini     } else {
178973ddb7dSMehdi Amini       assert((insertPt == body.end() ||
179973ddb7dSMehdi Amini               insertPt->getParentOp() == symbolTableOp) &&
180b8cd0c14STres Popp              "expected insertPt to be in the associated module operation");
181973ddb7dSMehdi Amini     }
182973ddb7dSMehdi Amini     // Insert before the terminator, if any.
183973ddb7dSMehdi Amini     if (insertPt == Block::iterator(body.end()) && !body.empty() &&
184973ddb7dSMehdi Amini         std::prev(body.end())->hasTrait<OpTrait::IsTerminator>())
185973ddb7dSMehdi Amini       insertPt = std::prev(body.end());
186b8cd0c14STres Popp 
187b8cd0c14STres Popp     body.getOperations().insert(insertPt, symbol);
188f43e67ccSTres Popp   }
189f43e67ccSTres Popp   assert(symbol->getParentOp() == symbolTableOp &&
190f43e67ccSTres Popp          "symbol is already inserted in another op");
191b8cd0c14STres Popp 
192927b7074SRiver Riddle   // Add this symbol to the symbol table, uniquing the name if a conflict is
193927b7074SRiver Riddle   // detected.
19441d4aa7dSChris Lattner   StringAttr name = getSymbolName(symbol);
1956fca03f0SRiver Riddle   if (symbolTable.insert({name, symbol}).second)
196feec2d90SAlex Zinenko     return name;
197f43e67ccSTres Popp   // If the symbol was already in the table, also return.
198f43e67ccSTres Popp   if (symbolTable.lookup(name) == symbol)
199feec2d90SAlex Zinenko     return name;
200ee8e8b55SRiver Riddle   // If a conflict was detected, then the symbol will not have been added to
201927b7074SRiver Riddle   // the symbol table. Try suffixes until we get to a unique name that works.
20241d4aa7dSChris Lattner   SmallString<128> nameBuffer(name.getValue());
203927b7074SRiver Riddle   unsigned originalLength = nameBuffer.size();
204927b7074SRiver Riddle 
20541d4aa7dSChris Lattner   MLIRContext *context = symbol->getContext();
20641d4aa7dSChris Lattner 
207ee8e8b55SRiver Riddle   // Iteratively try suffixes until we find one that isn't used.
208927b7074SRiver Riddle   do {
209927b7074SRiver Riddle     nameBuffer.resize(originalLength);
210927b7074SRiver Riddle     nameBuffer += '_';
211927b7074SRiver Riddle     nameBuffer += std::to_string(uniquingCounter++);
21241d4aa7dSChris Lattner   } while (!symbolTable.insert({StringAttr::get(context, nameBuffer), symbol})
21341d4aa7dSChris Lattner                 .second);
2146fca03f0SRiver Riddle   setSymbolName(symbol, nameBuffer);
215feec2d90SAlex Zinenko   return getSymbolName(symbol);
2166fca03f0SRiver Riddle }
2176fca03f0SRiver Riddle 
2186fca03f0SRiver Riddle /// Returns the name of the given symbol operation.
getSymbolName(Operation * symbol)21941d4aa7dSChris Lattner StringAttr SymbolTable::getSymbolName(Operation *symbol) {
22041d4aa7dSChris Lattner   StringAttr name = getNameIfSymbol(symbol);
2216fca03f0SRiver Riddle   assert(name && "expected valid symbol name");
22241d4aa7dSChris Lattner   return name;
2236fca03f0SRiver Riddle }
22441d4aa7dSChris Lattner 
2256fca03f0SRiver Riddle /// Sets the name of the given symbol operation.
setSymbolName(Operation * symbol,StringAttr name)22641d4aa7dSChris Lattner void SymbolTable::setSymbolName(Operation *symbol, StringAttr name) {
22741d4aa7dSChris Lattner   symbol->setAttr(getSymbolAttrName(), name);
228ee8e8b55SRiver Riddle }
229ee8e8b55SRiver Riddle 
2309b92e4fbSRiver Riddle /// Returns the visibility of the given symbol operation.
getSymbolVisibility(Operation * symbol)2319b92e4fbSRiver Riddle SymbolTable::Visibility SymbolTable::getSymbolVisibility(Operation *symbol) {
2329b92e4fbSRiver Riddle   // If the attribute doesn't exist, assume public.
2339b92e4fbSRiver Riddle   StringAttr vis = symbol->getAttrOfType<StringAttr>(getVisibilityAttrName());
2349b92e4fbSRiver Riddle   if (!vis)
2359b92e4fbSRiver Riddle     return Visibility::Public;
2369b92e4fbSRiver Riddle 
2379b92e4fbSRiver Riddle   // Otherwise, switch on the string value.
238cc83dc19SChristian Sigg   return StringSwitch<Visibility>(vis.getValue())
2399b92e4fbSRiver Riddle       .Case("private", Visibility::Private)
2409b92e4fbSRiver Riddle       .Case("nested", Visibility::Nested)
2419b92e4fbSRiver Riddle       .Case("public", Visibility::Public);
2429b92e4fbSRiver Riddle }
2439b92e4fbSRiver Riddle /// Sets the visibility of the given symbol operation.
setSymbolVisibility(Operation * symbol,Visibility vis)2449b92e4fbSRiver Riddle void SymbolTable::setSymbolVisibility(Operation *symbol, Visibility vis) {
2459b92e4fbSRiver Riddle   MLIRContext *ctx = symbol->getContext();
2469b92e4fbSRiver Riddle 
2479b92e4fbSRiver Riddle   // If the visibility is public, just drop the attribute as this is the
2489b92e4fbSRiver Riddle   // default.
2499b92e4fbSRiver Riddle   if (vis == Visibility::Public) {
250195730a6SRiver Riddle     symbol->removeAttr(StringAttr::get(ctx, getVisibilityAttrName()));
2519b92e4fbSRiver Riddle     return;
2529b92e4fbSRiver Riddle   }
2539b92e4fbSRiver Riddle 
2549b92e4fbSRiver Riddle   // Otherwise, update the attribute.
2559b92e4fbSRiver Riddle   assert((vis == Visibility::Private || vis == Visibility::Nested) &&
2569b92e4fbSRiver Riddle          "unknown symbol visibility kind");
2579b92e4fbSRiver Riddle 
2589b92e4fbSRiver Riddle   StringRef visName = vis == Visibility::Private ? "private" : "nested";
259c2c83e97STres Popp   symbol->setAttr(getVisibilityAttrName(), StringAttr::get(ctx, visName));
2609b92e4fbSRiver Riddle }
2619b92e4fbSRiver Riddle 
26229e411b3SLei Zhang /// Returns the nearest symbol table from a given operation `from`. Returns
26329e411b3SLei Zhang /// nullptr if no valid parent symbol table could be found.
getNearestSymbolTable(Operation * from)26429e411b3SLei Zhang Operation *SymbolTable::getNearestSymbolTable(Operation *from) {
26529e411b3SLei Zhang   assert(from && "expected valid operation");
26629e411b3SLei Zhang   if (isPotentiallyUnknownSymbolTable(from))
26729e411b3SLei Zhang     return nullptr;
26829e411b3SLei Zhang 
26929e411b3SLei Zhang   while (!from->hasTrait<OpTrait::SymbolTable>()) {
27029e411b3SLei Zhang     from = from->getParentOp();
27129e411b3SLei Zhang 
27229e411b3SLei Zhang     // Check that this is a valid op and isn't an unknown symbol table.
27329e411b3SLei Zhang     if (!from || isPotentiallyUnknownSymbolTable(from))
27429e411b3SLei Zhang       return nullptr;
27529e411b3SLei Zhang   }
27629e411b3SLei Zhang   return from;
27729e411b3SLei Zhang }
27829e411b3SLei Zhang 
279a90151d6SRiver Riddle /// Walks all symbol table operations nested within, and including, `op`. For
280a90151d6SRiver Riddle /// each symbol table operation, the provided callback is invoked with the op
281a90151d6SRiver Riddle /// and a boolean signifying if the symbols within that symbol table can be
282a90151d6SRiver Riddle /// treated as if all uses are visible. `allSymUsesVisible` identifies whether
283a90151d6SRiver Riddle /// all of the symbol uses of symbols within `op` are visible.
walkSymbolTables(Operation * op,bool allSymUsesVisible,function_ref<void (Operation *,bool)> callback)284a90151d6SRiver Riddle void SymbolTable::walkSymbolTables(
285a90151d6SRiver Riddle     Operation *op, bool allSymUsesVisible,
286a90151d6SRiver Riddle     function_ref<void(Operation *, bool)> callback) {
287a90151d6SRiver Riddle   bool isSymbolTable = op->hasTrait<OpTrait::SymbolTable>();
288a90151d6SRiver Riddle   if (isSymbolTable) {
289a90151d6SRiver Riddle     SymbolOpInterface symbol = dyn_cast<SymbolOpInterface>(op);
290a90151d6SRiver Riddle     allSymUsesVisible |= !symbol || symbol.isPrivate();
291a90151d6SRiver Riddle   } else {
292a90151d6SRiver Riddle     // Otherwise if 'op' is not a symbol table, any nested symbols are
293a90151d6SRiver Riddle     // guaranteed to be hidden.
294a90151d6SRiver Riddle     allSymUsesVisible = true;
295a90151d6SRiver Riddle   }
296a90151d6SRiver Riddle 
297a90151d6SRiver Riddle   for (Region &region : op->getRegions())
298a90151d6SRiver Riddle     for (Block &block : region)
299a90151d6SRiver Riddle       for (Operation &nestedOp : block)
300a90151d6SRiver Riddle         walkSymbolTables(&nestedOp, allSymUsesVisible, callback);
301a90151d6SRiver Riddle 
302a90151d6SRiver Riddle   // If 'op' had the symbol table trait, visit it after any nested symbol
303a90151d6SRiver Riddle   // tables.
304a90151d6SRiver Riddle   if (isSymbolTable)
305a90151d6SRiver Riddle     callback(op, allSymUsesVisible);
306a90151d6SRiver Riddle }
307a90151d6SRiver Riddle 
3088cb405a8SRiver Riddle /// Returns the operation registered with the given symbol name with the
3098cb405a8SRiver Riddle /// regions of 'symbolTableOp'. 'symbolTableOp' is required to be an operation
3108cb405a8SRiver Riddle /// with the 'OpTrait::SymbolTable' trait. Returns nullptr if no valid symbol
3118cb405a8SRiver Riddle /// was found.
lookupSymbolIn(Operation * symbolTableOp,StringAttr symbol)3128cb405a8SRiver Riddle Operation *SymbolTable::lookupSymbolIn(Operation *symbolTableOp,
31341d4aa7dSChris Lattner                                        StringAttr symbol) {
3148cb405a8SRiver Riddle   assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>());
315973ddb7dSMehdi Amini   Region &region = symbolTableOp->getRegion(0);
316973ddb7dSMehdi Amini   if (region.empty())
317973ddb7dSMehdi Amini     return nullptr;
3188cb405a8SRiver Riddle 
3198cb405a8SRiver Riddle   // Look for a symbol with the given name.
320195730a6SRiver Riddle   StringAttr symbolNameId = StringAttr::get(symbolTableOp->getContext(),
321195730a6SRiver Riddle                                             SymbolTable::getSymbolAttrName());
322973ddb7dSMehdi Amini   for (auto &op : region.front())
323eda450bbSRiver Riddle     if (getNameIfSymbol(&op, symbolNameId) == symbol)
3248cb405a8SRiver Riddle       return &op;
3258cb405a8SRiver Riddle   return nullptr;
3268cb405a8SRiver Riddle }
lookupSymbolIn(Operation * symbolTableOp,SymbolRefAttr symbol)3276fca03f0SRiver Riddle Operation *SymbolTable::lookupSymbolIn(Operation *symbolTableOp,
3286fca03f0SRiver Riddle                                        SymbolRefAttr symbol) {
329b276dec5SRiver Riddle   SmallVector<Operation *, 4> resolvedSymbols;
330b276dec5SRiver Riddle   if (failed(lookupSymbolIn(symbolTableOp, symbol, resolvedSymbols)))
331b276dec5SRiver Riddle     return nullptr;
332b276dec5SRiver Riddle   return resolvedSymbols.back();
333b276dec5SRiver Riddle }
334b276dec5SRiver Riddle 
3357bc7d0acSRiver Riddle /// Internal implementation of `lookupSymbolIn` that allows for specialized
3367bc7d0acSRiver Riddle /// implementations of the lookup function.
lookupSymbolInImpl(Operation * symbolTableOp,SymbolRefAttr symbol,SmallVectorImpl<Operation * > & symbols,function_ref<Operation * (Operation *,StringAttr)> lookupSymbolFn)3377bc7d0acSRiver Riddle static LogicalResult lookupSymbolInImpl(
3387bc7d0acSRiver Riddle     Operation *symbolTableOp, SymbolRefAttr symbol,
3397bc7d0acSRiver Riddle     SmallVectorImpl<Operation *> &symbols,
34041d4aa7dSChris Lattner     function_ref<Operation *(Operation *, StringAttr)> lookupSymbolFn) {
3416fca03f0SRiver Riddle   assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>());
3426fca03f0SRiver Riddle 
3436fca03f0SRiver Riddle   // Lookup the root reference for this symbol.
3447bc7d0acSRiver Riddle   symbolTableOp = lookupSymbolFn(symbolTableOp, symbol.getRootReference());
3456fca03f0SRiver Riddle   if (!symbolTableOp)
346b276dec5SRiver Riddle     return failure();
347b276dec5SRiver Riddle   symbols.push_back(symbolTableOp);
3486fca03f0SRiver Riddle 
3496fca03f0SRiver Riddle   // If there are no nested references, just return the root symbol directly.
3506fca03f0SRiver Riddle   ArrayRef<FlatSymbolRefAttr> nestedRefs = symbol.getNestedReferences();
3516fca03f0SRiver Riddle   if (nestedRefs.empty())
352b276dec5SRiver Riddle     return success();
3536fca03f0SRiver Riddle 
3546fca03f0SRiver Riddle   // Verify that the root is also a symbol table.
3556fca03f0SRiver Riddle   if (!symbolTableOp->hasTrait<OpTrait::SymbolTable>())
356b276dec5SRiver Riddle     return failure();
3576fca03f0SRiver Riddle 
3586fca03f0SRiver Riddle   // Otherwise, lookup each of the nested non-leaf references and ensure that
3596fca03f0SRiver Riddle   // each corresponds to a valid symbol table.
3606fca03f0SRiver Riddle   for (FlatSymbolRefAttr ref : nestedRefs.drop_back()) {
36141d4aa7dSChris Lattner     symbolTableOp = lookupSymbolFn(symbolTableOp, ref.getAttr());
3626fca03f0SRiver Riddle     if (!symbolTableOp || !symbolTableOp->hasTrait<OpTrait::SymbolTable>())
363b276dec5SRiver Riddle       return failure();
364b276dec5SRiver Riddle     symbols.push_back(symbolTableOp);
3656fca03f0SRiver Riddle   }
3667bc7d0acSRiver Riddle   symbols.push_back(lookupSymbolFn(symbolTableOp, symbol.getLeafReference()));
367b276dec5SRiver Riddle   return success(symbols.back());
3686fca03f0SRiver Riddle }
3698cb405a8SRiver Riddle 
3707bc7d0acSRiver Riddle LogicalResult
lookupSymbolIn(Operation * symbolTableOp,SymbolRefAttr symbol,SmallVectorImpl<Operation * > & symbols)3717bc7d0acSRiver Riddle SymbolTable::lookupSymbolIn(Operation *symbolTableOp, SymbolRefAttr symbol,
3727bc7d0acSRiver Riddle                             SmallVectorImpl<Operation *> &symbols) {
37341d4aa7dSChris Lattner   auto lookupFn = [](Operation *symbolTableOp, StringAttr symbol) {
3747bc7d0acSRiver Riddle     return lookupSymbolIn(symbolTableOp, symbol);
3757bc7d0acSRiver Riddle   };
3767bc7d0acSRiver Riddle   return lookupSymbolInImpl(symbolTableOp, symbol, symbols, lookupFn);
3777bc7d0acSRiver Riddle }
3787bc7d0acSRiver Riddle 
3798cb405a8SRiver Riddle /// Returns the operation registered with the given symbol name within the
3808cb405a8SRiver Riddle /// closes parent operation with the 'OpTrait::SymbolTable' trait. Returns
3818cb405a8SRiver Riddle /// nullptr if no valid symbol was found.
lookupNearestSymbolFrom(Operation * from,StringAttr symbol)3828cb405a8SRiver Riddle Operation *SymbolTable::lookupNearestSymbolFrom(Operation *from,
38341d4aa7dSChris Lattner                                                 StringAttr symbol) {
3846fca03f0SRiver Riddle   Operation *symbolTableOp = getNearestSymbolTable(from);
3856fca03f0SRiver Riddle   return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
386b3a6ae83SRiver Riddle }
lookupNearestSymbolFrom(Operation * from,SymbolRefAttr symbol)3876fca03f0SRiver Riddle Operation *SymbolTable::lookupNearestSymbolFrom(Operation *from,
3886fca03f0SRiver Riddle                                                 SymbolRefAttr symbol) {
3896fca03f0SRiver Riddle   Operation *symbolTableOp = getNearestSymbolTable(from);
3906fca03f0SRiver Riddle   return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
3918cb405a8SRiver Riddle }
3928cb405a8SRiver Riddle 
operator <<(raw_ostream & os,SymbolTable::Visibility visibility)393f492c359SRiver Riddle raw_ostream &mlir::operator<<(raw_ostream &os,
394f492c359SRiver Riddle                               SymbolTable::Visibility visibility) {
395f492c359SRiver Riddle   switch (visibility) {
396f492c359SRiver Riddle   case SymbolTable::Visibility::Public:
397f492c359SRiver Riddle     return os << "public";
398f492c359SRiver Riddle   case SymbolTable::Visibility::Private:
399f492c359SRiver Riddle     return os << "private";
400f492c359SRiver Riddle   case SymbolTable::Visibility::Nested:
401f492c359SRiver Riddle     return os << "nested";
402f492c359SRiver Riddle   }
4032c811548SMehdi Amini   llvm_unreachable("Unexpected visibility");
404f492c359SRiver Riddle }
405f492c359SRiver Riddle 
406ee8e8b55SRiver Riddle //===----------------------------------------------------------------------===//
407ee8e8b55SRiver Riddle // SymbolTable Trait Types
408ee8e8b55SRiver Riddle //===----------------------------------------------------------------------===//
409ee8e8b55SRiver Riddle 
verifySymbolTable(Operation * op)4107c221a7dSRiver Riddle LogicalResult detail::verifySymbolTable(Operation *op) {
411ee8e8b55SRiver Riddle   if (op->getNumRegions() != 1)
412ee8e8b55SRiver Riddle     return op->emitOpError()
413ee8e8b55SRiver Riddle            << "Operations with a 'SymbolTable' must have exactly one region";
414204c3b55SRiver Riddle   if (!llvm::hasSingleElement(op->getRegion(0)))
415b8cd0c14STres Popp     return op->emitOpError()
416b8cd0c14STres Popp            << "Operations with a 'SymbolTable' must have exactly one block";
417ee8e8b55SRiver Riddle 
4188bfedb3cSKazuaki Ishizaki   // Check that all symbols are uniquely named within child regions.
4196fca03f0SRiver Riddle   DenseMap<Attribute, Location> nameToOrigLoc;
420ee8e8b55SRiver Riddle   for (auto &block : op->getRegion(0)) {
421ee8e8b55SRiver Riddle     for (auto &op : block) {
422ee8e8b55SRiver Riddle       // Check for a symbol name attribute.
423ee8e8b55SRiver Riddle       auto nameAttr =
424ee8e8b55SRiver Riddle           op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
425ee8e8b55SRiver Riddle       if (!nameAttr)
426ee8e8b55SRiver Riddle         continue;
427ee8e8b55SRiver Riddle 
428ee8e8b55SRiver Riddle       // Try to insert this symbol into the table.
4296fca03f0SRiver Riddle       auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
430ee8e8b55SRiver Riddle       if (!it.second)
431ee8e8b55SRiver Riddle         return op.emitError()
432ee8e8b55SRiver Riddle             .append("redefinition of symbol named '", nameAttr.getValue(), "'")
433ee8e8b55SRiver Riddle             .attachNote(it.first->second)
434ee8e8b55SRiver Riddle             .append("see existing symbol definition here");
435ee8e8b55SRiver Riddle     }
436ee8e8b55SRiver Riddle   }
43771eeb5ecSRiver Riddle 
43871eeb5ecSRiver Riddle   // Verify any nested symbol user operations.
43971eeb5ecSRiver Riddle   SymbolTableCollection symbolTable;
44071eeb5ecSRiver Riddle   auto verifySymbolUserFn = [&](Operation *op) -> Optional<WalkResult> {
44171eeb5ecSRiver Riddle     if (SymbolUserOpInterface user = dyn_cast<SymbolUserOpInterface>(op))
44271eeb5ecSRiver Riddle       return WalkResult(user.verifySymbolUses(symbolTable));
44371eeb5ecSRiver Riddle     return WalkResult::advance();
44471eeb5ecSRiver Riddle   };
44571eeb5ecSRiver Riddle 
44671eeb5ecSRiver Riddle   Optional<WalkResult> result =
44771eeb5ecSRiver Riddle       walkSymbolTable(op->getRegions(), verifySymbolUserFn);
44871eeb5ecSRiver Riddle   return success(result && !result->wasInterrupted());
449927b7074SRiver Riddle }
450ac91e673SRiver Riddle 
verifySymbol(Operation * op)4517c221a7dSRiver Riddle LogicalResult detail::verifySymbol(Operation *op) {
4529b92e4fbSRiver Riddle   // Verify the name attribute.
4539ac459e8SRiver Riddle   if (!op->getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName()))
4549ac459e8SRiver Riddle     return op->emitOpError() << "requires string attribute '"
4559ac459e8SRiver Riddle                              << mlir::SymbolTable::getSymbolAttrName() << "'";
4569b92e4fbSRiver Riddle 
4579b92e4fbSRiver Riddle   // Verify the visibility attribute.
4589b92e4fbSRiver Riddle   if (Attribute vis = op->getAttr(mlir::SymbolTable::getVisibilityAttrName())) {
4599b92e4fbSRiver Riddle     StringAttr visStrAttr = vis.dyn_cast<StringAttr>();
4609b92e4fbSRiver Riddle     if (!visStrAttr)
4619b92e4fbSRiver Riddle       return op->emitOpError() << "requires visibility attribute '"
4629b92e4fbSRiver Riddle                                << mlir::SymbolTable::getVisibilityAttrName()
4639b92e4fbSRiver Riddle                                << "' to be a string attribute, but got " << vis;
4649b92e4fbSRiver Riddle 
4659b92e4fbSRiver Riddle     if (!llvm::is_contained(ArrayRef<StringRef>{"public", "private", "nested"},
4669b92e4fbSRiver Riddle                             visStrAttr.getValue()))
4679b92e4fbSRiver Riddle       return op->emitOpError()
4689b92e4fbSRiver Riddle              << "visibility expected to be one of [\"public\", \"private\", "
4699b92e4fbSRiver Riddle                 "\"nested\"], but got "
4709b92e4fbSRiver Riddle              << visStrAttr;
4719b92e4fbSRiver Riddle   }
4729ac459e8SRiver Riddle   return success();
4739ac459e8SRiver Riddle }
4749ac459e8SRiver Riddle 
475ac91e673SRiver Riddle //===----------------------------------------------------------------------===//
476ef43b565SRiver Riddle // Symbol Use Lists
477ac91e673SRiver Riddle //===----------------------------------------------------------------------===//
478ac91e673SRiver Riddle 
479ac91e673SRiver Riddle /// Walk all of the symbol references within the given operation, invoking the
480*01eedbc7SRiver Riddle /// provided callback for each found use. The callbacks takes the use of the
481*01eedbc7SRiver Riddle /// symbol.
482*01eedbc7SRiver Riddle static WalkResult
walkSymbolRefs(Operation * op,function_ref<WalkResult (SymbolTable::SymbolUse)> callback)483*01eedbc7SRiver Riddle walkSymbolRefs(Operation *op,
484*01eedbc7SRiver Riddle                function_ref<WalkResult(SymbolTable::SymbolUse)> callback) {
485ac91e673SRiver Riddle   // Check to see if the operation has any attributes.
486fc5cf50eSRiver Riddle   DictionaryAttr attrDict = op->getAttrDictionary();
487fc5cf50eSRiver Riddle   if (attrDict.empty())
488ac91e673SRiver Riddle     return WalkResult::advance();
489ac91e673SRiver Riddle 
490ac91e673SRiver Riddle   // A worklist of a container attribute and the current index into the held
491ac91e673SRiver Riddle   // attribute list.
49210a80c44SMarkus Böck   struct WorklistItem {
49310a80c44SMarkus Böck     SubElementAttrInterface container;
49410a80c44SMarkus Böck     SmallVector<Attribute> immediateSubElements;
49510a80c44SMarkus Böck 
49610a80c44SMarkus Böck     explicit WorklistItem(SubElementAttrInterface container) {
49710a80c44SMarkus Böck       SmallVector<Attribute> subElements;
49810a80c44SMarkus Böck       container.walkImmediateSubElements(
49910a80c44SMarkus Böck           [&](Attribute attr) { subElements.push_back(attr); }, [](Type) {});
50010a80c44SMarkus Böck       immediateSubElements = std::move(subElements);
50110a80c44SMarkus Böck     }
50210a80c44SMarkus Böck   };
50310a80c44SMarkus Böck 
50410a80c44SMarkus Böck   SmallVector<WorklistItem, 1> attrWorklist(1, WorklistItem(attrDict));
505ef43b565SRiver Riddle   SmallVector<int, 1> curAccessChain(1, /*Value=*/-1);
5065f6bdd14SRiver Riddle 
5075f6bdd14SRiver Riddle   // Process the symbol references within the given nested attribute range.
50810a80c44SMarkus Böck   auto processAttrs = [&](int &index,
50910a80c44SMarkus Böck                           WorklistItem &worklistItem) -> WalkResult {
51010a80c44SMarkus Böck     for (Attribute attr :
51110a80c44SMarkus Böck          llvm::drop_begin(worklistItem.immediateSubElements, index)) {
512*01eedbc7SRiver Riddle       // Invoke the provided callback if we find a symbol use and check for a
513*01eedbc7SRiver Riddle       // requested interrupt.
514*01eedbc7SRiver Riddle       if (auto symbolRef = attr.dyn_cast<SymbolRefAttr>()) {
515*01eedbc7SRiver Riddle         if (callback({op, symbolRef}).wasInterrupted())
516*01eedbc7SRiver Riddle           return WalkResult::interrupt();
517*01eedbc7SRiver Riddle 
5185f6bdd14SRiver Riddle         /// Check for a nested container attribute, these will also need to be
5195f6bdd14SRiver Riddle         /// walked.
520*01eedbc7SRiver Riddle       } else if (auto interface = attr.dyn_cast<SubElementAttrInterface>()) {
52110a80c44SMarkus Böck         attrWorklist.emplace_back(interface);
522ef43b565SRiver Riddle         curAccessChain.push_back(-1);
5235f6bdd14SRiver Riddle         return WalkResult::advance();
5245f6bdd14SRiver Riddle       }
525ef43b565SRiver Riddle       // Make sure to keep the index counter in sync.
526ef43b565SRiver Riddle       ++index;
5275f6bdd14SRiver Riddle     }
5285f6bdd14SRiver Riddle 
5295f6bdd14SRiver Riddle     // Pop this container attribute from the worklist.
530ef43b565SRiver Riddle     attrWorklist.pop_back();
531ef43b565SRiver Riddle     curAccessChain.pop_back();
5325f6bdd14SRiver Riddle     return WalkResult::advance();
5335f6bdd14SRiver Riddle   };
5345f6bdd14SRiver Riddle 
5355f6bdd14SRiver Riddle   WalkResult result = WalkResult::advance();
5365f6bdd14SRiver Riddle   do {
53710a80c44SMarkus Böck     WorklistItem &item = attrWorklist.back();
538ef43b565SRiver Riddle     int &index = curAccessChain.back();
539ef43b565SRiver Riddle     ++index;
540ac91e673SRiver Riddle 
5415f6bdd14SRiver Riddle     // Process the given attribute, which is guaranteed to be a container.
54210a80c44SMarkus Böck     result = processAttrs(index, item);
543ef43b565SRiver Riddle   } while (!attrWorklist.empty() && !result.wasInterrupted());
5445f6bdd14SRiver Riddle   return result;
545ac91e673SRiver Riddle }
546ac91e673SRiver Riddle 
547ac91e673SRiver Riddle /// Walk all of the uses, for any symbol, that are nested within the given
548ab9e5598SRiver Riddle /// regions, invoking the provided callback for each. This does not traverse
549ab9e5598SRiver Riddle /// into any nested symbol tables.
550*01eedbc7SRiver Riddle static Optional<WalkResult>
walkSymbolUses(MutableArrayRef<Region> regions,function_ref<WalkResult (SymbolTable::SymbolUse)> callback)551*01eedbc7SRiver Riddle walkSymbolUses(MutableArrayRef<Region> regions,
552*01eedbc7SRiver Riddle                function_ref<WalkResult(SymbolTable::SymbolUse)> callback) {
55371eeb5ecSRiver Riddle   return walkSymbolTable(regions, [&](Operation *op) -> Optional<WalkResult> {
554ab9e5598SRiver Riddle     // Check that this isn't a potentially unknown symbol table.
55571eeb5ecSRiver Riddle     if (isPotentiallyUnknownSymbolTable(op))
556b3a6ae83SRiver Riddle       return llvm::None;
557b3a6ae83SRiver Riddle 
55871eeb5ecSRiver Riddle     return walkSymbolRefs(op, callback);
55971eeb5ecSRiver Riddle   });
560ac91e673SRiver Riddle }
561ab9e5598SRiver Riddle /// Walk all of the uses, for any symbol, that are nested within the given
5625aacce3dSKazuaki Ishizaki /// operation 'from', invoking the provided callback for each. This does not
563ab9e5598SRiver Riddle /// traverse into any nested symbol tables.
564*01eedbc7SRiver Riddle static Optional<WalkResult>
walkSymbolUses(Operation * from,function_ref<WalkResult (SymbolTable::SymbolUse)> callback)565*01eedbc7SRiver Riddle walkSymbolUses(Operation *from,
566*01eedbc7SRiver Riddle                function_ref<WalkResult(SymbolTable::SymbolUse)> callback) {
567ab9e5598SRiver Riddle   // If this operation has regions, and it, as well as its dialect, isn't
568ab9e5598SRiver Riddle   // registered then conservatively fail. The operation may define a
569ab9e5598SRiver Riddle   // symbol table, so we can't opaquely know if we should traverse to find
570ab9e5598SRiver Riddle   // nested uses.
571ab9e5598SRiver Riddle   if (isPotentiallyUnknownSymbolTable(from))
572ab9e5598SRiver Riddle     return llvm::None;
573ac91e673SRiver Riddle 
574ab9e5598SRiver Riddle   // Walk the uses on this operation.
575ab9e5598SRiver Riddle   if (walkSymbolRefs(from, callback).wasInterrupted())
576ab9e5598SRiver Riddle     return WalkResult::interrupt();
577ab9e5598SRiver Riddle 
578ab9e5598SRiver Riddle   // Only recurse if this operation is not a symbol table. A symbol table
579ab9e5598SRiver Riddle   // defines a new scope, so we can't walk the attributes from within the symbol
580ab9e5598SRiver Riddle   // table op.
581ab9e5598SRiver Riddle   if (!from->hasTrait<OpTrait::SymbolTable>())
582ab9e5598SRiver Riddle     return walkSymbolUses(from->getRegions(), callback);
583ab9e5598SRiver Riddle   return WalkResult::advance();
584ab9e5598SRiver Riddle }
585ab9e5598SRiver Riddle 
586ab9e5598SRiver Riddle namespace {
587ab9e5598SRiver Riddle /// This class represents a single symbol scope. A symbol scope represents the
588ab9e5598SRiver Riddle /// set of operations nested within a symbol table that may reference symbols
589ab9e5598SRiver Riddle /// within that table. A symbol scope does not contain the symbol table
590ab9e5598SRiver Riddle /// operation itself, just its contained operations. A scope ends at leaf
591ab9e5598SRiver Riddle /// operations or another symbol table operation.
592ab9e5598SRiver Riddle struct SymbolScope {
593ab9e5598SRiver Riddle   /// Walk the symbol uses within this scope, invoking the given callback.
594ab9e5598SRiver Riddle   /// This variant is used when the callback type matches that expected by
595ab9e5598SRiver Riddle   /// 'walkSymbolUses'.
596ab9e5598SRiver Riddle   template <typename CallbackT,
597ab9e5598SRiver Riddle             typename std::enable_if_t<!std::is_same<
5988cbe371cSRiver Riddle                 typename llvm::function_traits<CallbackT>::result_t,
5998cbe371cSRiver Riddle                 void>::value> * = nullptr>
walk__anonb7b65d210711::SymbolScope600ab9e5598SRiver Riddle   Optional<WalkResult> walk(CallbackT cback) {
601ab9e5598SRiver Riddle     if (Region *region = limit.dyn_cast<Region *>())
602ab9e5598SRiver Riddle       return walkSymbolUses(*region, cback);
603ab9e5598SRiver Riddle     return walkSymbolUses(limit.get<Operation *>(), cback);
604ab9e5598SRiver Riddle   }
605ab9e5598SRiver Riddle   /// This variant is used when the callback type matches a stripped down type:
606ab9e5598SRiver Riddle   /// void(SymbolTable::SymbolUse use)
607ab9e5598SRiver Riddle   template <typename CallbackT,
608ab9e5598SRiver Riddle             typename std::enable_if_t<std::is_same<
6098cbe371cSRiver Riddle                 typename llvm::function_traits<CallbackT>::result_t,
6108cbe371cSRiver Riddle                 void>::value> * = nullptr>
walk__anonb7b65d210711::SymbolScope611ab9e5598SRiver Riddle   Optional<WalkResult> walk(CallbackT cback) {
612*01eedbc7SRiver Riddle     return walk([=](SymbolTable::SymbolUse use) {
613ab9e5598SRiver Riddle       return cback(use), WalkResult::advance();
614ab9e5598SRiver Riddle     });
615ab9e5598SRiver Riddle   }
616ab9e5598SRiver Riddle 
617*01eedbc7SRiver Riddle   /// Walk all of the operations nested under the current scope without
618*01eedbc7SRiver Riddle   /// traversing into any nested symbol tables.
619*01eedbc7SRiver Riddle   template <typename CallbackT>
walkSymbolTable__anonb7b65d210711::SymbolScope620*01eedbc7SRiver Riddle   Optional<WalkResult> walkSymbolTable(CallbackT &&cback) {
621*01eedbc7SRiver Riddle     if (Region *region = limit.dyn_cast<Region *>())
622*01eedbc7SRiver Riddle       return ::walkSymbolTable(*region, cback);
623*01eedbc7SRiver Riddle     return ::walkSymbolTable(limit.get<Operation *>(), cback);
624*01eedbc7SRiver Riddle   }
625*01eedbc7SRiver Riddle 
626ab9e5598SRiver Riddle   /// The representation of the symbol within this scope.
627ab9e5598SRiver Riddle   SymbolRefAttr symbol;
628ab9e5598SRiver Riddle 
629ab9e5598SRiver Riddle   /// The IR unit representing this scope.
630ab9e5598SRiver Riddle   llvm::PointerUnion<Operation *, Region *> limit;
631ab9e5598SRiver Riddle };
632be0a7e9fSMehdi Amini } // namespace
633ab9e5598SRiver Riddle 
634ab9e5598SRiver Riddle /// Collect all of the symbol scopes from 'symbol' to (inclusive) 'limit'.
collectSymbolScopes(Operation * symbol,Operation * limit)635ab9e5598SRiver Riddle static SmallVector<SymbolScope, 2> collectSymbolScopes(Operation *symbol,
636ab9e5598SRiver Riddle                                                        Operation *limit) {
63741d4aa7dSChris Lattner   StringAttr symName = SymbolTable::getSymbolName(symbol);
6386fca03f0SRiver Riddle   assert(!symbol->hasTrait<OpTrait::SymbolTable>() || symbol != limit);
6396fca03f0SRiver Riddle 
6406fca03f0SRiver Riddle   // Compute the ancestors of 'limit'.
6414efb7754SRiver Riddle   SetVector<Operation *, SmallVector<Operation *, 4>,
6426fca03f0SRiver Riddle             SmallPtrSet<Operation *, 4>>
6436fca03f0SRiver Riddle       limitAncestors;
6446fca03f0SRiver Riddle   Operation *limitAncestor = limit;
6456fca03f0SRiver Riddle   do {
6466fca03f0SRiver Riddle     // Check to see if 'symbol' is an ancestor of 'limit'.
6476fca03f0SRiver Riddle     if (limitAncestor == symbol) {
6486fca03f0SRiver Riddle       // Check that the nearest symbol table is 'symbol's parent. SymbolRefAttr
6496fca03f0SRiver Riddle       // doesn't support parent references.
650ab9e5598SRiver Riddle       if (SymbolTable::getNearestSymbolTable(limit->getParentOp()) ==
651ab9e5598SRiver Riddle           symbol->getParentOp())
65241d4aa7dSChris Lattner         return {{SymbolRefAttr::get(symName), limit}};
653ab9e5598SRiver Riddle       return {};
6546fca03f0SRiver Riddle     }
6556fca03f0SRiver Riddle 
6566fca03f0SRiver Riddle     limitAncestors.insert(limitAncestor);
6576fca03f0SRiver Riddle   } while ((limitAncestor = limitAncestor->getParentOp()));
6586fca03f0SRiver Riddle 
6596fca03f0SRiver Riddle   // Try to find the first ancestor of 'symbol' that is an ancestor of 'limit'.
6606fca03f0SRiver Riddle   Operation *commonAncestor = symbol->getParentOp();
6616fca03f0SRiver Riddle   do {
6626fca03f0SRiver Riddle     if (limitAncestors.count(commonAncestor))
6636fca03f0SRiver Riddle       break;
6646fca03f0SRiver Riddle   } while ((commonAncestor = commonAncestor->getParentOp()));
6656fca03f0SRiver Riddle   assert(commonAncestor && "'limit' and 'symbol' have no common ancestor");
6666fca03f0SRiver Riddle 
6676fca03f0SRiver Riddle   // Compute the set of valid nested references for 'symbol' as far up to the
6686fca03f0SRiver Riddle   // common ancestor as possible.
6696fca03f0SRiver Riddle   SmallVector<SymbolRefAttr, 2> references;
670ab9e5598SRiver Riddle   bool collectedAllReferences = succeeded(
671ab9e5598SRiver Riddle       collectValidReferencesFor(symbol, symName, commonAncestor, references));
6726fca03f0SRiver Riddle 
6736fca03f0SRiver Riddle   // Handle the case where the common ancestor is 'limit'.
6746fca03f0SRiver Riddle   if (commonAncestor == limit) {
675ab9e5598SRiver Riddle     SmallVector<SymbolScope, 2> scopes;
676ab9e5598SRiver Riddle 
6776fca03f0SRiver Riddle     // Walk each of the ancestors of 'symbol', calling the compute function for
6786fca03f0SRiver Riddle     // each one.
6796fca03f0SRiver Riddle     Operation *limitIt = symbol->getParentOp();
6806fca03f0SRiver Riddle     for (size_t i = 0, e = references.size(); i != e;
6816fca03f0SRiver Riddle          ++i, limitIt = limitIt->getParentOp()) {
682ab9e5598SRiver Riddle       assert(limitIt->hasTrait<OpTrait::SymbolTable>());
683ab9e5598SRiver Riddle       scopes.push_back({references[i], &limitIt->getRegion(0)});
6846fca03f0SRiver Riddle     }
685ab9e5598SRiver Riddle     return scopes;
6866fca03f0SRiver Riddle   }
6876fca03f0SRiver Riddle 
6886fca03f0SRiver Riddle   // Otherwise, we just need the symbol reference for 'symbol' that will be
6896fca03f0SRiver Riddle   // used within 'limit'. This is the last reference in the list we computed
6906fca03f0SRiver Riddle   // above if we were able to collect all references.
6916fca03f0SRiver Riddle   if (!collectedAllReferences)
692ab9e5598SRiver Riddle     return {};
693ab9e5598SRiver Riddle   return {{references.back(), limit}};
6946fca03f0SRiver Riddle }
collectSymbolScopes(Operation * symbol,Region * limit)695ab9e5598SRiver Riddle static SmallVector<SymbolScope, 2> collectSymbolScopes(Operation *symbol,
696ab9e5598SRiver Riddle                                                        Region *limit) {
697ab9e5598SRiver Riddle   auto scopes = collectSymbolScopes(symbol, limit->getParentOp());
6986fca03f0SRiver Riddle 
699ab9e5598SRiver Riddle   // If we collected some scopes to walk, make sure to constrain the one for
700ab9e5598SRiver Riddle   // limit to the specific region requested.
701ab9e5598SRiver Riddle   if (!scopes.empty())
702ab9e5598SRiver Riddle     scopes.back().limit = limit;
703ab9e5598SRiver Riddle   return scopes;
704ab9e5598SRiver Riddle }
705ab9e5598SRiver Riddle template <typename IRUnit>
collectSymbolScopes(StringAttr symbol,IRUnit * limit)70641d4aa7dSChris Lattner static SmallVector<SymbolScope, 1> collectSymbolScopes(StringAttr symbol,
707ab9e5598SRiver Riddle                                                        IRUnit *limit) {
70841d4aa7dSChris Lattner   return {{SymbolRefAttr::get(symbol), limit}};
7096fca03f0SRiver Riddle }
7106fca03f0SRiver Riddle 
7116fca03f0SRiver Riddle /// Returns true if the given reference 'SubRef' is a sub reference of the
7126fca03f0SRiver Riddle /// reference 'ref', i.e. 'ref' is a further qualified reference.
isReferencePrefixOf(SymbolRefAttr subRef,SymbolRefAttr ref)7136fca03f0SRiver Riddle static bool isReferencePrefixOf(SymbolRefAttr subRef, SymbolRefAttr ref) {
7146fca03f0SRiver Riddle   if (ref == subRef)
7156fca03f0SRiver Riddle     return true;
7166fca03f0SRiver Riddle 
7176fca03f0SRiver Riddle   // If the references are not pointer equal, check to see if `subRef` is a
7186fca03f0SRiver Riddle   // prefix of `ref`.
7196fca03f0SRiver Riddle   if (ref.isa<FlatSymbolRefAttr>() ||
7206fca03f0SRiver Riddle       ref.getRootReference() != subRef.getRootReference())
7216fca03f0SRiver Riddle     return false;
7226fca03f0SRiver Riddle 
7236fca03f0SRiver Riddle   auto refLeafs = ref.getNestedReferences();
7246fca03f0SRiver Riddle   auto subRefLeafs = subRef.getNestedReferences();
7256fca03f0SRiver Riddle   return subRefLeafs.size() < refLeafs.size() &&
7266fca03f0SRiver Riddle          subRefLeafs == refLeafs.take_front(subRefLeafs.size());
7276fca03f0SRiver Riddle }
7286fca03f0SRiver Riddle 
7296fca03f0SRiver Riddle //===----------------------------------------------------------------------===//
7306fca03f0SRiver Riddle // SymbolTable::getSymbolUses
7316fca03f0SRiver Riddle 
732ab9e5598SRiver Riddle /// The implementation of SymbolTable::getSymbolUses below.
733ab9e5598SRiver Riddle template <typename FromT>
getSymbolUsesImpl(FromT from)734ab9e5598SRiver Riddle static Optional<SymbolTable::UseRange> getSymbolUsesImpl(FromT from) {
735ab9e5598SRiver Riddle   std::vector<SymbolTable::SymbolUse> uses;
736*01eedbc7SRiver Riddle   auto walkFn = [&](SymbolTable::SymbolUse symbolUse) {
737ab9e5598SRiver Riddle     uses.push_back(symbolUse);
738ab9e5598SRiver Riddle     return WalkResult::advance();
739ab9e5598SRiver Riddle   };
740ab9e5598SRiver Riddle   auto result = walkSymbolUses(from, walkFn);
741ab9e5598SRiver Riddle   return result ? Optional<SymbolTable::UseRange>(std::move(uses)) : llvm::None;
742ab9e5598SRiver Riddle }
743ab9e5598SRiver Riddle 
744b3a6ae83SRiver Riddle /// Get an iterator range for all of the uses, for any symbol, that are nested
745b3a6ae83SRiver Riddle /// within the given operation 'from'. This does not traverse into any nested
746b3a6ae83SRiver Riddle /// symbol tables, and will also only return uses on 'from' if it does not
747ef43b565SRiver Riddle /// also define a symbol table. This is because we treat the region as the
748ef43b565SRiver Riddle /// boundary of the symbol table, and not the op itself. This function returns
749ef43b565SRiver Riddle /// None if there are any unknown operations that may potentially be symbol
750ef43b565SRiver Riddle /// tables.
getSymbolUses(Operation * from)751b3a6ae83SRiver Riddle auto SymbolTable::getSymbolUses(Operation *from) -> Optional<UseRange> {
752ab9e5598SRiver Riddle   return getSymbolUsesImpl(from);
753ab9e5598SRiver Riddle }
getSymbolUses(Region * from)754ab9e5598SRiver Riddle auto SymbolTable::getSymbolUses(Region *from) -> Optional<UseRange> {
755ab9e5598SRiver Riddle   return getSymbolUsesImpl(MutableArrayRef<Region>(*from));
7566fca03f0SRiver Riddle }
7576fca03f0SRiver Riddle 
7586fca03f0SRiver Riddle //===----------------------------------------------------------------------===//
7596fca03f0SRiver Riddle // SymbolTable::getSymbolUses
7606fca03f0SRiver Riddle 
7616fca03f0SRiver Riddle /// The implementation of SymbolTable::getSymbolUses below.
762ab9e5598SRiver Riddle template <typename SymbolT, typename IRUnitT>
getSymbolUsesImpl(SymbolT symbol,IRUnitT * limit)7636fca03f0SRiver Riddle static Optional<SymbolTable::UseRange> getSymbolUsesImpl(SymbolT symbol,
764ab9e5598SRiver Riddle                                                          IRUnitT *limit) {
7656fca03f0SRiver Riddle   std::vector<SymbolTable::SymbolUse> uses;
766ab9e5598SRiver Riddle   for (SymbolScope &scope : collectSymbolScopes(symbol, limit)) {
767ab9e5598SRiver Riddle     if (!scope.walk([&](SymbolTable::SymbolUse symbolUse) {
768ab9e5598SRiver Riddle           if (isReferencePrefixOf(scope.symbol, symbolUse.getSymbolRef()))
769b3a6ae83SRiver Riddle             uses.push_back(symbolUse);
770ab9e5598SRiver Riddle         }))
7716fca03f0SRiver Riddle       return llvm::None;
772ac91e673SRiver Riddle   }
773ab9e5598SRiver Riddle   return SymbolTable::UseRange(std::move(uses));
774ab9e5598SRiver Riddle }
775ac91e673SRiver Riddle 
776b3a6ae83SRiver Riddle /// Get all of the uses of the given symbol that are nested within the given
777b3a6ae83SRiver Riddle /// operation 'from', invoking the provided callback for each. This does not
778ab9e5598SRiver Riddle /// traverse into any nested symbol tables. This function returns None if there
779ab9e5598SRiver Riddle /// are any unknown operations that may potentially be symbol tables.
getSymbolUses(StringAttr symbol,Operation * from)78041d4aa7dSChris Lattner auto SymbolTable::getSymbolUses(StringAttr symbol, Operation *from)
781b3a6ae83SRiver Riddle     -> Optional<UseRange> {
7826fca03f0SRiver Riddle   return getSymbolUsesImpl(symbol, from);
7836fca03f0SRiver Riddle }
getSymbolUses(Operation * symbol,Operation * from)7846fca03f0SRiver Riddle auto SymbolTable::getSymbolUses(Operation *symbol, Operation *from)
7856fca03f0SRiver Riddle     -> Optional<UseRange> {
7866fca03f0SRiver Riddle   return getSymbolUsesImpl(symbol, from);
7876fca03f0SRiver Riddle }
getSymbolUses(StringAttr symbol,Region * from)78841d4aa7dSChris Lattner auto SymbolTable::getSymbolUses(StringAttr symbol, Region *from)
789ab9e5598SRiver Riddle     -> Optional<UseRange> {
790ab9e5598SRiver Riddle   return getSymbolUsesImpl(symbol, from);
791ab9e5598SRiver Riddle }
getSymbolUses(Operation * symbol,Region * from)792ab9e5598SRiver Riddle auto SymbolTable::getSymbolUses(Operation *symbol, Region *from)
793ab9e5598SRiver Riddle     -> Optional<UseRange> {
794ab9e5598SRiver Riddle   return getSymbolUsesImpl(symbol, from);
795ab9e5598SRiver Riddle }
796b3a6ae83SRiver Riddle 
7976fca03f0SRiver Riddle //===----------------------------------------------------------------------===//
7986fca03f0SRiver Riddle // SymbolTable::symbolKnownUseEmpty
7996fca03f0SRiver Riddle 
8006fca03f0SRiver Riddle /// The implementation of SymbolTable::symbolKnownUseEmpty below.
801ab9e5598SRiver Riddle template <typename SymbolT, typename IRUnitT>
symbolKnownUseEmptyImpl(SymbolT symbol,IRUnitT * limit)802ab9e5598SRiver Riddle static bool symbolKnownUseEmptyImpl(SymbolT symbol, IRUnitT *limit) {
803ab9e5598SRiver Riddle   for (SymbolScope &scope : collectSymbolScopes(symbol, limit)) {
8046fca03f0SRiver Riddle     // Walk all of the symbol uses looking for a reference to 'symbol'.
805*01eedbc7SRiver Riddle     if (scope.walk([&](SymbolTable::SymbolUse symbolUse) {
806ab9e5598SRiver Riddle           return isReferencePrefixOf(scope.symbol, symbolUse.getSymbolRef())
8076fca03f0SRiver Riddle                      ? WalkResult::interrupt()
8086fca03f0SRiver Riddle                      : WalkResult::advance();
809ab9e5598SRiver Riddle         }) != WalkResult::advance())
810ab9e5598SRiver Riddle       return false;
811ab9e5598SRiver Riddle   }
812ab9e5598SRiver Riddle   return true;
813b3a6ae83SRiver Riddle }
814b3a6ae83SRiver Riddle 
815b3a6ae83SRiver Riddle /// Return if the given symbol is known to have no uses that are nested within
816b3a6ae83SRiver Riddle /// the given operation 'from'. This does not traverse into any nested symbol
817ab9e5598SRiver Riddle /// tables. This function will also return false if there are any unknown
818ab9e5598SRiver Riddle /// operations that may potentially be symbol tables.
symbolKnownUseEmpty(StringAttr symbol,Operation * from)81941d4aa7dSChris Lattner bool SymbolTable::symbolKnownUseEmpty(StringAttr symbol, Operation *from) {
8206fca03f0SRiver Riddle   return symbolKnownUseEmptyImpl(symbol, from);
8216fca03f0SRiver Riddle }
symbolKnownUseEmpty(Operation * symbol,Operation * from)8226fca03f0SRiver Riddle bool SymbolTable::symbolKnownUseEmpty(Operation *symbol, Operation *from) {
8236fca03f0SRiver Riddle   return symbolKnownUseEmptyImpl(symbol, from);
824ac91e673SRiver Riddle }
symbolKnownUseEmpty(StringAttr symbol,Region * from)82541d4aa7dSChris Lattner bool SymbolTable::symbolKnownUseEmpty(StringAttr symbol, Region *from) {
826ab9e5598SRiver Riddle   return symbolKnownUseEmptyImpl(symbol, from);
827ab9e5598SRiver Riddle }
symbolKnownUseEmpty(Operation * symbol,Region * from)828ab9e5598SRiver Riddle bool SymbolTable::symbolKnownUseEmpty(Operation *symbol, Region *from) {
829ab9e5598SRiver Riddle   return symbolKnownUseEmptyImpl(symbol, from);
830ab9e5598SRiver Riddle }
831ef43b565SRiver Riddle 
8326fca03f0SRiver Riddle //===----------------------------------------------------------------------===//
8336fca03f0SRiver Riddle // SymbolTable::replaceAllSymbolUses
8346fca03f0SRiver Riddle 
8356fca03f0SRiver Riddle /// Generates a new symbol reference attribute with a new leaf reference.
generateNewRefAttr(SymbolRefAttr oldAttr,FlatSymbolRefAttr newLeafAttr)836df186507SBenjamin Kramer static SymbolRefAttr generateNewRefAttr(SymbolRefAttr oldAttr,
8376fca03f0SRiver Riddle                                         FlatSymbolRefAttr newLeafAttr) {
8386fca03f0SRiver Riddle   if (oldAttr.isa<FlatSymbolRefAttr>())
8396fca03f0SRiver Riddle     return newLeafAttr;
8406fca03f0SRiver Riddle   auto nestedRefs = llvm::to_vector<2>(oldAttr.getNestedReferences());
8416fca03f0SRiver Riddle   nestedRefs.back() = newLeafAttr;
84241d4aa7dSChris Lattner   return SymbolRefAttr::get(oldAttr.getRootReference(), nestedRefs);
8436fca03f0SRiver Riddle }
8446fca03f0SRiver Riddle 
8456fca03f0SRiver Riddle /// The implementation of SymbolTable::replaceAllSymbolUses below.
846ab9e5598SRiver Riddle template <typename SymbolT, typename IRUnitT>
847ab9e5598SRiver Riddle static LogicalResult
replaceAllSymbolUsesImpl(SymbolT symbol,StringAttr newSymbol,IRUnitT * limit)84841d4aa7dSChris Lattner replaceAllSymbolUsesImpl(SymbolT symbol, StringAttr newSymbol, IRUnitT *limit) {
8496fca03f0SRiver Riddle   // Generate a new attribute to replace the given attribute.
85041d4aa7dSChris Lattner   FlatSymbolRefAttr newLeafAttr = FlatSymbolRefAttr::get(newSymbol);
851ab9e5598SRiver Riddle   for (SymbolScope &scope : collectSymbolScopes(symbol, limit)) {
852*01eedbc7SRiver Riddle     SymbolRefAttr oldAttr = scope.symbol;
853ab9e5598SRiver Riddle     SymbolRefAttr newAttr = generateNewRefAttr(scope.symbol, newLeafAttr);
8546fca03f0SRiver Riddle 
855*01eedbc7SRiver Riddle     auto walkFn = [&](Operation *op) -> Optional<WalkResult> {
856*01eedbc7SRiver Riddle       auto remapAttrFn = [&](Attribute attr) -> Attribute {
857*01eedbc7SRiver Riddle         if (attr == oldAttr)
858*01eedbc7SRiver Riddle           return newAttr;
859*01eedbc7SRiver Riddle         // Handle prefix matches.
860*01eedbc7SRiver Riddle         if (SymbolRefAttr symRef = attr.dyn_cast<SymbolRefAttr>()) {
861*01eedbc7SRiver Riddle           if (isReferencePrefixOf(oldAttr, symRef)) {
862*01eedbc7SRiver Riddle             auto oldNestedRefs = oldAttr.getNestedReferences();
863*01eedbc7SRiver Riddle             auto nestedRefs = symRef.getNestedReferences();
864*01eedbc7SRiver Riddle             if (oldNestedRefs.empty())
865*01eedbc7SRiver Riddle               return SymbolRefAttr::get(newSymbol, nestedRefs);
866*01eedbc7SRiver Riddle 
867*01eedbc7SRiver Riddle             auto newNestedRefs = llvm::to_vector<4>(nestedRefs);
868*01eedbc7SRiver Riddle             newNestedRefs[oldNestedRefs.size() - 1] = newLeafAttr;
869*01eedbc7SRiver Riddle             return SymbolRefAttr::get(symRef.getRootReference(), newNestedRefs);
8706fca03f0SRiver Riddle           }
8716fca03f0SRiver Riddle         }
872*01eedbc7SRiver Riddle         return attr;
873*01eedbc7SRiver Riddle       };
874*01eedbc7SRiver Riddle       // Generate a new attribute dictionary by replacing references to the old
875*01eedbc7SRiver Riddle       // symbol.
876*01eedbc7SRiver Riddle       auto newDict = op->getAttrDictionary().replaceSubElements(remapAttrFn);
877*01eedbc7SRiver Riddle       if (!newDict)
878*01eedbc7SRiver Riddle         return WalkResult::interrupt();
8796fca03f0SRiver Riddle 
880*01eedbc7SRiver Riddle       op->setAttrs(newDict.template cast<DictionaryAttr>());
8816fca03f0SRiver Riddle       return WalkResult::advance();
8826fca03f0SRiver Riddle     };
883*01eedbc7SRiver Riddle     if (!scope.walkSymbolTable(walkFn))
884ab9e5598SRiver Riddle       return failure();
8856fca03f0SRiver Riddle   }
8866fca03f0SRiver Riddle   return success();
8876fca03f0SRiver Riddle }
8886fca03f0SRiver Riddle 
889ef43b565SRiver Riddle /// Attempt to replace all uses of the given symbol 'oldSymbol' with the
890ef43b565SRiver Riddle /// provided symbol 'newSymbol' that are nested within the given operation
891ab9e5598SRiver Riddle /// 'from'. This does not traverse into any nested symbol tables. If there are
892ab9e5598SRiver Riddle /// any unknown operations that may potentially be symbol tables, no uses are
893ab9e5598SRiver Riddle /// replaced and failure is returned.
replaceAllSymbolUses(StringAttr oldSymbol,StringAttr newSymbol,Operation * from)89441d4aa7dSChris Lattner LogicalResult SymbolTable::replaceAllSymbolUses(StringAttr oldSymbol,
89541d4aa7dSChris Lattner                                                 StringAttr newSymbol,
896ef43b565SRiver Riddle                                                 Operation *from) {
8976fca03f0SRiver Riddle   return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from);
898ef43b565SRiver Riddle }
replaceAllSymbolUses(Operation * oldSymbol,StringAttr newSymbol,Operation * from)8996fca03f0SRiver Riddle LogicalResult SymbolTable::replaceAllSymbolUses(Operation *oldSymbol,
90041d4aa7dSChris Lattner                                                 StringAttr newSymbol,
9016fca03f0SRiver Riddle                                                 Operation *from) {
9026fca03f0SRiver Riddle   return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from);
903ef43b565SRiver Riddle }
replaceAllSymbolUses(StringAttr oldSymbol,StringAttr newSymbol,Region * from)90441d4aa7dSChris Lattner LogicalResult SymbolTable::replaceAllSymbolUses(StringAttr oldSymbol,
90541d4aa7dSChris Lattner                                                 StringAttr newSymbol,
906ab9e5598SRiver Riddle                                                 Region *from) {
907ab9e5598SRiver Riddle   return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from);
908ab9e5598SRiver Riddle }
replaceAllSymbolUses(Operation * oldSymbol,StringAttr newSymbol,Region * from)909ab9e5598SRiver Riddle LogicalResult SymbolTable::replaceAllSymbolUses(Operation *oldSymbol,
91041d4aa7dSChris Lattner                                                 StringAttr newSymbol,
911ab9e5598SRiver Riddle                                                 Region *from) {
912ab9e5598SRiver Riddle   return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from);
913ab9e5598SRiver Riddle }
9147c221a7dSRiver Riddle 
9157c221a7dSRiver Riddle //===----------------------------------------------------------------------===//
9167bc7d0acSRiver Riddle // SymbolTableCollection
9177bc7d0acSRiver Riddle //===----------------------------------------------------------------------===//
9187bc7d0acSRiver Riddle 
lookupSymbolIn(Operation * symbolTableOp,StringAttr symbol)9197bc7d0acSRiver Riddle Operation *SymbolTableCollection::lookupSymbolIn(Operation *symbolTableOp,
92041d4aa7dSChris Lattner                                                  StringAttr symbol) {
9217bc7d0acSRiver Riddle   return getSymbolTable(symbolTableOp).lookup(symbol);
9227bc7d0acSRiver Riddle }
lookupSymbolIn(Operation * symbolTableOp,SymbolRefAttr name)9237bc7d0acSRiver Riddle Operation *SymbolTableCollection::lookupSymbolIn(Operation *symbolTableOp,
9247bc7d0acSRiver Riddle                                                  SymbolRefAttr name) {
9257bc7d0acSRiver Riddle   SmallVector<Operation *, 4> symbols;
9267bc7d0acSRiver Riddle   if (failed(lookupSymbolIn(symbolTableOp, name, symbols)))
9277bc7d0acSRiver Riddle     return nullptr;
9287bc7d0acSRiver Riddle   return symbols.back();
9297bc7d0acSRiver Riddle }
9307bc7d0acSRiver Riddle /// A variant of 'lookupSymbolIn' that returns all of the symbols referenced by
9317bc7d0acSRiver Riddle /// a given SymbolRefAttr. Returns failure if any of the nested references could
9327bc7d0acSRiver Riddle /// not be resolved.
9337bc7d0acSRiver Riddle LogicalResult
lookupSymbolIn(Operation * symbolTableOp,SymbolRefAttr name,SmallVectorImpl<Operation * > & symbols)9347bc7d0acSRiver Riddle SymbolTableCollection::lookupSymbolIn(Operation *symbolTableOp,
9357bc7d0acSRiver Riddle                                       SymbolRefAttr name,
9367bc7d0acSRiver Riddle                                       SmallVectorImpl<Operation *> &symbols) {
93741d4aa7dSChris Lattner   auto lookupFn = [this](Operation *symbolTableOp, StringAttr symbol) {
9387bc7d0acSRiver Riddle     return lookupSymbolIn(symbolTableOp, symbol);
9397bc7d0acSRiver Riddle   };
9407bc7d0acSRiver Riddle   return lookupSymbolInImpl(symbolTableOp, name, symbols, lookupFn);
9417bc7d0acSRiver Riddle }
9427bc7d0acSRiver Riddle 
94371eeb5ecSRiver Riddle /// Returns the operation registered with the given symbol name within the
94471eeb5ecSRiver Riddle /// closest parent operation of, or including, 'from' with the
94571eeb5ecSRiver Riddle /// 'OpTrait::SymbolTable' trait. Returns nullptr if no valid symbol was
94671eeb5ecSRiver Riddle /// found.
lookupNearestSymbolFrom(Operation * from,StringAttr symbol)94771eeb5ecSRiver Riddle Operation *SymbolTableCollection::lookupNearestSymbolFrom(Operation *from,
94841d4aa7dSChris Lattner                                                           StringAttr symbol) {
94971eeb5ecSRiver Riddle   Operation *symbolTableOp = SymbolTable::getNearestSymbolTable(from);
95071eeb5ecSRiver Riddle   return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
95171eeb5ecSRiver Riddle }
95271eeb5ecSRiver Riddle Operation *
lookupNearestSymbolFrom(Operation * from,SymbolRefAttr symbol)95371eeb5ecSRiver Riddle SymbolTableCollection::lookupNearestSymbolFrom(Operation *from,
95471eeb5ecSRiver Riddle                                                SymbolRefAttr symbol) {
95571eeb5ecSRiver Riddle   Operation *symbolTableOp = SymbolTable::getNearestSymbolTable(from);
95671eeb5ecSRiver Riddle   return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
95771eeb5ecSRiver Riddle }
95871eeb5ecSRiver Riddle 
9597bc7d0acSRiver Riddle /// Lookup, or create, a symbol table for an operation.
getSymbolTable(Operation * op)9607bc7d0acSRiver Riddle SymbolTable &SymbolTableCollection::getSymbolTable(Operation *op) {
9617bc7d0acSRiver Riddle   auto it = symbolTables.try_emplace(op, nullptr);
9627bc7d0acSRiver Riddle   if (it.second)
9637bc7d0acSRiver Riddle     it.first->second = std::make_unique<SymbolTable>(op);
9647bc7d0acSRiver Riddle   return *it.first->second;
9657bc7d0acSRiver Riddle }
9667bc7d0acSRiver Riddle 
9677bc7d0acSRiver Riddle //===----------------------------------------------------------------------===//
9684a7aed4eSRiver Riddle // SymbolUserMap
9694a7aed4eSRiver Riddle //===----------------------------------------------------------------------===//
9704a7aed4eSRiver Riddle 
SymbolUserMap(SymbolTableCollection & symbolTable,Operation * symbolTableOp)9714a7aed4eSRiver Riddle SymbolUserMap::SymbolUserMap(SymbolTableCollection &symbolTable,
9724a7aed4eSRiver Riddle                              Operation *symbolTableOp)
9734a7aed4eSRiver Riddle     : symbolTable(symbolTable) {
9744a7aed4eSRiver Riddle   // Walk each of the symbol tables looking for discardable callgraph nodes.
9754a7aed4eSRiver Riddle   SmallVector<Operation *> symbols;
9764a7aed4eSRiver Riddle   auto walkFn = [&](Operation *symbolTableOp, bool allUsesVisible) {
9774a7aed4eSRiver Riddle     for (Operation &nestedOp : symbolTableOp->getRegion(0).getOps()) {
9784a7aed4eSRiver Riddle       auto symbolUses = SymbolTable::getSymbolUses(&nestedOp);
9794a7aed4eSRiver Riddle       assert(symbolUses && "expected uses to be valid");
9804a7aed4eSRiver Riddle 
9814a7aed4eSRiver Riddle       for (const SymbolTable::SymbolUse &use : *symbolUses) {
9824a7aed4eSRiver Riddle         symbols.clear();
9834a7aed4eSRiver Riddle         (void)symbolTable.lookupSymbolIn(symbolTableOp, use.getSymbolRef(),
9844a7aed4eSRiver Riddle                                          symbols);
9854a7aed4eSRiver Riddle         for (Operation *symbolOp : symbols)
9864a7aed4eSRiver Riddle           symbolToUsers[symbolOp].insert(use.getUser());
9874a7aed4eSRiver Riddle       }
9884a7aed4eSRiver Riddle     }
9894a7aed4eSRiver Riddle   };
9904a7aed4eSRiver Riddle   // We just set `allSymUsesVisible` to false here because it isn't necessary
9914a7aed4eSRiver Riddle   // for building the user map.
9924a7aed4eSRiver Riddle   SymbolTable::walkSymbolTables(symbolTableOp, /*allSymUsesVisible=*/false,
9934a7aed4eSRiver Riddle                                 walkFn);
9944a7aed4eSRiver Riddle }
9954a7aed4eSRiver Riddle 
replaceAllUsesWith(Operation * symbol,StringAttr newSymbolName)9964a7aed4eSRiver Riddle void SymbolUserMap::replaceAllUsesWith(Operation *symbol,
99741d4aa7dSChris Lattner                                        StringAttr newSymbolName) {
9984a7aed4eSRiver Riddle   auto it = symbolToUsers.find(symbol);
9994a7aed4eSRiver Riddle   if (it == symbolToUsers.end())
10004a7aed4eSRiver Riddle     return;
10014a7aed4eSRiver Riddle 
10024a7aed4eSRiver Riddle   // Replace the uses within the users of `symbol`.
1003f92d319cSNandor Licker   for (Operation *user : it->second)
10044a7aed4eSRiver Riddle     (void)SymbolTable::replaceAllSymbolUses(symbol, newSymbolName, user);
10054a7aed4eSRiver Riddle 
10064a7aed4eSRiver Riddle   // Move the current users of `symbol` to the new symbol if it is in the
10074a7aed4eSRiver Riddle   // symbol table.
10084a7aed4eSRiver Riddle   Operation *newSymbol =
10094a7aed4eSRiver Riddle       symbolTable.lookupSymbolIn(symbol->getParentOp(), newSymbolName);
10104a7aed4eSRiver Riddle   if (newSymbol != symbol) {
1011f92d319cSNandor Licker     // Transfer over the users to the new symbol.  The reference to the old one
1012f92d319cSNandor Licker     // is fetched again as the iterator is invalidated during the insertion.
1013f92d319cSNandor Licker     auto newIt = symbolToUsers.try_emplace(newSymbol, SetVector<Operation *>{});
1014f92d319cSNandor Licker     auto oldIt = symbolToUsers.find(symbol);
1015f92d319cSNandor Licker     assert(oldIt != symbolToUsers.end() && "missing old users list");
1016f92d319cSNandor Licker     if (newIt.second)
1017f92d319cSNandor Licker       newIt.first->second = std::move(oldIt->second);
10184a7aed4eSRiver Riddle     else
1019f92d319cSNandor Licker       newIt.first->second.set_union(oldIt->second);
1020f92d319cSNandor Licker     symbolToUsers.erase(oldIt);
10214a7aed4eSRiver Riddle   }
10224a7aed4eSRiver Riddle }
10234a7aed4eSRiver Riddle 
10244a7aed4eSRiver Riddle //===----------------------------------------------------------------------===//
10258b5a3e46SRahul Joshi // Visibility parsing implementation.
10268b5a3e46SRahul Joshi //===----------------------------------------------------------------------===//
10278b5a3e46SRahul Joshi 
parseOptionalVisibilityKeyword(OpAsmParser & parser,NamedAttrList & attrs)10288b5a3e46SRahul Joshi ParseResult impl::parseOptionalVisibilityKeyword(OpAsmParser &parser,
10298b5a3e46SRahul Joshi                                                  NamedAttrList &attrs) {
10308b5a3e46SRahul Joshi   StringRef visibility;
10318b5a3e46SRahul Joshi   if (parser.parseOptionalKeyword(&visibility, {"public", "private", "nested"}))
10328b5a3e46SRahul Joshi     return failure();
10338b5a3e46SRahul Joshi 
10348b5a3e46SRahul Joshi   StringAttr visibilityAttr = parser.getBuilder().getStringAttr(visibility);
10358b5a3e46SRahul Joshi   attrs.push_back(parser.getBuilder().getNamedAttr(
10368b5a3e46SRahul Joshi       SymbolTable::getVisibilityAttrName(), visibilityAttr));
10378b5a3e46SRahul Joshi   return success();
10388b5a3e46SRahul Joshi }
10398b5a3e46SRahul Joshi 
10408b5a3e46SRahul Joshi //===----------------------------------------------------------------------===//
10417c221a7dSRiver Riddle // Symbol Interfaces
10427c221a7dSRiver Riddle //===----------------------------------------------------------------------===//
10437c221a7dSRiver Riddle 
10447c221a7dSRiver Riddle /// Include the generated symbol interfaces.
10457c221a7dSRiver Riddle #include "mlir/IR/SymbolInterfaces.cpp.inc"
1046