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 ®ion : op.getRegions())
9371eeb5ecSRiver Riddle worklist.push_back(®ion);
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 ®ion : 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 ®ion = 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