MLIR  14.0.0git
SymbolTable.cpp
Go to the documentation of this file.
1 //===- SymbolTable.cpp - MLIR Symbol Table Class --------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "mlir/IR/SymbolTable.h"
10 #include "mlir/IR/Builders.h"
12 #include "llvm/ADT/SetVector.h"
13 #include "llvm/ADT/SmallPtrSet.h"
14 #include "llvm/ADT/SmallString.h"
15 #include "llvm/ADT/StringSwitch.h"
16 
17 using namespace mlir;
18 
19 /// Return true if the given operation is unknown and may potentially define a
20 /// symbol table.
22  return op->getNumRegions() == 1 && !op->getDialect();
23 }
24 
25 /// Returns the string name of the given symbol, or null if this is not a
26 /// symbol.
27 static StringAttr getNameIfSymbol(Operation *op) {
28  return op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
29 }
30 static StringAttr getNameIfSymbol(Operation *op, StringAttr symbolAttrNameId) {
31  return op->getAttrOfType<StringAttr>(symbolAttrNameId);
32 }
33 
34 /// Computes the nested symbol reference attribute for the symbol 'symbolName'
35 /// that are usable within the symbol table operations from 'symbol' as far up
36 /// to the given operation 'within', where 'within' is an ancestor of 'symbol'.
37 /// Returns success if all references up to 'within' could be computed.
38 static LogicalResult
39 collectValidReferencesFor(Operation *symbol, StringAttr symbolName,
40  Operation *within,
42  assert(within->isAncestor(symbol) && "expected 'within' to be an ancestor");
43  MLIRContext *ctx = symbol->getContext();
44 
45  auto leafRef = FlatSymbolRefAttr::get(symbolName);
46  results.push_back(leafRef);
47 
48  // Early exit for when 'within' is the parent of 'symbol'.
49  Operation *symbolTableOp = symbol->getParentOp();
50  if (within == symbolTableOp)
51  return success();
52 
53  // Collect references until 'symbolTableOp' reaches 'within'.
54  SmallVector<FlatSymbolRefAttr, 1> nestedRefs(1, leafRef);
55  StringAttr symbolNameId =
56  StringAttr::get(ctx, SymbolTable::getSymbolAttrName());
57  do {
58  // Each parent of 'symbol' should define a symbol table.
59  if (!symbolTableOp->hasTrait<OpTrait::SymbolTable>())
60  return failure();
61  // Each parent of 'symbol' should also be a symbol.
62  StringAttr symbolTableName = getNameIfSymbol(symbolTableOp, symbolNameId);
63  if (!symbolTableName)
64  return failure();
65  results.push_back(SymbolRefAttr::get(symbolTableName, nestedRefs));
66 
67  symbolTableOp = symbolTableOp->getParentOp();
68  if (symbolTableOp == within)
69  break;
70  nestedRefs.insert(nestedRefs.begin(),
71  FlatSymbolRefAttr::get(symbolTableName));
72  } while (true);
73  return success();
74 }
75 
76 /// Walk all of the operations within the given set of regions, without
77 /// traversing into any nested symbol tables. Stops walking if the result of the
78 /// callback is anything other than `WalkResult::advance`.
82  SmallVector<Region *, 1> worklist(llvm::make_pointer_range(regions));
83  while (!worklist.empty()) {
84  for (Operation &op : worklist.pop_back_val()->getOps()) {
85  Optional<WalkResult> result = callback(&op);
86  if (result != WalkResult::advance())
87  return result;
88 
89  // If this op defines a new symbol table scope, we can't traverse. Any
90  // symbol references nested within 'op' are different semantically.
91  if (!op.hasTrait<OpTrait::SymbolTable>()) {
92  for (Region &region : op.getRegions())
93  worklist.push_back(&region);
94  }
95  }
96  }
97  return WalkResult::advance();
98 }
99 
100 //===----------------------------------------------------------------------===//
101 // SymbolTable
102 //===----------------------------------------------------------------------===//
103 
104 /// Build a symbol table with the symbols within the given operation.
106  : symbolTableOp(symbolTableOp) {
107  assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>() &&
108  "expected operation to have SymbolTable trait");
109  assert(symbolTableOp->getNumRegions() == 1 &&
110  "expected operation to have a single region");
111  assert(llvm::hasSingleElement(symbolTableOp->getRegion(0)) &&
112  "expected operation to have a single block");
113 
114  StringAttr symbolNameId = StringAttr::get(symbolTableOp->getContext(),
116  for (auto &op : symbolTableOp->getRegion(0).front()) {
117  StringAttr name = getNameIfSymbol(&op, symbolNameId);
118  if (!name)
119  continue;
120 
121  auto inserted = symbolTable.insert({name, &op});
122  (void)inserted;
123  assert(inserted.second &&
124  "expected region to contain uniquely named symbol operations");
125  }
126 }
127 
128 /// Look up a symbol with the specified name, returning null if no such name
129 /// exists. Names never include the @ on them.
130 Operation *SymbolTable::lookup(StringRef name) const {
131  return lookup(StringAttr::get(symbolTableOp->getContext(), name));
132 }
133 Operation *SymbolTable::lookup(StringAttr name) const {
134  return symbolTable.lookup(name);
135 }
136 
137 /// Erase the given symbol from the table.
139  StringAttr name = getNameIfSymbol(symbol);
140  assert(name && "expected valid 'name' attribute");
141  assert(symbol->getParentOp() == symbolTableOp &&
142  "expected this operation to be inside of the operation with this "
143  "SymbolTable");
144 
145  auto it = symbolTable.find(name);
146  if (it != symbolTable.end() && it->second == symbol) {
147  symbolTable.erase(it);
148  symbol->erase();
149  }
150 }
151 
152 // TODO: Consider if this should be renamed to something like insertOrUpdate
153 /// Insert a new symbol into the table and associated operation if not already
154 /// there and rename it as necessary to avoid collisions. Return the name of
155 /// the symbol after insertion as attribute.
156 StringAttr SymbolTable::insert(Operation *symbol, Block::iterator insertPt) {
157  // The symbol cannot be the child of another op and must be the child of the
158  // symbolTableOp after this.
159  //
160  // TODO: consider if SymbolTable's constructor should behave the same.
161  if (!symbol->getParentOp()) {
162  auto &body = symbolTableOp->getRegion(0).front();
163  if (insertPt == Block::iterator()) {
164  insertPt = Block::iterator(body.end());
165  } else {
166  assert((insertPt == body.end() ||
167  insertPt->getParentOp() == symbolTableOp) &&
168  "expected insertPt to be in the associated module operation");
169  }
170  // Insert before the terminator, if any.
171  if (insertPt == Block::iterator(body.end()) && !body.empty() &&
172  std::prev(body.end())->hasTrait<OpTrait::IsTerminator>())
173  insertPt = std::prev(body.end());
174 
175  body.getOperations().insert(insertPt, symbol);
176  }
177  assert(symbol->getParentOp() == symbolTableOp &&
178  "symbol is already inserted in another op");
179 
180  // Add this symbol to the symbol table, uniquing the name if a conflict is
181  // detected.
182  StringAttr name = getSymbolName(symbol);
183  if (symbolTable.insert({name, symbol}).second)
184  return name;
185  // If the symbol was already in the table, also return.
186  if (symbolTable.lookup(name) == symbol)
187  return name;
188  // If a conflict was detected, then the symbol will not have been added to
189  // the symbol table. Try suffixes until we get to a unique name that works.
190  SmallString<128> nameBuffer(name.getValue());
191  unsigned originalLength = nameBuffer.size();
192 
193  MLIRContext *context = symbol->getContext();
194 
195  // Iteratively try suffixes until we find one that isn't used.
196  do {
197  nameBuffer.resize(originalLength);
198  nameBuffer += '_';
199  nameBuffer += std::to_string(uniquingCounter++);
200  } while (!symbolTable.insert({StringAttr::get(context, nameBuffer), symbol})
201  .second);
202  setSymbolName(symbol, nameBuffer);
203  return getSymbolName(symbol);
204 }
205 
206 /// Returns the name of the given symbol operation.
208  StringAttr name = getNameIfSymbol(symbol);
209  assert(name && "expected valid symbol name");
210  return name;
211 }
212 
213 /// Sets the name of the given symbol operation.
214 void SymbolTable::setSymbolName(Operation *symbol, StringAttr name) {
215  symbol->setAttr(getSymbolAttrName(), name);
216 }
217 
218 /// Returns the visibility of the given symbol operation.
220  // If the attribute doesn't exist, assume public.
221  StringAttr vis = symbol->getAttrOfType<StringAttr>(getVisibilityAttrName());
222  if (!vis)
223  return Visibility::Public;
224 
225  // Otherwise, switch on the string value.
226  return StringSwitch<Visibility>(vis.getValue())
227  .Case("private", Visibility::Private)
228  .Case("nested", Visibility::Nested)
229  .Case("public", Visibility::Public);
230 }
231 /// Sets the visibility of the given symbol operation.
233  MLIRContext *ctx = symbol->getContext();
234 
235  // If the visibility is public, just drop the attribute as this is the
236  // default.
237  if (vis == Visibility::Public) {
238  symbol->removeAttr(StringAttr::get(ctx, getVisibilityAttrName()));
239  return;
240  }
241 
242  // Otherwise, update the attribute.
243  assert((vis == Visibility::Private || vis == Visibility::Nested) &&
244  "unknown symbol visibility kind");
245 
246  StringRef visName = vis == Visibility::Private ? "private" : "nested";
247  symbol->setAttr(getVisibilityAttrName(), StringAttr::get(ctx, visName));
248 }
249 
250 /// Returns the nearest symbol table from a given operation `from`. Returns
251 /// nullptr if no valid parent symbol table could be found.
253  assert(from && "expected valid operation");
255  return nullptr;
256 
257  while (!from->hasTrait<OpTrait::SymbolTable>()) {
258  from = from->getParentOp();
259 
260  // Check that this is a valid op and isn't an unknown symbol table.
261  if (!from || isPotentiallyUnknownSymbolTable(from))
262  return nullptr;
263  }
264  return from;
265 }
266 
267 /// Walks all symbol table operations nested within, and including, `op`. For
268 /// each symbol table operation, the provided callback is invoked with the op
269 /// and a boolean signifying if the symbols within that symbol table can be
270 /// treated as if all uses are visible. `allSymUsesVisible` identifies whether
271 /// all of the symbol uses of symbols within `op` are visible.
273  Operation *op, bool allSymUsesVisible,
274  function_ref<void(Operation *, bool)> callback) {
275  bool isSymbolTable = op->hasTrait<OpTrait::SymbolTable>();
276  if (isSymbolTable) {
277  SymbolOpInterface symbol = dyn_cast<SymbolOpInterface>(op);
278  allSymUsesVisible |= !symbol || symbol.isPrivate();
279  } else {
280  // Otherwise if 'op' is not a symbol table, any nested symbols are
281  // guaranteed to be hidden.
282  allSymUsesVisible = true;
283  }
284 
285  for (Region &region : op->getRegions())
286  for (Block &block : region)
287  for (Operation &nestedOp : block)
288  walkSymbolTables(&nestedOp, allSymUsesVisible, callback);
289 
290  // If 'op' had the symbol table trait, visit it after any nested symbol
291  // tables.
292  if (isSymbolTable)
293  callback(op, allSymUsesVisible);
294 }
295 
296 /// Returns the operation registered with the given symbol name with the
297 /// regions of 'symbolTableOp'. 'symbolTableOp' is required to be an operation
298 /// with the 'OpTrait::SymbolTable' trait. Returns nullptr if no valid symbol
299 /// was found.
301  StringAttr symbol) {
302  assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>());
303  Region &region = symbolTableOp->getRegion(0);
304  if (region.empty())
305  return nullptr;
306 
307  // Look for a symbol with the given name.
308  StringAttr symbolNameId = StringAttr::get(symbolTableOp->getContext(),
310  for (auto &op : region.front())
311  if (getNameIfSymbol(&op, symbolNameId) == symbol)
312  return &op;
313  return nullptr;
314 }
316  SymbolRefAttr symbol) {
317  SmallVector<Operation *, 4> resolvedSymbols;
318  if (failed(lookupSymbolIn(symbolTableOp, symbol, resolvedSymbols)))
319  return nullptr;
320  return resolvedSymbols.back();
321 }
322 
323 /// Internal implementation of `lookupSymbolIn` that allows for specialized
324 /// implementations of the lookup function.
326  Operation *symbolTableOp, SymbolRefAttr symbol,
328  function_ref<Operation *(Operation *, StringAttr)> lookupSymbolFn) {
329  assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>());
330 
331  // Lookup the root reference for this symbol.
332  symbolTableOp = lookupSymbolFn(symbolTableOp, symbol.getRootReference());
333  if (!symbolTableOp)
334  return failure();
335  symbols.push_back(symbolTableOp);
336 
337  // If there are no nested references, just return the root symbol directly.
338  ArrayRef<FlatSymbolRefAttr> nestedRefs = symbol.getNestedReferences();
339  if (nestedRefs.empty())
340  return success();
341 
342  // Verify that the root is also a symbol table.
343  if (!symbolTableOp->hasTrait<OpTrait::SymbolTable>())
344  return failure();
345 
346  // Otherwise, lookup each of the nested non-leaf references and ensure that
347  // each corresponds to a valid symbol table.
348  for (FlatSymbolRefAttr ref : nestedRefs.drop_back()) {
349  symbolTableOp = lookupSymbolFn(symbolTableOp, ref.getAttr());
350  if (!symbolTableOp || !symbolTableOp->hasTrait<OpTrait::SymbolTable>())
351  return failure();
352  symbols.push_back(symbolTableOp);
353  }
354  symbols.push_back(lookupSymbolFn(symbolTableOp, symbol.getLeafReference()));
355  return success(symbols.back());
356 }
357 
359 SymbolTable::lookupSymbolIn(Operation *symbolTableOp, SymbolRefAttr symbol,
360  SmallVectorImpl<Operation *> &symbols) {
361  auto lookupFn = [](Operation *symbolTableOp, StringAttr symbol) {
362  return lookupSymbolIn(symbolTableOp, symbol);
363  };
364  return lookupSymbolInImpl(symbolTableOp, symbol, symbols, lookupFn);
365 }
366 
367 /// Returns the operation registered with the given symbol name within the
368 /// closes parent operation with the 'OpTrait::SymbolTable' trait. Returns
369 /// nullptr if no valid symbol was found.
371  StringAttr symbol) {
372  Operation *symbolTableOp = getNearestSymbolTable(from);
373  return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
374 }
376  SymbolRefAttr symbol) {
377  Operation *symbolTableOp = getNearestSymbolTable(from);
378  return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
379 }
380 
381 raw_ostream &mlir::operator<<(raw_ostream &os,
382  SymbolTable::Visibility visibility) {
383  switch (visibility) {
385  return os << "public";
387  return os << "private";
389  return os << "nested";
390  }
391  llvm_unreachable("Unexpected visibility");
392 }
393 
394 //===----------------------------------------------------------------------===//
395 // SymbolTable Trait Types
396 //===----------------------------------------------------------------------===//
397 
399  if (op->getNumRegions() != 1)
400  return op->emitOpError()
401  << "Operations with a 'SymbolTable' must have exactly one region";
402  if (!llvm::hasSingleElement(op->getRegion(0)))
403  return op->emitOpError()
404  << "Operations with a 'SymbolTable' must have exactly one block";
405 
406  // Check that all symbols are uniquely named within child regions.
407  DenseMap<Attribute, Location> nameToOrigLoc;
408  for (auto &block : op->getRegion(0)) {
409  for (auto &op : block) {
410  // Check for a symbol name attribute.
411  auto nameAttr =
413  if (!nameAttr)
414  continue;
415 
416  // Try to insert this symbol into the table.
417  auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
418  if (!it.second)
419  return op.emitError()
420  .append("redefinition of symbol named '", nameAttr.getValue(), "'")
421  .attachNote(it.first->second)
422  .append("see existing symbol definition here");
423  }
424  }
425 
426  // Verify any nested symbol user operations.
427  SymbolTableCollection symbolTable;
428  auto verifySymbolUserFn = [&](Operation *op) -> Optional<WalkResult> {
429  if (SymbolUserOpInterface user = dyn_cast<SymbolUserOpInterface>(op))
430  return WalkResult(user.verifySymbolUses(symbolTable));
431  return WalkResult::advance();
432  };
433 
434  Optional<WalkResult> result =
435  walkSymbolTable(op->getRegions(), verifySymbolUserFn);
436  return success(result && !result->wasInterrupted());
437 }
438 
440  // Verify the name attribute.
441  if (!op->getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName()))
442  return op->emitOpError() << "requires string attribute '"
444 
445  // Verify the visibility attribute.
447  StringAttr visStrAttr = vis.dyn_cast<StringAttr>();
448  if (!visStrAttr)
449  return op->emitOpError() << "requires visibility attribute '"
451  << "' to be a string attribute, but got " << vis;
452 
453  if (!llvm::is_contained(ArrayRef<StringRef>{"public", "private", "nested"},
454  visStrAttr.getValue()))
455  return op->emitOpError()
456  << "visibility expected to be one of [\"public\", \"private\", "
457  "\"nested\"], but got "
458  << visStrAttr;
459  }
460  return success();
461 }
462 
463 //===----------------------------------------------------------------------===//
464 // Symbol Use Lists
465 //===----------------------------------------------------------------------===//
466 
467 /// Walk all of the symbol references within the given operation, invoking the
468 /// provided callback for each found use. The callbacks takes as arguments: the
469 /// use of the symbol, and the nested access chain to the attribute within the
470 /// operation dictionary. An access chain is a set of indices into nested
471 /// container attributes. For example, a symbol use in an attribute dictionary
472 /// that looks like the following:
473 ///
474 /// {use = [{other_attr, @symbol}]}
475 ///
476 /// May have the following access chain:
477 ///
478 /// [0, 0, 1]
479 ///
481  Operation *op,
483  // Check to see if the operation has any attributes.
484  DictionaryAttr attrDict = op->getAttrDictionary();
485  if (attrDict.empty())
486  return WalkResult::advance();
487 
488  // A worklist of a container attribute and the current index into the held
489  // attribute list.
490  struct WorklistItem {
491  SubElementAttrInterface container;
492  SmallVector<Attribute> immediateSubElements;
493 
494  explicit WorklistItem(SubElementAttrInterface container) {
495  SmallVector<Attribute> subElements;
496  container.walkImmediateSubElements(
497  [&](Attribute attr) { subElements.push_back(attr); }, [](Type) {});
498  immediateSubElements = std::move(subElements);
499  }
500  };
501 
502  SmallVector<WorklistItem, 1> attrWorklist(1, WorklistItem(attrDict));
503  SmallVector<int, 1> curAccessChain(1, /*Value=*/-1);
504 
505  // Process the symbol references within the given nested attribute range.
506  auto processAttrs = [&](int &index,
507  WorklistItem &worklistItem) -> WalkResult {
508  for (Attribute attr :
509  llvm::drop_begin(worklistItem.immediateSubElements, index)) {
510  /// Check for a nested container attribute, these will also need to be
511  /// walked.
512  if (auto interface = attr.dyn_cast<SubElementAttrInterface>()) {
513  attrWorklist.emplace_back(interface);
514  curAccessChain.push_back(-1);
515  return WalkResult::advance();
516  }
517 
518  // Invoke the provided callback if we find a symbol use and check for a
519  // requested interrupt.
520  if (auto symbolRef = attr.dyn_cast<SymbolRefAttr>())
521  if (callback({op, symbolRef}, curAccessChain).wasInterrupted())
522  return WalkResult::interrupt();
523 
524  // Make sure to keep the index counter in sync.
525  ++index;
526  }
527 
528  // Pop this container attribute from the worklist.
529  attrWorklist.pop_back();
530  curAccessChain.pop_back();
531  return WalkResult::advance();
532  };
533 
534  WalkResult result = WalkResult::advance();
535  do {
536  WorklistItem &item = attrWorklist.back();
537  int &index = curAccessChain.back();
538  ++index;
539 
540  // Process the given attribute, which is guaranteed to be a container.
541  result = processAttrs(index, item);
542  } while (!attrWorklist.empty() && !result.wasInterrupted());
543  return result;
544 }
545 
546 /// Walk all of the uses, for any symbol, that are nested within the given
547 /// regions, invoking the provided callback for each. This does not traverse
548 /// into any nested symbol tables.
550  MutableArrayRef<Region> regions,
552  return walkSymbolTable(regions, [&](Operation *op) -> Optional<WalkResult> {
553  // Check that this isn't a potentially unknown symbol table.
555  return llvm::None;
556 
557  return walkSymbolRefs(op, callback);
558  });
559 }
560 /// Walk all of the uses, for any symbol, that are nested within the given
561 /// operation 'from', invoking the provided callback for each. This does not
562 /// traverse into any nested symbol tables.
564  Operation *from,
566  // If this operation has regions, and it, as well as its dialect, isn't
567  // registered then conservatively fail. The operation may define a
568  // symbol table, so we can't opaquely know if we should traverse to find
569  // nested uses.
571  return llvm::None;
572 
573  // Walk the uses on this operation.
574  if (walkSymbolRefs(from, callback).wasInterrupted())
575  return WalkResult::interrupt();
576 
577  // Only recurse if this operation is not a symbol table. A symbol table
578  // defines a new scope, so we can't walk the attributes from within the symbol
579  // table op.
580  if (!from->hasTrait<OpTrait::SymbolTable>())
581  return walkSymbolUses(from->getRegions(), callback);
582  return WalkResult::advance();
583 }
584 
585 namespace {
586 /// This class represents a single symbol scope. A symbol scope represents the
587 /// set of operations nested within a symbol table that may reference symbols
588 /// within that table. A symbol scope does not contain the symbol table
589 /// operation itself, just its contained operations. A scope ends at leaf
590 /// operations or another symbol table operation.
591 struct SymbolScope {
592  /// Walk the symbol uses within this scope, invoking the given callback.
593  /// This variant is used when the callback type matches that expected by
594  /// 'walkSymbolUses'.
595  template <typename CallbackT,
596  typename std::enable_if_t<!std::is_same<
597  typename llvm::function_traits<CallbackT>::result_t,
598  void>::value> * = nullptr>
599  Optional<WalkResult> walk(CallbackT cback) {
600  if (Region *region = limit.dyn_cast<Region *>())
601  return walkSymbolUses(*region, cback);
602  return walkSymbolUses(limit.get<Operation *>(), cback);
603  }
604  /// This variant is used when the callback type matches a stripped down type:
605  /// void(SymbolTable::SymbolUse use)
606  template <typename CallbackT,
607  typename std::enable_if_t<std::is_same<
608  typename llvm::function_traits<CallbackT>::result_t,
609  void>::value> * = nullptr>
610  Optional<WalkResult> walk(CallbackT cback) {
611  return walk([=](SymbolTable::SymbolUse use, ArrayRef<int>) {
612  return cback(use), WalkResult::advance();
613  });
614  }
615 
616  /// The representation of the symbol within this scope.
617  SymbolRefAttr symbol;
618 
619  /// The IR unit representing this scope.
621 };
622 } // end anonymous namespace
623 
624 /// Collect all of the symbol scopes from 'symbol' to (inclusive) 'limit'.
625 static SmallVector<SymbolScope, 2> collectSymbolScopes(Operation *symbol,
626  Operation *limit) {
627  StringAttr symName = SymbolTable::getSymbolName(symbol);
628  assert(!symbol->hasTrait<OpTrait::SymbolTable>() || symbol != limit);
629 
630  // Compute the ancestors of 'limit'.
633  limitAncestors;
634  Operation *limitAncestor = limit;
635  do {
636  // Check to see if 'symbol' is an ancestor of 'limit'.
637  if (limitAncestor == symbol) {
638  // Check that the nearest symbol table is 'symbol's parent. SymbolRefAttr
639  // doesn't support parent references.
641  symbol->getParentOp())
642  return {{SymbolRefAttr::get(symName), limit}};
643  return {};
644  }
645 
646  limitAncestors.insert(limitAncestor);
647  } while ((limitAncestor = limitAncestor->getParentOp()));
648 
649  // Try to find the first ancestor of 'symbol' that is an ancestor of 'limit'.
650  Operation *commonAncestor = symbol->getParentOp();
651  do {
652  if (limitAncestors.count(commonAncestor))
653  break;
654  } while ((commonAncestor = commonAncestor->getParentOp()));
655  assert(commonAncestor && "'limit' and 'symbol' have no common ancestor");
656 
657  // Compute the set of valid nested references for 'symbol' as far up to the
658  // common ancestor as possible.
659  SmallVector<SymbolRefAttr, 2> references;
660  bool collectedAllReferences = succeeded(
661  collectValidReferencesFor(symbol, symName, commonAncestor, references));
662 
663  // Handle the case where the common ancestor is 'limit'.
664  if (commonAncestor == limit) {
665  SmallVector<SymbolScope, 2> scopes;
666 
667  // Walk each of the ancestors of 'symbol', calling the compute function for
668  // each one.
669  Operation *limitIt = symbol->getParentOp();
670  for (size_t i = 0, e = references.size(); i != e;
671  ++i, limitIt = limitIt->getParentOp()) {
672  assert(limitIt->hasTrait<OpTrait::SymbolTable>());
673  scopes.push_back({references[i], &limitIt->getRegion(0)});
674  }
675  return scopes;
676  }
677 
678  // Otherwise, we just need the symbol reference for 'symbol' that will be
679  // used within 'limit'. This is the last reference in the list we computed
680  // above if we were able to collect all references.
681  if (!collectedAllReferences)
682  return {};
683  return {{references.back(), limit}};
684 }
685 static SmallVector<SymbolScope, 2> collectSymbolScopes(Operation *symbol,
686  Region *limit) {
687  auto scopes = collectSymbolScopes(symbol, limit->getParentOp());
688 
689  // If we collected some scopes to walk, make sure to constrain the one for
690  // limit to the specific region requested.
691  if (!scopes.empty())
692  scopes.back().limit = limit;
693  return scopes;
694 }
695 template <typename IRUnit>
696 static SmallVector<SymbolScope, 1> collectSymbolScopes(StringAttr symbol,
697  IRUnit *limit) {
698  return {{SymbolRefAttr::get(symbol), limit}};
699 }
700 
701 /// Returns true if the given reference 'SubRef' is a sub reference of the
702 /// reference 'ref', i.e. 'ref' is a further qualified reference.
703 static bool isReferencePrefixOf(SymbolRefAttr subRef, SymbolRefAttr ref) {
704  if (ref == subRef)
705  return true;
706 
707  // If the references are not pointer equal, check to see if `subRef` is a
708  // prefix of `ref`.
709  if (ref.isa<FlatSymbolRefAttr>() ||
710  ref.getRootReference() != subRef.getRootReference())
711  return false;
712 
713  auto refLeafs = ref.getNestedReferences();
714  auto subRefLeafs = subRef.getNestedReferences();
715  return subRefLeafs.size() < refLeafs.size() &&
716  subRefLeafs == refLeafs.take_front(subRefLeafs.size());
717 }
718 
719 //===----------------------------------------------------------------------===//
720 // SymbolTable::getSymbolUses
721 
722 /// The implementation of SymbolTable::getSymbolUses below.
723 template <typename FromT>
725  std::vector<SymbolTable::SymbolUse> uses;
726  auto walkFn = [&](SymbolTable::SymbolUse symbolUse, ArrayRef<int>) {
727  uses.push_back(symbolUse);
728  return WalkResult::advance();
729  };
730  auto result = walkSymbolUses(from, walkFn);
731  return result ? Optional<SymbolTable::UseRange>(std::move(uses)) : llvm::None;
732 }
733 
734 /// Get an iterator range for all of the uses, for any symbol, that are nested
735 /// within the given operation 'from'. This does not traverse into any nested
736 /// symbol tables, and will also only return uses on 'from' if it does not
737 /// also define a symbol table. This is because we treat the region as the
738 /// boundary of the symbol table, and not the op itself. This function returns
739 /// None if there are any unknown operations that may potentially be symbol
740 /// tables.
742  return getSymbolUsesImpl(from);
743 }
746 }
747 
748 //===----------------------------------------------------------------------===//
749 // SymbolTable::getSymbolUses
750 
751 /// The implementation of SymbolTable::getSymbolUses below.
752 template <typename SymbolT, typename IRUnitT>
754  IRUnitT *limit) {
755  std::vector<SymbolTable::SymbolUse> uses;
756  for (SymbolScope &scope : collectSymbolScopes(symbol, limit)) {
757  if (!scope.walk([&](SymbolTable::SymbolUse symbolUse) {
758  if (isReferencePrefixOf(scope.symbol, symbolUse.getSymbolRef()))
759  uses.push_back(symbolUse);
760  }))
761  return llvm::None;
762  }
763  return SymbolTable::UseRange(std::move(uses));
764 }
765 
766 /// Get all of the uses of the given symbol that are nested within the given
767 /// operation 'from', invoking the provided callback for each. This does not
768 /// traverse into any nested symbol tables. This function returns None if there
769 /// are any unknown operations that may potentially be symbol tables.
770 auto SymbolTable::getSymbolUses(StringAttr symbol, Operation *from)
771  -> Optional<UseRange> {
772  return getSymbolUsesImpl(symbol, from);
773 }
775  -> Optional<UseRange> {
776  return getSymbolUsesImpl(symbol, from);
777 }
778 auto SymbolTable::getSymbolUses(StringAttr symbol, Region *from)
779  -> Optional<UseRange> {
780  return getSymbolUsesImpl(symbol, from);
781 }
783  -> Optional<UseRange> {
784  return getSymbolUsesImpl(symbol, from);
785 }
786 
787 //===----------------------------------------------------------------------===//
788 // SymbolTable::symbolKnownUseEmpty
789 
790 /// The implementation of SymbolTable::symbolKnownUseEmpty below.
791 template <typename SymbolT, typename IRUnitT>
792 static bool symbolKnownUseEmptyImpl(SymbolT symbol, IRUnitT *limit) {
793  for (SymbolScope &scope : collectSymbolScopes(symbol, limit)) {
794  // Walk all of the symbol uses looking for a reference to 'symbol'.
795  if (scope.walk([&](SymbolTable::SymbolUse symbolUse, ArrayRef<int>) {
796  return isReferencePrefixOf(scope.symbol, symbolUse.getSymbolRef())
797  ? WalkResult::interrupt()
798  : WalkResult::advance();
799  }) != WalkResult::advance())
800  return false;
801  }
802  return true;
803 }
804 
805 /// Return if the given symbol is known to have no uses that are nested within
806 /// the given operation 'from'. This does not traverse into any nested symbol
807 /// tables. This function will also return false if there are any unknown
808 /// operations that may potentially be symbol tables.
809 bool SymbolTable::symbolKnownUseEmpty(StringAttr symbol, Operation *from) {
810  return symbolKnownUseEmptyImpl(symbol, from);
811 }
813  return symbolKnownUseEmptyImpl(symbol, from);
814 }
815 bool SymbolTable::symbolKnownUseEmpty(StringAttr symbol, Region *from) {
816  return symbolKnownUseEmptyImpl(symbol, from);
817 }
819  return symbolKnownUseEmptyImpl(symbol, from);
820 }
821 
822 //===----------------------------------------------------------------------===//
823 // SymbolTable::replaceAllSymbolUses
824 
825 /// Rebuild the given attribute container after replacing all references to a
826 /// symbol with the updated attribute in 'accesses'.
827 static SubElementAttrInterface rebuildAttrAfterRAUW(
828  SubElementAttrInterface container,
829  ArrayRef<std::pair<SmallVector<int, 1>, SymbolRefAttr>> accesses,
830  unsigned depth) {
831  // Given a range of Attributes, update the ones referred to by the given
832  // access chains to point to the new symbol attribute.
833 
834  SmallVector<std::pair<size_t, Attribute>> replacements;
835 
836  SmallVector<Attribute> subElements;
837  container.walkImmediateSubElements(
838  [&](Attribute attribute) { subElements.push_back(attribute); },
839  [](Type) {});
840  for (unsigned i = 0, e = accesses.size(); i != e;) {
841  ArrayRef<int> access = accesses[i].first;
842 
843  // Check to see if this is a leaf access, i.e. a SymbolRef.
844  if (access.size() == depth + 1) {
845  replacements.emplace_back(access.back(), accesses[i].second);
846  ++i;
847  continue;
848  }
849 
850  // Otherwise, this is a container. Collect all of the accesses for this
851  // index and recurse. The recursion here is bounded by the size of the
852  // largest access array.
853  auto nestedAccesses = accesses.drop_front(i).take_while([&](auto &it) {
854  ArrayRef<int> nextAccess = it.first;
855  return nextAccess.size() > depth + 1 &&
856  nextAccess[depth] == access[depth];
857  });
858  auto result = rebuildAttrAfterRAUW(subElements[access[depth]],
859  nestedAccesses, depth + 1);
860  replacements.emplace_back(access[depth], result);
861 
862  // Skip over all of the accesses that refer to the nested container.
863  i += nestedAccesses.size();
864  }
865 
866  return container.replaceImmediateSubAttribute(replacements);
867 }
868 
869 /// Generates a new symbol reference attribute with a new leaf reference.
870 static SymbolRefAttr generateNewRefAttr(SymbolRefAttr oldAttr,
871  FlatSymbolRefAttr newLeafAttr) {
872  if (oldAttr.isa<FlatSymbolRefAttr>())
873  return newLeafAttr;
874  auto nestedRefs = llvm::to_vector<2>(oldAttr.getNestedReferences());
875  nestedRefs.back() = newLeafAttr;
876  return SymbolRefAttr::get(oldAttr.getRootReference(), nestedRefs);
877 }
878 
879 /// The implementation of SymbolTable::replaceAllSymbolUses below.
880 template <typename SymbolT, typename IRUnitT>
881 static LogicalResult
882 replaceAllSymbolUsesImpl(SymbolT symbol, StringAttr newSymbol, IRUnitT *limit) {
883  // A collection of operations along with their new attribute dictionary.
884  std::vector<std::pair<Operation *, DictionaryAttr>> updatedAttrDicts;
885 
886  // The current operation being processed.
887  Operation *curOp = nullptr;
888 
889  // The set of access chains into the attribute dictionary of the current
890  // operation, as well as the replacement attribute to use.
891  SmallVector<std::pair<SmallVector<int, 1>, SymbolRefAttr>, 1> accessChains;
892 
893  // Generate a new attribute dictionary for the current operation by replacing
894  // references to the old symbol.
895  auto generateNewAttrDict = [&] {
896  auto oldDict = curOp->getAttrDictionary();
897  auto newDict = rebuildAttrAfterRAUW(oldDict, accessChains, /*depth=*/0);
898  return newDict.cast<DictionaryAttr>();
899  };
900 
901  // Generate a new attribute to replace the given attribute.
902  FlatSymbolRefAttr newLeafAttr = FlatSymbolRefAttr::get(newSymbol);
903  for (SymbolScope &scope : collectSymbolScopes(symbol, limit)) {
904  SymbolRefAttr newAttr = generateNewRefAttr(scope.symbol, newLeafAttr);
905  auto walkFn = [&](SymbolTable::SymbolUse symbolUse,
906  ArrayRef<int> accessChain) {
907  SymbolRefAttr useRef = symbolUse.getSymbolRef();
908  if (!isReferencePrefixOf(scope.symbol, useRef))
909  return WalkResult::advance();
910 
911  // If we have a valid match, check to see if this is a proper
912  // subreference. If it is, then we will need to generate a different new
913  // attribute specifically for this use.
914  SymbolRefAttr replacementRef = newAttr;
915  if (useRef != scope.symbol) {
916  if (scope.symbol.isa<FlatSymbolRefAttr>()) {
917  replacementRef =
918  SymbolRefAttr::get(newSymbol, useRef.getNestedReferences());
919  } else {
920  auto nestedRefs = llvm::to_vector<4>(useRef.getNestedReferences());
921  nestedRefs[scope.symbol.getNestedReferences().size() - 1] =
922  newLeafAttr;
923  replacementRef =
924  SymbolRefAttr::get(useRef.getRootReference(), nestedRefs);
925  }
926  }
927 
928  // If there was a previous operation, generate a new attribute dict
929  // for it. This means that we've finished processing the current
930  // operation, so generate a new dictionary for it.
931  if (curOp && symbolUse.getUser() != curOp) {
932  updatedAttrDicts.push_back({curOp, generateNewAttrDict()});
933  accessChains.clear();
934  }
935 
936  // Record this access.
937  curOp = symbolUse.getUser();
938  accessChains.push_back({llvm::to_vector<1>(accessChain), replacementRef});
939  return WalkResult::advance();
940  };
941  if (!scope.walk(walkFn))
942  return failure();
943 
944  // Check to see if we have a dangling op that needs to be processed.
945  if (curOp) {
946  updatedAttrDicts.push_back({curOp, generateNewAttrDict()});
947  curOp = nullptr;
948  }
949  }
950 
951  // Update the attribute dictionaries as necessary.
952  for (auto &it : updatedAttrDicts)
953  it.first->setAttrs(it.second);
954  return success();
955 }
956 
957 /// Attempt to replace all uses of the given symbol 'oldSymbol' with the
958 /// provided symbol 'newSymbol' that are nested within the given operation
959 /// 'from'. This does not traverse into any nested symbol tables. If there are
960 /// any unknown operations that may potentially be symbol tables, no uses are
961 /// replaced and failure is returned.
963  StringAttr newSymbol,
964  Operation *from) {
965  return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from);
966 }
968  StringAttr newSymbol,
969  Operation *from) {
970  return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from);
971 }
973  StringAttr newSymbol,
974  Region *from) {
975  return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from);
976 }
978  StringAttr newSymbol,
979  Region *from) {
980  return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from);
981 }
982 
983 //===----------------------------------------------------------------------===//
984 // SymbolTableCollection
985 //===----------------------------------------------------------------------===//
986 
988  StringAttr symbol) {
989  return getSymbolTable(symbolTableOp).lookup(symbol);
990 }
992  SymbolRefAttr name) {
994  if (failed(lookupSymbolIn(symbolTableOp, name, symbols)))
995  return nullptr;
996  return symbols.back();
997 }
998 /// A variant of 'lookupSymbolIn' that returns all of the symbols referenced by
999 /// a given SymbolRefAttr. Returns failure if any of the nested references could
1000 /// not be resolved.
1003  SymbolRefAttr name,
1004  SmallVectorImpl<Operation *> &symbols) {
1005  auto lookupFn = [this](Operation *symbolTableOp, StringAttr symbol) {
1006  return lookupSymbolIn(symbolTableOp, symbol);
1007  };
1008  return lookupSymbolInImpl(symbolTableOp, name, symbols, lookupFn);
1009 }
1010 
1011 /// Returns the operation registered with the given symbol name within the
1012 /// closest parent operation of, or including, 'from' with the
1013 /// 'OpTrait::SymbolTable' trait. Returns nullptr if no valid symbol was
1014 /// found.
1016  StringAttr symbol) {
1017  Operation *symbolTableOp = SymbolTable::getNearestSymbolTable(from);
1018  return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
1019 }
1020 Operation *
1022  SymbolRefAttr symbol) {
1023  Operation *symbolTableOp = SymbolTable::getNearestSymbolTable(from);
1024  return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
1025 }
1026 
1027 /// Lookup, or create, a symbol table for an operation.
1029  auto it = symbolTables.try_emplace(op, nullptr);
1030  if (it.second)
1031  it.first->second = std::make_unique<SymbolTable>(op);
1032  return *it.first->second;
1033 }
1034 
1035 //===----------------------------------------------------------------------===//
1036 // SymbolUserMap
1037 //===----------------------------------------------------------------------===//
1038 
1040  Operation *symbolTableOp)
1041  : symbolTable(symbolTable) {
1042  // Walk each of the symbol tables looking for discardable callgraph nodes.
1043  SmallVector<Operation *> symbols;
1044  auto walkFn = [&](Operation *symbolTableOp, bool allUsesVisible) {
1045  for (Operation &nestedOp : symbolTableOp->getRegion(0).getOps()) {
1046  auto symbolUses = SymbolTable::getSymbolUses(&nestedOp);
1047  assert(symbolUses && "expected uses to be valid");
1048 
1049  for (const SymbolTable::SymbolUse &use : *symbolUses) {
1050  symbols.clear();
1051  (void)symbolTable.lookupSymbolIn(symbolTableOp, use.getSymbolRef(),
1052  symbols);
1053  for (Operation *symbolOp : symbols)
1054  symbolToUsers[symbolOp].insert(use.getUser());
1055  }
1056  }
1057  };
1058  // We just set `allSymUsesVisible` to false here because it isn't necessary
1059  // for building the user map.
1060  SymbolTable::walkSymbolTables(symbolTableOp, /*allSymUsesVisible=*/false,
1061  walkFn);
1062 }
1063 
1065  StringAttr newSymbolName) {
1066  auto it = symbolToUsers.find(symbol);
1067  if (it == symbolToUsers.end())
1068  return;
1069  SetVector<Operation *> &users = it->second;
1070 
1071  // Replace the uses within the users of `symbol`.
1072  for (Operation *user : users)
1073  (void)SymbolTable::replaceAllSymbolUses(symbol, newSymbolName, user);
1074 
1075  // Move the current users of `symbol` to the new symbol if it is in the
1076  // symbol table.
1077  Operation *newSymbol =
1078  symbolTable.lookupSymbolIn(symbol->getParentOp(), newSymbolName);
1079  if (newSymbol != symbol) {
1080  // Transfer over the users to the new symbol.
1081  auto newIt = symbolToUsers.find(newSymbol);
1082  if (newIt == symbolToUsers.end())
1083  symbolToUsers.try_emplace(newSymbol, std::move(users));
1084  else
1085  newIt->second.set_union(users);
1086  symbolToUsers.erase(symbol);
1087  }
1088 }
1089 
1090 //===----------------------------------------------------------------------===//
1091 // Visibility parsing implementation.
1092 //===----------------------------------------------------------------------===//
1093 
1095  NamedAttrList &attrs) {
1096  StringRef visibility;
1097  if (parser.parseOptionalKeyword(&visibility, {"public", "private", "nested"}))
1098  return failure();
1099 
1100  StringAttr visibilityAttr = parser.getBuilder().getStringAttr(visibility);
1101  attrs.push_back(parser.getBuilder().getNamedAttr(
1102  SymbolTable::getVisibilityAttrName(), visibilityAttr));
1103  return success();
1104 }
1105 
1106 //===----------------------------------------------------------------------===//
1107 // Symbol Interfaces
1108 //===----------------------------------------------------------------------===//
1109 
1110 /// Include the generated symbol interfaces.
1111 #include "mlir/IR/SymbolInterfaces.cpp.inc"
static SymbolRefAttr generateNewRefAttr(SymbolRefAttr oldAttr, FlatSymbolRefAttr newLeafAttr)
Generates a new symbol reference attribute with a new leaf reference.
Include the generated interface declarations.
static StringAttr getSymbolName(Operation *symbol)
Returns the name of the given symbol operation, aborting if no symbol is present. ...
This class contains a list of basic blocks and a link to the parent operation it is attached to...
Definition: Region.h:26
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition: SymbolTable.h:55
Operation * getUser() const
Return the operation user of this symbol reference.
Definition: SymbolTable.h:150
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition: Operation.h:423
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
Definition: Operation.h:145
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition: Operation.h:420
static Operation * lookupSymbolIn(Operation *op, StringAttr symbol)
Returns the operation registered with the given symbol name with the regions of &#39;symbolTableOp&#39;.
Block represents an ordered list of Operations.
Definition: Block.h:29
Block & front()
Definition: Region.h:65
A symbol reference with a reference path containing a single element.
static Visibility getSymbolVisibility(Operation *symbol)
Returns the visibility of the given symbol operation.
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: Visitors.h:55
static WalkResult walkSymbolRefs(Operation *op, function_ref< WalkResult(SymbolTable::SymbolUse, ArrayRef< int >)> callback)
Walk all of the symbol references within the given operation, invoking the provided callback for each...
static Optional< UseRange > getSymbolUses(Operation *from)
Get an iterator range for all of the uses, for any symbol, that are nested within the given operation...
AttrClass getAttrOfType(StringAttr name)
Definition: Operation.h:327
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
static StringRef getVisibilityAttrName()
Return the name of the attribute used for symbol visibility.
Definition: SymbolTable.h:61
static SubElementAttrInterface rebuildAttrAfterRAUW(SubElementAttrInterface container, ArrayRef< std::pair< SmallVector< int, 1 >, SymbolRefAttr >> accesses, unsigned depth)
Rebuild the given attribute container after replacing all references to a symbol with the updated att...
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
Definition: LogicalResult.h:68
The symbol is public and may be referenced anywhere internal or external to the visible references in...
The OpAsmParser has methods for interacting with the asm parser: parsing things from it...
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
NamedAttribute getNamedAttr(StringRef name, Attribute val)
Definition: Builders.cpp:85
static bool isPotentiallyUnknownSymbolTable(Operation *op)
Return true if the given operation is unknown and may potentially define a symbol table...
Definition: SymbolTable.cpp:21
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Definition: AliasAnalysis.h:78
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
void erase(Operation *symbol)
Erase the given symbol from the table.
This class implements a range of SymbolRef uses.
Definition: SymbolTable.h:164
static bool symbolKnownUseEmptyImpl(SymbolT symbol, IRUnitT *limit)
The implementation of SymbolTable::symbolKnownUseEmpty below.
static constexpr const bool value
void erase()
Remove this operation from its parent block and delete it.
Definition: Operation.cpp:424
StringAttr insert(Operation *symbol, Block::iterator insertPt={})
Insert a new symbol into the table, and rename it as necessary to avoid collisions.
Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of...
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:99
The symbol is visible to the current IR, which may include operations in symbol tables above the one ...
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
Visibility
An enumeration detailing the different visibility types that a symbol may have.
Definition: SymbolTable.h:69
static void setSymbolName(Operation *symbol, StringAttr name)
Sets the name of the given symbol operation.
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
static SmallVector< SymbolScope, 2 > collectSymbolScopes(Operation *symbol, Operation *limit)
Collect all of the symbol scopes from &#39;symbol&#39; to (inclusive) &#39;limit&#39;.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
This class represents a collection of SymbolTables.
Definition: SymbolTable.h:242
OpListType::iterator iterator
Definition: Block.h:132
iterator_range< OpIterator > getOps()
Definition: Region.h:166
bool empty()
Definition: Region.h:60
static LogicalResult lookupSymbolInImpl(Operation *symbolTableOp, SymbolRefAttr symbol, SmallVectorImpl< Operation *> &symbols, function_ref< Operation *(Operation *, StringAttr)> lookupSymbolFn)
Internal implementation of lookupSymbolIn that allows for specialized implementations of the lookup f...
static bool symbolKnownUseEmpty(StringAttr symbol, Operation *from)
Return if the given symbol is known to have no uses that are nested within the given operation &#39;from&#39;...
Attributes are known-constant values of operations.
Definition: Attributes.h:27
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition: Operation.h:470
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:117
Attribute removeAttr(StringAttr name)
Remove the attribute with the specified name if it exists.
Definition: Operation.h:359
static Optional< WalkResult > walkSymbolUses(MutableArrayRef< Region > regions, function_ref< WalkResult(SymbolTable::SymbolUse, ArrayRef< int >)> callback)
Walk all of the uses, for any symbol, that are nested within the given regions, invoking the provided...
SymbolTable & getSymbolTable(Operation *op)
Lookup, or create, a symbol table for an operation.
A trait used to provide symbol table functionalities to a region operation.
Definition: SymbolTable.h:338
SymbolUserMap(SymbolTableCollection &symbolTable, Operation *symbolTableOp)
Build a user map for all of the symbols defined in regions nested under &#39;symbolTableOp&#39;.
SymbolRefAttr getSymbolRef() const
Return the symbol reference that this use represents.
Definition: SymbolTable.h:153
static WalkResult advance()
Definition: Visitors.h:51
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:106
void replaceAllUsesWith(Operation *symbol, StringAttr newSymbolName)
Replace all of the uses of the given symbol with newSymbolName.
static WalkResult interrupt()
Definition: Visitors.h:50
A utility result that is used to signal how to proceed with an ongoing walk:
Definition: Visitors.h:34
static void walkSymbolTables(Operation *op, bool allSymUsesVisible, function_ref< void(Operation *, bool)> callback)
Walks all symbol table operations nested within, and including, op.
ParseResult parseOptionalVisibilityKeyword(OpAsmParser &parser, NamedAttrList &attrs)
Parse an optional visibility attribute keyword (i.e., public, private, or nested) without quotes in a...
The symbol is private and may only be referenced by SymbolRefAttrs local to the operations within the...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:72
DictionaryAttr getAttrDictionary()
Return all of the attributes on this operation as a DictionaryAttr.
Definition: Operation.h:311
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of...
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition: Region.h:194
static StringAttr getNameIfSymbol(Operation *op)
Returns the string name of the given symbol, or null if this is not a symbol.
Definition: SymbolTable.cpp:27
LogicalResult verifySymbolTable(Operation *op)
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
Definition: Operation.h:347
static void setSymbolVisibility(Operation *symbol, Visibility vis)
Sets the visibility of the given symbol operation.
static LogicalResult replaceAllSymbolUsesImpl(SymbolT symbol, StringAttr newSymbol, IRUnitT *limit)
The implementation of SymbolTable::replaceAllSymbolUses below.
static bool isReferencePrefixOf(SymbolRefAttr subRef, SymbolRefAttr ref)
Returns true if the given reference &#39;SubRef&#39; is a sub reference of the reference &#39;ref&#39;, i.e.
Operation * lookup(StringRef name) const
Look up a symbol with the specified name, returning null if no such name exists.
void walk(Operation *op, function_ref< void(Region *)> callback, WalkOrder order)
Walk all of the regions, blocks, or operations nested under (and including) the given operation...
Definition: Visitors.cpp:21
static Optional< WalkResult > walkSymbolTable(MutableArrayRef< Region > regions, function_ref< Optional< WalkResult >(Operation *)> callback)
Walk all of the operations within the given set of regions, without traversing into any nested symbol...
Definition: SymbolTable.cpp:80
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
LogicalResult verifySymbol(Operation *op)
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Definition: Operation.h:103
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:55
SymbolTable(Operation *symbolTableOp)
Build a symbol table with the symbols within the given operation.
Operation * lookupSymbolIn(Operation *symbolTableOp, StringAttr symbol)
Look up a symbol with the specified name within the specified symbol table operation, returning null if no such name exists.
This class allows for representing and managing the symbol table used by operations with the &#39;SymbolT...
Definition: SymbolTable.h:23
InFlightDiagnostic & append(Args &&... args) &
Append arguments to the diagnostic.
Definition: Diagnostics.h:322
static Operation * getNearestSymbolTable(Operation *from)
Returns the nearest symbol table from a given operation from.
static LogicalResult collectValidReferencesFor(Operation *symbol, StringAttr symbolName, Operation *within, SmallVectorImpl< SymbolRefAttr > &results)
Computes the nested symbol reference attribute for the symbol &#39;symbolName&#39; that are usable within the...
Definition: SymbolTable.cpp:39
static LogicalResult replaceAllSymbolUses(StringAttr oldSymbol, StringAttr newSymbol, Operation *from)
Attempt to replace all uses of the given symbol &#39;oldSymbol&#39; with the provided symbol &#39;newSymbol&#39; that...
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "&#39;dim&#39; op " which is convenient for verifiers...
Definition: Operation.cpp:518
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:231
This class represents success/failure for operation parsing.
Definition: OpDefinition.h:36
This class represents a specific symbol use.
Definition: SymbolTable.h:144
void setAttrs(DictionaryAttr newAttrs)
Set the attribute dictionary on this operation.
Definition: Operation.h:314
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
Definition: Operation.h:323
StringAttr getStringAttr(const Twine &bytes)
Definition: Builders.cpp:205
static Optional< SymbolTable::UseRange > getSymbolUsesImpl(FromT from)
The implementation of SymbolTable::getSymbolUses below.
Region & getRegion(unsigned index)
Returns the region held by this operation at position &#39;index&#39;.
Definition: Operation.h:429