38#include <llvm/ADT/SmallPtrSet.h>
50static bool isPotentiallyUnknownSymbolTable(Operation *op) {
51 return op->getNumRegions() == 1 && !op->getDialect();
55static StringAttr getNameIfSymbol(Operation *op, StringAttr symbolAttrNameId) {
56 return op->getAttrOfType<StringAttr>(symbolAttrNameId);
63static LogicalResult collectValidReferencesFor(
64 Operation *symbol, StringAttr symbolName, Operation *within,
65 SmallVectorImpl<SymbolRefAttr> &results
67 assert(within->isAncestor(symbol) &&
"expected 'within' to be an ancestor");
68 MLIRContext *ctx = symbol->getContext();
70 auto leafRef = FlatSymbolRefAttr::get(symbolName);
71 results.push_back(leafRef);
74 Operation *symbolTableOp = symbol->getParentOp();
75 if (within == symbolTableOp) {
80 SmallVector<FlatSymbolRefAttr, 1> nestedRefs(1, leafRef);
81 StringAttr symbolNameId = StringAttr::get(ctx, SymbolTable::getSymbolAttrName());
84 if (!symbolTableOp->hasTrait<OpTrait::SymbolTable>()) {
88 StringAttr symbolTableName = getNameIfSymbol(symbolTableOp, symbolNameId);
89 if (!symbolTableName) {
92 results.push_back(SymbolRefAttr::get(symbolTableName, nestedRefs));
94 symbolTableOp = symbolTableOp->getParentOp();
95 if (symbolTableOp == within) {
98 nestedRefs.insert(nestedRefs.begin(), FlatSymbolRefAttr::get(symbolTableName));
106static std::optional<WalkResult> walkSymbolTable(
107 MutableArrayRef<Region> regions, function_ref<std::optional<WalkResult>(Operation *)> callback
109 SmallVector<Region *, 1> worklist(llvm::make_pointer_range(regions));
110 while (!worklist.empty()) {
111 for (Operation &op : worklist.pop_back_val()->getOps()) {
112 std::optional<WalkResult> result = callback(&op);
113 if (result != WalkResult::advance()) {
119 if (!op.hasTrait<OpTrait::SymbolTable>()) {
120 for (Region ®ion : op.getRegions()) {
121 worklist.push_back(®ion);
126 return WalkResult::advance();
132walkSymbolRefs(Operation *op, function_ref<WalkResult(SymbolTable::SymbolUse)> callback) {
134 auto walkFn = [&op, &callback](SymbolRefAttr symbolRef) {
135 if (callback({op, symbolRef}).wasInterrupted()) {
136 return WalkResult::interrupt();
138 return WalkResult::skip();
140 for (Type t : op->getOperandTypes()) {
141 if (t.walk<WalkOrder::PreOrder>(walkFn).wasInterrupted()) {
142 return WalkResult::interrupt();
145 for (Type t : op->getResultTypes()) {
146 if (t.walk<WalkOrder::PreOrder>(walkFn).wasInterrupted()) {
147 return WalkResult::interrupt();
150 return op->getAttrDictionary().walk<WalkOrder::PreOrder>(walkFn);
156static std::optional<WalkResult> walkSymbolUses(
157 MutableArrayRef<Region> regions, function_ref<WalkResult(SymbolTable::SymbolUse)> callback
159 return walkSymbolTable(regions, [&](Operation *op) -> std::optional<WalkResult> {
161 if (isPotentiallyUnknownSymbolTable(op)) {
164 return walkSymbolRefs(op, callback);
171static std::optional<WalkResult>
172walkSymbolUses(Operation *
from, function_ref<WalkResult(SymbolTable::SymbolUse)> callback) {
177 if (isPotentiallyUnknownSymbolTable(
from)) {
182 if (walkSymbolRefs(
from, callback).wasInterrupted()) {
183 return WalkResult::interrupt();
189 if (!
from->hasTrait<OpTrait::SymbolTable>()) {
190 return walkSymbolUses(
from->getRegions(), callback);
192 return WalkResult::advance();
206 std::enable_if_t<!std::is_same<
207 typename llvm::function_traits<CallbackT>::result_t,
void>::value> * =
nullptr>
208 std::optional<WalkResult> walk(CallbackT cback) {
209 if (Region *region = llvm::dyn_cast_if_present<Region *>(limit)) {
210 return walkSymbolUses(*region, cback);
212 return walkSymbolUses(llvm::cast<Operation *>(limit), cback);
218 std::enable_if_t<std::is_same<
219 typename llvm::function_traits<CallbackT>::result_t,
void>::value> * =
nullptr>
220 std::optional<WalkResult> walk(CallbackT cback) {
221 return walk([=](SymbolTable::SymbolUse
use) {
return cback(
use), WalkResult::advance(); });
226 template <
typename CallbackT>
228 std::optional<WalkResult> walkSymbolTable(CallbackT &&cback) {
229 if (Region *region = llvm::dyn_cast_if_present<Region *>(limit)) {
230 return ::walkSymbolTable(*region, cback);
232 return ::walkSymbolTable(llvm::cast<Operation *>(limit), cback);
236 SymbolRefAttr symbol;
239 llvm::PointerUnion<Operation *, Region *> limit;
243static SmallVector<SymbolScope, 2> collectSymbolScopes(Operation *symbol, Operation *limit) {
244 StringAttr symName = SymbolTable::getSymbolName(symbol);
245 assert(!symbol->hasTrait<OpTrait::SymbolTable>() || symbol != limit);
248 SetVector<Operation *, SmallVector<Operation *, 4>, SmallPtrSet<Operation *, 4>> limitAncestors;
249 Operation *limitAncestor = limit;
252 if (limitAncestor == symbol) {
255 if (SymbolTable::getNearestSymbolTable(limit->getParentOp()) == symbol->getParentOp()) {
256 return {{SymbolRefAttr::get(symName), limit}};
261 limitAncestors.insert(limitAncestor);
262 }
while ((limitAncestor = limitAncestor->getParentOp()));
265 Operation *commonAncestor = symbol->getParentOp();
267 if (limitAncestors.count(commonAncestor)) {
270 }
while ((commonAncestor = commonAncestor->getParentOp()));
271 assert(commonAncestor &&
"'limit' and 'symbol' have no common ancestor");
275 SmallVector<SymbolRefAttr, 2> references;
276 bool collectedAllReferences =
277 succeeded(collectValidReferencesFor(symbol, symName, commonAncestor, references));
280 if (commonAncestor == limit) {
281 SmallVector<SymbolScope, 2> scopes;
285 Operation *limitIt = symbol->getParentOp();
286 for (
size_t i = 0, e = references.size(); i != e; ++i, limitIt = limitIt->getParentOp()) {
287 assert(limitIt->hasTrait<OpTrait::SymbolTable>());
288 scopes.push_back({references[i], &limitIt->getRegion(0)});
296 if (!collectedAllReferences) {
299 return {{references.back(), limit}};
302static SmallVector<SymbolScope, 2> collectSymbolScopes(Operation *symbol, Region *limit) {
303 auto scopes = collectSymbolScopes(symbol, limit->getParentOp());
307 if (!scopes.empty()) {
308 scopes.back().limit = limit;
313static SmallVector<SymbolScope, 1> collectSymbolScopes(StringAttr symbol, Region *limit) {
314 return {{SymbolRefAttr::get(symbol), limit}};
317static SmallVector<SymbolScope, 1> collectSymbolScopes(StringAttr symbol, Operation *limit) {
318 SmallVector<SymbolScope, 1> scopes;
319 auto symbolRef = SymbolRefAttr::get(symbol);
320 for (
auto ®ion : limit->getRegions()) {
321 scopes.push_back({symbolRef, ®ion});
328static bool isReferencePrefixOf(SymbolRefAttr subRef, SymbolRefAttr ref) {
335 if (llvm::isa<FlatSymbolRefAttr>(ref) || ref.getRootReference() != subRef.getRootReference()) {
339 auto refLeafs = ref.getNestedReferences();
340 auto subRefLeafs = subRef.getNestedReferences();
341 return subRefLeafs.size() < refLeafs.size() &&
342 subRefLeafs == refLeafs.take_front(subRefLeafs.size());
353template <
typename FromT>
354static std::optional<SymbolTable::UseRange> getSymbolUsesImpl(FromT
from) {
355 std::vector<SymbolTable::SymbolUse> uses;
356 auto walkFn = [&](SymbolTable::SymbolUse symbolUse) {
357 uses.push_back(symbolUse);
358 return WalkResult::advance();
360 auto result = walkSymbolUses(
from, walkFn);
361 return result ? std::optional<SymbolTable::UseRange>(std::move(uses)) : std::nullopt;
374 return getSymbolUsesImpl(
from);
377 return getSymbolUsesImpl(MutableArrayRef<Region>(*
from));
386template <
typename SymbolT,
typename IRUnitT>
387static std::optional<SymbolTable::UseRange> getSymbolUsesImpl(SymbolT symbol, IRUnitT *limit) {
388 std::vector<SymbolTable::SymbolUse> uses;
389 for (SymbolScope &scope : collectSymbolScopes(symbol, limit)) {
390 if (!scope.walk([&](SymbolTable::SymbolUse symbolUse) {
391 if (isReferencePrefixOf(scope.symbol, symbolUse.getSymbolRef())) {
392 uses.push_back(symbolUse);
398 return SymbolTable::UseRange(std::move(uses));
408 return getSymbolUsesImpl(symbol,
from);
411 return getSymbolUsesImpl(symbol,
from);
414 return getSymbolUsesImpl(symbol,
from);
417 return getSymbolUsesImpl(symbol,
from);
424 t.walk([&symbolsUsed](SymbolRefAttr symbolRef) { symbolsUsed.insert(symbolRef); });
428 for (Type t : types) {
434 llvm::SmallDenseSet<SymbolRefAttr> symbolsUsed;
440 llvm::SmallDenseSet<SymbolRefAttr> symbolsUsed;
451template <
typename SymbolT,
typename IRUnitT>
452static bool symbolKnownUseEmptyImpl(SymbolT symbol, IRUnitT *limit) {
453 for (SymbolScope &scope : collectSymbolScopes(symbol, limit)) {
455 if (scope.walk([&](SymbolTable::SymbolUse symbolUse) {
456 return isReferencePrefixOf(scope.symbol, symbolUse.getSymbolRef()) ? WalkResult::interrupt()
457 : WalkResult::advance();
458 }) != WalkResult::advance()) {
472 return symbolKnownUseEmptyImpl(symbol,
from);
475 return symbolKnownUseEmptyImpl(symbol,
from);
478 return symbolKnownUseEmptyImpl(symbol,
from);
481 return symbolKnownUseEmptyImpl(symbol,
from);
492 return op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the whether in Source or Object that is based or other modifications as a an original work of authorship For the purposes of this Derivative Works shall not include works that remain separable from
std::optional< mlir::SymbolTable::UseRange > getSymbolUses(mlir::Operation *from)
Get an iterator range for all of the uses, for any symbol, that are nested within the given operation...
mlir::StringAttr getSymbolName(mlir::Operation *symbol)
Returns the name of the given symbol operation, or nullptr if no symbol is present.
void getSymbolsUsedIn(mlir::Type t, llvm::SmallDenseSet< mlir::SymbolRefAttr > &symbolsUsed)
Add all symbols used within the given Type to the provided set.
bool symbolKnownUseEmpty(mlir::StringAttr symbol, mlir::Operation *from)
Return if the given symbol is known to have no uses that are nested within the given operation 'from'...