1927b7074SRiver Riddle //===- SymbolTable.cpp - MLIR Symbol Table Class --------------------------===// 2927b7074SRiver Riddle // 356222a06SMehdi Amini // Part of the MLIR 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" 10*6fca03f0SRiver Riddle #include "llvm/ADT/SetVector.h" 11*6fca03f0SRiver Riddle #include "llvm/ADT/SmallPtrSet.h" 12ee8e8b55SRiver Riddle #include "llvm/ADT/SmallString.h" 13927b7074SRiver Riddle 14927b7074SRiver Riddle using namespace mlir; 15927b7074SRiver Riddle 16b3a6ae83SRiver Riddle /// Return true if the given operation is unknown and may potentially define a 17b3a6ae83SRiver Riddle /// symbol table. 18b3a6ae83SRiver Riddle static bool isPotentiallyUnknownSymbolTable(Operation *op) { 19b3a6ae83SRiver Riddle return !op->getDialect() && op->getNumRegions() == 1; 20b3a6ae83SRiver Riddle } 21b3a6ae83SRiver Riddle 22*6fca03f0SRiver Riddle /// Returns the nearest symbol table from a given operation `from`. Returns 23*6fca03f0SRiver Riddle /// nullptr if no valid parent symbol table could be found. 24*6fca03f0SRiver Riddle static Operation *getNearestSymbolTable(Operation *from) { 25*6fca03f0SRiver Riddle assert(from && "expected valid operation"); 26*6fca03f0SRiver Riddle if (isPotentiallyUnknownSymbolTable(from)) 27*6fca03f0SRiver Riddle return nullptr; 28*6fca03f0SRiver Riddle 29*6fca03f0SRiver Riddle while (!from->hasTrait<OpTrait::SymbolTable>()) { 30*6fca03f0SRiver Riddle from = from->getParentOp(); 31*6fca03f0SRiver Riddle 32*6fca03f0SRiver Riddle // Check that this is a valid op and isn't an unknown symbol table. 33*6fca03f0SRiver Riddle if (!from || isPotentiallyUnknownSymbolTable(from)) 34*6fca03f0SRiver Riddle return nullptr; 35*6fca03f0SRiver Riddle } 36*6fca03f0SRiver Riddle return from; 37*6fca03f0SRiver Riddle } 38*6fca03f0SRiver Riddle 39*6fca03f0SRiver Riddle /// Returns the string name of the given symbol, or None if this is not a 40*6fca03f0SRiver Riddle /// symbol. 41*6fca03f0SRiver Riddle static Optional<StringRef> getNameIfSymbol(Operation *symbol) { 42*6fca03f0SRiver Riddle auto nameAttr = 43*6fca03f0SRiver Riddle symbol->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName()); 44*6fca03f0SRiver Riddle return nameAttr ? nameAttr.getValue() : Optional<StringRef>(); 45*6fca03f0SRiver Riddle } 46*6fca03f0SRiver Riddle 47*6fca03f0SRiver Riddle /// Computes the nested symbol reference attribute for the symbol 'symbolName' 48*6fca03f0SRiver Riddle /// that are usable within the symbol table operations from 'symbol' as far up 49*6fca03f0SRiver Riddle /// to the given operation 'within', where 'within' is an ancestor of 'symbol'. 50*6fca03f0SRiver Riddle /// Returns success if all references up to 'within' could be computed. 51*6fca03f0SRiver Riddle static LogicalResult 52*6fca03f0SRiver Riddle collectValidReferencesFor(Operation *symbol, StringRef symbolName, 53*6fca03f0SRiver Riddle Operation *within, 54*6fca03f0SRiver Riddle SmallVectorImpl<SymbolRefAttr> &results) { 55*6fca03f0SRiver Riddle assert(within->isAncestor(symbol) && "expected 'within' to be an ancestor"); 56*6fca03f0SRiver Riddle MLIRContext *ctx = symbol->getContext(); 57*6fca03f0SRiver Riddle 58*6fca03f0SRiver Riddle auto leafRef = FlatSymbolRefAttr::get(symbolName, ctx); 59*6fca03f0SRiver Riddle results.push_back(leafRef); 60*6fca03f0SRiver Riddle 61*6fca03f0SRiver Riddle // Early exit for when 'within' is the parent of 'symbol'. 62*6fca03f0SRiver Riddle Operation *symbolTableOp = symbol->getParentOp(); 63*6fca03f0SRiver Riddle if (within == symbolTableOp) 64*6fca03f0SRiver Riddle return success(); 65*6fca03f0SRiver Riddle 66*6fca03f0SRiver Riddle // Collect references until 'symbolTableOp' reaches 'within'. 67*6fca03f0SRiver Riddle SmallVector<FlatSymbolRefAttr, 1> nestedRefs(1, leafRef); 68*6fca03f0SRiver Riddle do { 69*6fca03f0SRiver Riddle // Each parent of 'symbol' should define a symbol table. 70*6fca03f0SRiver Riddle if (!symbolTableOp->hasTrait<OpTrait::SymbolTable>()) 71*6fca03f0SRiver Riddle return failure(); 72*6fca03f0SRiver Riddle // Each parent of 'symbol' should also be a symbol. 73*6fca03f0SRiver Riddle Optional<StringRef> symbolTableName = getNameIfSymbol(symbolTableOp); 74*6fca03f0SRiver Riddle if (!symbolTableName) 75*6fca03f0SRiver Riddle return failure(); 76*6fca03f0SRiver Riddle results.push_back(SymbolRefAttr::get(*symbolTableName, nestedRefs, ctx)); 77*6fca03f0SRiver Riddle 78*6fca03f0SRiver Riddle symbolTableOp = symbolTableOp->getParentOp(); 79*6fca03f0SRiver Riddle if (symbolTableOp == within) 80*6fca03f0SRiver Riddle break; 81*6fca03f0SRiver Riddle nestedRefs.insert(nestedRefs.begin(), 82*6fca03f0SRiver Riddle FlatSymbolRefAttr::get(*symbolTableName, ctx)); 83*6fca03f0SRiver Riddle } while (true); 84*6fca03f0SRiver Riddle return success(); 85*6fca03f0SRiver Riddle } 86*6fca03f0SRiver Riddle 87b3a6ae83SRiver Riddle //===----------------------------------------------------------------------===// 88b3a6ae83SRiver Riddle // SymbolTable 89b3a6ae83SRiver Riddle //===----------------------------------------------------------------------===// 90b3a6ae83SRiver Riddle 91ee8e8b55SRiver Riddle /// Build a symbol table with the symbols within the given operation. 92b8cd0c14STres Popp SymbolTable::SymbolTable(Operation *symbolTableOp) 93b8cd0c14STres Popp : symbolTableOp(symbolTableOp) { 94b8cd0c14STres Popp assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>() && 95ee8e8b55SRiver Riddle "expected operation to have SymbolTable trait"); 96b8cd0c14STres Popp assert(symbolTableOp->getNumRegions() == 1 && 97ee8e8b55SRiver Riddle "expected operation to have a single region"); 98b8cd0c14STres Popp assert(has_single_element(symbolTableOp->getRegion(0)) && 99b8cd0c14STres Popp "expected operation to have a single block"); 100ee8e8b55SRiver Riddle 101b8cd0c14STres Popp for (auto &op : symbolTableOp->getRegion(0).front()) { 102*6fca03f0SRiver Riddle Optional<StringRef> name = getNameIfSymbol(&op); 103*6fca03f0SRiver Riddle if (!name) 104ee8e8b55SRiver Riddle continue; 105ee8e8b55SRiver Riddle 106*6fca03f0SRiver Riddle auto inserted = symbolTable.insert({*name, &op}); 1078c47e2edSRiver Riddle (void)inserted; 1088c47e2edSRiver Riddle assert(inserted.second && 109ee8e8b55SRiver Riddle "expected region to contain uniquely named symbol operations"); 110ee8e8b55SRiver Riddle } 1118c47e2edSRiver Riddle } 1128c47e2edSRiver Riddle 113927b7074SRiver Riddle /// Look up a symbol with the specified name, returning null if no such name 114927b7074SRiver Riddle /// exists. Names never include the @ on them. 115ee8e8b55SRiver Riddle Operation *SymbolTable::lookup(StringRef name) const { 116e7d594bbSRiver Riddle return symbolTable.lookup(name); 117927b7074SRiver Riddle } 118927b7074SRiver Riddle 119927b7074SRiver Riddle /// Erase the given symbol from the table. 120ee8e8b55SRiver Riddle void SymbolTable::erase(Operation *symbol) { 121*6fca03f0SRiver Riddle Optional<StringRef> name = getNameIfSymbol(symbol); 122*6fca03f0SRiver Riddle assert(name && "expected valid 'name' attribute"); 123b8cd0c14STres Popp assert(symbol->getParentOp() == symbolTableOp && 124b8cd0c14STres Popp "expected this operation to be inside of the operation with this " 125b8cd0c14STres Popp "SymbolTable"); 126ee8e8b55SRiver Riddle 127*6fca03f0SRiver Riddle auto it = symbolTable.find(*name); 128b8cd0c14STres Popp if (it != symbolTable.end() && it->second == symbol) { 129927b7074SRiver Riddle symbolTable.erase(it); 130b8cd0c14STres Popp symbol->erase(); 131b8cd0c14STres Popp } 132927b7074SRiver Riddle } 133927b7074SRiver Riddle 134b8cd0c14STres Popp /// Insert a new symbol into the table and associated operation, and rename it 135b8cd0c14STres Popp /// as necessary to avoid collisions. 136b8cd0c14STres Popp void SymbolTable::insert(Operation *symbol, Block::iterator insertPt) { 137b8cd0c14STres Popp auto &body = symbolTableOp->getRegion(0).front(); 138b8cd0c14STres Popp if (insertPt == Block::iterator() || insertPt == body.end()) 139b8cd0c14STres Popp insertPt = Block::iterator(body.getTerminator()); 140b8cd0c14STres Popp 141b8cd0c14STres Popp assert(insertPt->getParentOp() == symbolTableOp && 142b8cd0c14STres Popp "expected insertPt to be in the associated module operation"); 143b8cd0c14STres Popp 144b8cd0c14STres Popp body.getOperations().insert(insertPt, symbol); 145b8cd0c14STres Popp 146927b7074SRiver Riddle // Add this symbol to the symbol table, uniquing the name if a conflict is 147927b7074SRiver Riddle // detected. 148*6fca03f0SRiver Riddle StringRef name = getSymbolName(symbol); 149*6fca03f0SRiver Riddle if (symbolTable.insert({name, symbol}).second) 150927b7074SRiver Riddle return; 151ee8e8b55SRiver Riddle // If a conflict was detected, then the symbol will not have been added to 152927b7074SRiver Riddle // the symbol table. Try suffixes until we get to a unique name that works. 153*6fca03f0SRiver Riddle SmallString<128> nameBuffer(name); 154927b7074SRiver Riddle unsigned originalLength = nameBuffer.size(); 155927b7074SRiver Riddle 156ee8e8b55SRiver Riddle // Iteratively try suffixes until we find one that isn't used. 157927b7074SRiver Riddle do { 158927b7074SRiver Riddle nameBuffer.resize(originalLength); 159927b7074SRiver Riddle nameBuffer += '_'; 160927b7074SRiver Riddle nameBuffer += std::to_string(uniquingCounter++); 161e7d594bbSRiver Riddle } while (!symbolTable.insert({nameBuffer, symbol}).second); 162*6fca03f0SRiver Riddle setSymbolName(symbol, nameBuffer); 163*6fca03f0SRiver Riddle } 164*6fca03f0SRiver Riddle 165*6fca03f0SRiver Riddle /// Returns true if the given operation defines a symbol. 166*6fca03f0SRiver Riddle bool SymbolTable::isSymbol(Operation *op) { 167*6fca03f0SRiver Riddle return op->hasTrait<OpTrait::Symbol>() || getNameIfSymbol(op).hasValue(); 168*6fca03f0SRiver Riddle } 169*6fca03f0SRiver Riddle 170*6fca03f0SRiver Riddle /// Returns the name of the given symbol operation. 171*6fca03f0SRiver Riddle StringRef SymbolTable::getSymbolName(Operation *symbol) { 172*6fca03f0SRiver Riddle Optional<StringRef> name = getNameIfSymbol(symbol); 173*6fca03f0SRiver Riddle assert(name && "expected valid symbol name"); 174*6fca03f0SRiver Riddle return *name; 175*6fca03f0SRiver Riddle } 176*6fca03f0SRiver Riddle /// Sets the name of the given symbol operation. 177*6fca03f0SRiver Riddle void SymbolTable::setSymbolName(Operation *symbol, StringRef name) { 178b8cd0c14STres Popp symbol->setAttr(getSymbolAttrName(), 179*6fca03f0SRiver Riddle StringAttr::get(name, symbol->getContext())); 180ee8e8b55SRiver Riddle } 181ee8e8b55SRiver Riddle 1828cb405a8SRiver Riddle /// Returns the operation registered with the given symbol name with the 1838cb405a8SRiver Riddle /// regions of 'symbolTableOp'. 'symbolTableOp' is required to be an operation 1848cb405a8SRiver Riddle /// with the 'OpTrait::SymbolTable' trait. Returns nullptr if no valid symbol 1858cb405a8SRiver Riddle /// was found. 1868cb405a8SRiver Riddle Operation *SymbolTable::lookupSymbolIn(Operation *symbolTableOp, 1878cb405a8SRiver Riddle StringRef symbol) { 1888cb405a8SRiver Riddle assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>()); 1898cb405a8SRiver Riddle 1908cb405a8SRiver Riddle // Look for a symbol with the given name. 1918cb405a8SRiver Riddle for (auto &block : symbolTableOp->getRegion(0)) { 192*6fca03f0SRiver Riddle for (auto &op : block) 193*6fca03f0SRiver Riddle if (getNameIfSymbol(&op) == symbol) 1948cb405a8SRiver Riddle return &op; 1958cb405a8SRiver Riddle } 1968cb405a8SRiver Riddle return nullptr; 1978cb405a8SRiver Riddle } 198*6fca03f0SRiver Riddle Operation *SymbolTable::lookupSymbolIn(Operation *symbolTableOp, 199*6fca03f0SRiver Riddle SymbolRefAttr symbol) { 200*6fca03f0SRiver Riddle assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>()); 201*6fca03f0SRiver Riddle 202*6fca03f0SRiver Riddle // Lookup the root reference for this symbol. 203*6fca03f0SRiver Riddle symbolTableOp = lookupSymbolIn(symbolTableOp, symbol.getRootReference()); 204*6fca03f0SRiver Riddle if (!symbolTableOp) 205*6fca03f0SRiver Riddle return nullptr; 206*6fca03f0SRiver Riddle 207*6fca03f0SRiver Riddle // If there are no nested references, just return the root symbol directly. 208*6fca03f0SRiver Riddle ArrayRef<FlatSymbolRefAttr> nestedRefs = symbol.getNestedReferences(); 209*6fca03f0SRiver Riddle if (nestedRefs.empty()) 210*6fca03f0SRiver Riddle return symbolTableOp; 211*6fca03f0SRiver Riddle 212*6fca03f0SRiver Riddle // Verify that the root is also a symbol table. 213*6fca03f0SRiver Riddle if (!symbolTableOp->hasTrait<OpTrait::SymbolTable>()) 214*6fca03f0SRiver Riddle return nullptr; 215*6fca03f0SRiver Riddle 216*6fca03f0SRiver Riddle // Otherwise, lookup each of the nested non-leaf references and ensure that 217*6fca03f0SRiver Riddle // each corresponds to a valid symbol table. 218*6fca03f0SRiver Riddle for (FlatSymbolRefAttr ref : nestedRefs.drop_back()) { 219*6fca03f0SRiver Riddle symbolTableOp = lookupSymbolIn(symbolTableOp, ref.getValue()); 220*6fca03f0SRiver Riddle if (!symbolTableOp || !symbolTableOp->hasTrait<OpTrait::SymbolTable>()) 221*6fca03f0SRiver Riddle return nullptr; 222*6fca03f0SRiver Riddle } 223*6fca03f0SRiver Riddle return lookupSymbolIn(symbolTableOp, symbol.getLeafReference()); 224*6fca03f0SRiver Riddle } 2258cb405a8SRiver Riddle 2268cb405a8SRiver Riddle /// Returns the operation registered with the given symbol name within the 2278cb405a8SRiver Riddle /// closes parent operation with the 'OpTrait::SymbolTable' trait. Returns 2288cb405a8SRiver Riddle /// nullptr if no valid symbol was found. 2298cb405a8SRiver Riddle Operation *SymbolTable::lookupNearestSymbolFrom(Operation *from, 2308cb405a8SRiver Riddle StringRef symbol) { 231*6fca03f0SRiver Riddle Operation *symbolTableOp = getNearestSymbolTable(from); 232*6fca03f0SRiver Riddle return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr; 233b3a6ae83SRiver Riddle } 234*6fca03f0SRiver Riddle Operation *SymbolTable::lookupNearestSymbolFrom(Operation *from, 235*6fca03f0SRiver Riddle SymbolRefAttr symbol) { 236*6fca03f0SRiver Riddle Operation *symbolTableOp = getNearestSymbolTable(from); 237*6fca03f0SRiver Riddle return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr; 2388cb405a8SRiver Riddle } 2398cb405a8SRiver Riddle 240ee8e8b55SRiver Riddle //===----------------------------------------------------------------------===// 241ee8e8b55SRiver Riddle // SymbolTable Trait Types 242ee8e8b55SRiver Riddle //===----------------------------------------------------------------------===// 243ee8e8b55SRiver Riddle 244ee8e8b55SRiver Riddle LogicalResult OpTrait::impl::verifySymbolTable(Operation *op) { 245ee8e8b55SRiver Riddle if (op->getNumRegions() != 1) 246ee8e8b55SRiver Riddle return op->emitOpError() 247ee8e8b55SRiver Riddle << "Operations with a 'SymbolTable' must have exactly one region"; 248b8cd0c14STres Popp if (!has_single_element(op->getRegion(0))) 249b8cd0c14STres Popp return op->emitOpError() 250b8cd0c14STres Popp << "Operations with a 'SymbolTable' must have exactly one block"; 251ee8e8b55SRiver Riddle 2528bfedb3cSKazuaki Ishizaki // Check that all symbols are uniquely named within child regions. 253*6fca03f0SRiver Riddle DenseMap<Attribute, Location> nameToOrigLoc; 254ee8e8b55SRiver Riddle for (auto &block : op->getRegion(0)) { 255ee8e8b55SRiver Riddle for (auto &op : block) { 256ee8e8b55SRiver Riddle // Check for a symbol name attribute. 257ee8e8b55SRiver Riddle auto nameAttr = 258ee8e8b55SRiver Riddle op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName()); 259ee8e8b55SRiver Riddle if (!nameAttr) 260ee8e8b55SRiver Riddle continue; 261ee8e8b55SRiver Riddle 262ee8e8b55SRiver Riddle // Try to insert this symbol into the table. 263*6fca03f0SRiver Riddle auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc()); 264ee8e8b55SRiver Riddle if (!it.second) 265ee8e8b55SRiver Riddle return op.emitError() 266ee8e8b55SRiver Riddle .append("redefinition of symbol named '", nameAttr.getValue(), "'") 267ee8e8b55SRiver Riddle .attachNote(it.first->second) 268ee8e8b55SRiver Riddle .append("see existing symbol definition here"); 269ee8e8b55SRiver Riddle } 270ee8e8b55SRiver Riddle } 271ee8e8b55SRiver Riddle return success(); 272927b7074SRiver Riddle } 273ac91e673SRiver Riddle 2749ac459e8SRiver Riddle LogicalResult OpTrait::impl::verifySymbol(Operation *op) { 2759ac459e8SRiver Riddle if (!op->getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName())) 2769ac459e8SRiver Riddle return op->emitOpError() << "requires string attribute '" 2779ac459e8SRiver Riddle << mlir::SymbolTable::getSymbolAttrName() << "'"; 2789ac459e8SRiver Riddle return success(); 2799ac459e8SRiver Riddle } 2809ac459e8SRiver Riddle 281ac91e673SRiver Riddle //===----------------------------------------------------------------------===// 282ef43b565SRiver Riddle // Symbol Use Lists 283ac91e673SRiver Riddle //===----------------------------------------------------------------------===// 284ac91e673SRiver Riddle 285ac91e673SRiver Riddle /// Walk all of the symbol references within the given operation, invoking the 286ef43b565SRiver Riddle /// provided callback for each found use. The callbacks takes as arguments: the 287ef43b565SRiver Riddle /// use of the symbol, and the nested access chain to the attribute within the 288ef43b565SRiver Riddle /// operation dictionary. An access chain is a set of indices into nested 289ef43b565SRiver Riddle /// container attributes. For example, a symbol use in an attribute dictionary 290ef43b565SRiver Riddle /// that looks like the following: 291ef43b565SRiver Riddle /// 292ef43b565SRiver Riddle /// {use = [{other_attr, @symbol}]} 293ef43b565SRiver Riddle /// 294ef43b565SRiver Riddle /// May have the following access chain: 295ef43b565SRiver Riddle /// 296ef43b565SRiver Riddle /// [0, 0, 1] 297ef43b565SRiver Riddle /// 298ef43b565SRiver Riddle static WalkResult walkSymbolRefs( 299ef43b565SRiver Riddle Operation *op, 300ef43b565SRiver Riddle function_ref<WalkResult(SymbolTable::SymbolUse, ArrayRef<int>)> callback) { 301ac91e673SRiver Riddle // Check to see if the operation has any attributes. 302ac91e673SRiver Riddle DictionaryAttr attrDict = op->getAttrList().getDictionary(); 303ac91e673SRiver Riddle if (!attrDict) 304ac91e673SRiver Riddle return WalkResult::advance(); 305ac91e673SRiver Riddle 306ac91e673SRiver Riddle // A worklist of a container attribute and the current index into the held 307ac91e673SRiver Riddle // attribute list. 308ef43b565SRiver Riddle SmallVector<Attribute, 1> attrWorklist(1, attrDict); 309ef43b565SRiver Riddle SmallVector<int, 1> curAccessChain(1, /*Value=*/-1); 3105f6bdd14SRiver Riddle 3115f6bdd14SRiver Riddle // Process the symbol references within the given nested attribute range. 312ef43b565SRiver Riddle auto processAttrs = [&](int &index, auto attrRange) -> WalkResult { 3135f6bdd14SRiver Riddle for (Attribute attr : llvm::drop_begin(attrRange, index)) { 3145f6bdd14SRiver Riddle /// Check for a nested container attribute, these will also need to be 3155f6bdd14SRiver Riddle /// walked. 3165f6bdd14SRiver Riddle if (attr.isa<ArrayAttr>() || attr.isa<DictionaryAttr>()) { 317ef43b565SRiver Riddle attrWorklist.push_back(attr); 318ef43b565SRiver Riddle curAccessChain.push_back(-1); 3195f6bdd14SRiver Riddle return WalkResult::advance(); 3205f6bdd14SRiver Riddle } 3215f6bdd14SRiver Riddle 3225f6bdd14SRiver Riddle // Invoke the provided callback if we find a symbol use and check for a 3235f6bdd14SRiver Riddle // requested interrupt. 3245f6bdd14SRiver Riddle if (auto symbolRef = attr.dyn_cast<SymbolRefAttr>()) 325ef43b565SRiver Riddle if (callback({op, symbolRef}, curAccessChain).wasInterrupted()) 3265f6bdd14SRiver Riddle return WalkResult::interrupt(); 327ef43b565SRiver Riddle 328ef43b565SRiver Riddle // Make sure to keep the index counter in sync. 329ef43b565SRiver Riddle ++index; 3305f6bdd14SRiver Riddle } 3315f6bdd14SRiver Riddle 3325f6bdd14SRiver Riddle // Pop this container attribute from the worklist. 333ef43b565SRiver Riddle attrWorklist.pop_back(); 334ef43b565SRiver Riddle curAccessChain.pop_back(); 3355f6bdd14SRiver Riddle return WalkResult::advance(); 3365f6bdd14SRiver Riddle }; 3375f6bdd14SRiver Riddle 3385f6bdd14SRiver Riddle WalkResult result = WalkResult::advance(); 3395f6bdd14SRiver Riddle do { 340ef43b565SRiver Riddle Attribute attr = attrWorklist.back(); 341ef43b565SRiver Riddle int &index = curAccessChain.back(); 342ef43b565SRiver Riddle ++index; 343ac91e673SRiver Riddle 3445f6bdd14SRiver Riddle // Process the given attribute, which is guaranteed to be a container. 3455f6bdd14SRiver Riddle if (auto dict = attr.dyn_cast<DictionaryAttr>()) 3465f6bdd14SRiver Riddle result = processAttrs(index, make_second_range(dict.getValue())); 3475f6bdd14SRiver Riddle else 3485f6bdd14SRiver Riddle result = processAttrs(index, attr.cast<ArrayAttr>().getValue()); 349ef43b565SRiver Riddle } while (!attrWorklist.empty() && !result.wasInterrupted()); 3505f6bdd14SRiver Riddle return result; 351ac91e673SRiver Riddle } 352ac91e673SRiver Riddle 353ac91e673SRiver Riddle /// Walk all of the uses, for any symbol, that are nested within the given 354ac91e673SRiver Riddle /// operation 'from', invoking the provided callback for each. This does not 355ac91e673SRiver Riddle /// traverse into any nested symbol tables, and will also only return uses on 356ac91e673SRiver Riddle /// 'from' if it does not also define a symbol table. 357ef43b565SRiver Riddle static Optional<WalkResult> walkSymbolUses( 358ef43b565SRiver Riddle Operation *from, 359ef43b565SRiver Riddle function_ref<WalkResult(SymbolTable::SymbolUse, ArrayRef<int>)> callback) { 360ac91e673SRiver Riddle // If from is not a symbol table, check for uses. A symbol table defines a new 361ac91e673SRiver Riddle // scope, so we can't walk the attributes from the symbol table op. 362ac91e673SRiver Riddle if (!from->hasTrait<OpTrait::SymbolTable>()) { 363ac91e673SRiver Riddle if (walkSymbolRefs(from, callback).wasInterrupted()) 364ac91e673SRiver Riddle return WalkResult::interrupt(); 365ac91e673SRiver Riddle } 366ac91e673SRiver Riddle 367ac91e673SRiver Riddle SmallVector<Region *, 1> worklist; 368ac91e673SRiver Riddle worklist.reserve(from->getNumRegions()); 369ac91e673SRiver Riddle for (Region ®ion : from->getRegions()) 370ac91e673SRiver Riddle worklist.push_back(®ion); 371ac91e673SRiver Riddle 372ac91e673SRiver Riddle while (!worklist.empty()) { 373ac91e673SRiver Riddle Region *region = worklist.pop_back_val(); 374ac91e673SRiver Riddle for (Block &block : *region) { 375ac91e673SRiver Riddle for (Operation &op : block) { 376ac91e673SRiver Riddle if (walkSymbolRefs(&op, callback).wasInterrupted()) 377ac91e673SRiver Riddle return WalkResult::interrupt(); 378ac91e673SRiver Riddle 37984a6182dSKazuaki Ishizaki // If this operation has regions, and it as well as its dialect aren't 380b3a6ae83SRiver Riddle // registered then conservatively fail. The operation may define a 381b3a6ae83SRiver Riddle // symbol table, so we can't opaquely know if we should traverse to find 382b3a6ae83SRiver Riddle // nested uses. 383b3a6ae83SRiver Riddle if (isPotentiallyUnknownSymbolTable(&op)) 384b3a6ae83SRiver Riddle return llvm::None; 385b3a6ae83SRiver Riddle 386ac91e673SRiver Riddle // If this op defines a new symbol table scope, we can't traverse. Any 387ac91e673SRiver Riddle // symbol references nested within 'op' are different semantically. 388ac91e673SRiver Riddle if (!op.hasTrait<OpTrait::SymbolTable>()) { 389ac91e673SRiver Riddle for (Region ®ion : op.getRegions()) 390ac91e673SRiver Riddle worklist.push_back(®ion); 391ac91e673SRiver Riddle } 392ac91e673SRiver Riddle } 393ac91e673SRiver Riddle } 394ac91e673SRiver Riddle } 395ac91e673SRiver Riddle return WalkResult::advance(); 396ac91e673SRiver Riddle } 397ac91e673SRiver Riddle 398*6fca03f0SRiver Riddle /// Walks all of the symbol scopes from 'symbol' to (inclusive) 'limit' invoking 399*6fca03f0SRiver Riddle /// the provided callback at each one with a properly scoped reference to 400*6fca03f0SRiver Riddle /// 'symbol'. The callback takes as parameters the symbol reference at the 401*6fca03f0SRiver Riddle /// current scope as well as the top-level operation representing the top of 402*6fca03f0SRiver Riddle /// that scope. 403*6fca03f0SRiver Riddle static Optional<WalkResult> walkSymbolScopes( 404*6fca03f0SRiver Riddle Operation *symbol, Operation *limit, 405*6fca03f0SRiver Riddle function_ref<Optional<WalkResult>(SymbolRefAttr, Operation *)> callback) { 406*6fca03f0SRiver Riddle StringRef symbolName = SymbolTable::getSymbolName(symbol); 407*6fca03f0SRiver Riddle assert(!symbol->hasTrait<OpTrait::SymbolTable>() || symbol != limit); 408*6fca03f0SRiver Riddle 409*6fca03f0SRiver Riddle // Compute the ancestors of 'limit'. 410*6fca03f0SRiver Riddle llvm::SetVector<Operation *, SmallVector<Operation *, 4>, 411*6fca03f0SRiver Riddle SmallPtrSet<Operation *, 4>> 412*6fca03f0SRiver Riddle limitAncestors; 413*6fca03f0SRiver Riddle Operation *limitAncestor = limit; 414*6fca03f0SRiver Riddle do { 415*6fca03f0SRiver Riddle // Check to see if 'symbol' is an ancestor of 'limit'. 416*6fca03f0SRiver Riddle if (limitAncestor == symbol) { 417*6fca03f0SRiver Riddle // Check that the nearest symbol table is 'symbol's parent. SymbolRefAttr 418*6fca03f0SRiver Riddle // doesn't support parent references. 419*6fca03f0SRiver Riddle if (getNearestSymbolTable(limit) != symbol->getParentOp()) 420*6fca03f0SRiver Riddle return WalkResult::advance(); 421*6fca03f0SRiver Riddle return callback(SymbolRefAttr::get(symbolName, symbol->getContext()), 422*6fca03f0SRiver Riddle limit); 423*6fca03f0SRiver Riddle } 424*6fca03f0SRiver Riddle 425*6fca03f0SRiver Riddle limitAncestors.insert(limitAncestor); 426*6fca03f0SRiver Riddle } while ((limitAncestor = limitAncestor->getParentOp())); 427*6fca03f0SRiver Riddle 428*6fca03f0SRiver Riddle // Try to find the first ancestor of 'symbol' that is an ancestor of 'limit'. 429*6fca03f0SRiver Riddle Operation *commonAncestor = symbol->getParentOp(); 430*6fca03f0SRiver Riddle do { 431*6fca03f0SRiver Riddle if (limitAncestors.count(commonAncestor)) 432*6fca03f0SRiver Riddle break; 433*6fca03f0SRiver Riddle } while ((commonAncestor = commonAncestor->getParentOp())); 434*6fca03f0SRiver Riddle assert(commonAncestor && "'limit' and 'symbol' have no common ancestor"); 435*6fca03f0SRiver Riddle 436*6fca03f0SRiver Riddle // Compute the set of valid nested references for 'symbol' as far up to the 437*6fca03f0SRiver Riddle // common ancestor as possible. 438*6fca03f0SRiver Riddle SmallVector<SymbolRefAttr, 2> references; 439*6fca03f0SRiver Riddle bool collectedAllReferences = succeeded(collectValidReferencesFor( 440*6fca03f0SRiver Riddle symbol, symbolName, commonAncestor, references)); 441*6fca03f0SRiver Riddle 442*6fca03f0SRiver Riddle // Handle the case where the common ancestor is 'limit'. 443*6fca03f0SRiver Riddle if (commonAncestor == limit) { 444*6fca03f0SRiver Riddle // Walk each of the ancestors of 'symbol', calling the compute function for 445*6fca03f0SRiver Riddle // each one. 446*6fca03f0SRiver Riddle Operation *limitIt = symbol->getParentOp(); 447*6fca03f0SRiver Riddle for (size_t i = 0, e = references.size(); i != e; 448*6fca03f0SRiver Riddle ++i, limitIt = limitIt->getParentOp()) { 449*6fca03f0SRiver Riddle Optional<WalkResult> callbackResult = callback(references[i], limitIt); 450*6fca03f0SRiver Riddle if (callbackResult != WalkResult::advance()) 451*6fca03f0SRiver Riddle return callbackResult; 452*6fca03f0SRiver Riddle } 453*6fca03f0SRiver Riddle return WalkResult::advance(); 454*6fca03f0SRiver Riddle } 455*6fca03f0SRiver Riddle 456*6fca03f0SRiver Riddle // Otherwise, we just need the symbol reference for 'symbol' that will be 457*6fca03f0SRiver Riddle // used within 'limit'. This is the last reference in the list we computed 458*6fca03f0SRiver Riddle // above if we were able to collect all references. 459*6fca03f0SRiver Riddle if (!collectedAllReferences) 460*6fca03f0SRiver Riddle return WalkResult::advance(); 461*6fca03f0SRiver Riddle return callback(references.back(), limit); 462*6fca03f0SRiver Riddle } 463*6fca03f0SRiver Riddle 464*6fca03f0SRiver Riddle /// Walk the symbol scopes defined by 'limit' invoking the provided callback. 465*6fca03f0SRiver Riddle static Optional<WalkResult> walkSymbolScopes( 466*6fca03f0SRiver Riddle StringRef symbol, Operation *limit, 467*6fca03f0SRiver Riddle function_ref<Optional<WalkResult>(SymbolRefAttr, Operation *)> callback) { 468*6fca03f0SRiver Riddle return callback(SymbolRefAttr::get(symbol, limit->getContext()), limit); 469*6fca03f0SRiver Riddle } 470*6fca03f0SRiver Riddle 471*6fca03f0SRiver Riddle /// Returns true if the given reference 'SubRef' is a sub reference of the 472*6fca03f0SRiver Riddle /// reference 'ref', i.e. 'ref' is a further qualified reference. 473*6fca03f0SRiver Riddle static bool isReferencePrefixOf(SymbolRefAttr subRef, SymbolRefAttr ref) { 474*6fca03f0SRiver Riddle if (ref == subRef) 475*6fca03f0SRiver Riddle return true; 476*6fca03f0SRiver Riddle 477*6fca03f0SRiver Riddle // If the references are not pointer equal, check to see if `subRef` is a 478*6fca03f0SRiver Riddle // prefix of `ref`. 479*6fca03f0SRiver Riddle if (ref.isa<FlatSymbolRefAttr>() || 480*6fca03f0SRiver Riddle ref.getRootReference() != subRef.getRootReference()) 481*6fca03f0SRiver Riddle return false; 482*6fca03f0SRiver Riddle 483*6fca03f0SRiver Riddle auto refLeafs = ref.getNestedReferences(); 484*6fca03f0SRiver Riddle auto subRefLeafs = subRef.getNestedReferences(); 485*6fca03f0SRiver Riddle return subRefLeafs.size() < refLeafs.size() && 486*6fca03f0SRiver Riddle subRefLeafs == refLeafs.take_front(subRefLeafs.size()); 487*6fca03f0SRiver Riddle } 488*6fca03f0SRiver Riddle 489*6fca03f0SRiver Riddle //===----------------------------------------------------------------------===// 490*6fca03f0SRiver Riddle // SymbolTable::getSymbolUses 491*6fca03f0SRiver Riddle 492b3a6ae83SRiver Riddle /// Get an iterator range for all of the uses, for any symbol, that are nested 493b3a6ae83SRiver Riddle /// within the given operation 'from'. This does not traverse into any nested 494b3a6ae83SRiver Riddle /// symbol tables, and will also only return uses on 'from' if it does not 495ef43b565SRiver Riddle /// also define a symbol table. This is because we treat the region as the 496ef43b565SRiver Riddle /// boundary of the symbol table, and not the op itself. This function returns 497ef43b565SRiver Riddle /// None if there are any unknown operations that may potentially be symbol 498ef43b565SRiver Riddle /// tables. 499b3a6ae83SRiver Riddle auto SymbolTable::getSymbolUses(Operation *from) -> Optional<UseRange> { 500b3a6ae83SRiver Riddle std::vector<SymbolUse> uses; 501*6fca03f0SRiver Riddle auto walkFn = [&](SymbolUse symbolUse, ArrayRef<int>) { 502*6fca03f0SRiver Riddle uses.push_back(symbolUse); 503*6fca03f0SRiver Riddle return WalkResult::advance(); 504*6fca03f0SRiver Riddle }; 505*6fca03f0SRiver Riddle auto result = walkSymbolUses(from, walkFn); 506*6fca03f0SRiver Riddle return result ? Optional<UseRange>(std::move(uses)) : Optional<UseRange>(); 507*6fca03f0SRiver Riddle } 508*6fca03f0SRiver Riddle 509*6fca03f0SRiver Riddle //===----------------------------------------------------------------------===// 510*6fca03f0SRiver Riddle // SymbolTable::getSymbolUses 511*6fca03f0SRiver Riddle 512*6fca03f0SRiver Riddle /// The implementation of SymbolTable::getSymbolUses below. 513*6fca03f0SRiver Riddle template <typename SymbolT> 514*6fca03f0SRiver Riddle static Optional<SymbolTable::UseRange> getSymbolUsesImpl(SymbolT symbol, 515*6fca03f0SRiver Riddle Operation *limit) { 516*6fca03f0SRiver Riddle std::vector<SymbolTable::SymbolUse> uses; 517*6fca03f0SRiver Riddle auto walkFn = [&](SymbolRefAttr symbolRefAttr, Operation *from) { 518*6fca03f0SRiver Riddle return walkSymbolUses( 519*6fca03f0SRiver Riddle from, [&](SymbolTable::SymbolUse symbolUse, ArrayRef<int>) { 520*6fca03f0SRiver Riddle if (isReferencePrefixOf(symbolRefAttr, symbolUse.getSymbolRef())) 521b3a6ae83SRiver Riddle uses.push_back(symbolUse); 522ac91e673SRiver Riddle return WalkResult::advance(); 523ac91e673SRiver Riddle }); 524*6fca03f0SRiver Riddle }; 525*6fca03f0SRiver Riddle if (walkSymbolScopes(symbol, limit, walkFn)) 526*6fca03f0SRiver Riddle return SymbolTable::UseRange(std::move(uses)); 527*6fca03f0SRiver Riddle return llvm::None; 528ac91e673SRiver Riddle } 529ac91e673SRiver Riddle 530b3a6ae83SRiver Riddle /// Get all of the uses of the given symbol that are nested within the given 531b3a6ae83SRiver Riddle /// operation 'from', invoking the provided callback for each. This does not 532b3a6ae83SRiver Riddle /// traverse into any nested symbol tables, and will also only return uses on 533ef43b565SRiver Riddle /// 'from' if it does not also define a symbol table. This is because we treat 534ef43b565SRiver Riddle /// the region as the boundary of the symbol table, and not the op itself. This 535ef43b565SRiver Riddle /// function returns None if there are any unknown operations that may 536ef43b565SRiver Riddle /// potentially be symbol tables. 537b3a6ae83SRiver Riddle auto SymbolTable::getSymbolUses(StringRef symbol, Operation *from) 538b3a6ae83SRiver Riddle -> Optional<UseRange> { 539*6fca03f0SRiver Riddle return getSymbolUsesImpl(symbol, from); 540*6fca03f0SRiver Riddle } 541*6fca03f0SRiver Riddle auto SymbolTable::getSymbolUses(Operation *symbol, Operation *from) 542*6fca03f0SRiver Riddle -> Optional<UseRange> { 543*6fca03f0SRiver Riddle return getSymbolUsesImpl(symbol, from); 544*6fca03f0SRiver Riddle } 545b3a6ae83SRiver Riddle 546*6fca03f0SRiver Riddle //===----------------------------------------------------------------------===// 547*6fca03f0SRiver Riddle // SymbolTable::symbolKnownUseEmpty 548*6fca03f0SRiver Riddle 549*6fca03f0SRiver Riddle /// The implementation of SymbolTable::symbolKnownUseEmpty below. 550*6fca03f0SRiver Riddle template <typename SymbolT> 551*6fca03f0SRiver Riddle static bool symbolKnownUseEmptyImpl(SymbolT symbol, Operation *limit) { 552*6fca03f0SRiver Riddle // Walk all of the symbol uses looking for a reference to 'symbol'. 553*6fca03f0SRiver Riddle auto walkFn = [&](SymbolRefAttr symbolRefAttr, Operation *from) { 554*6fca03f0SRiver Riddle return walkSymbolUses( 555*6fca03f0SRiver Riddle from, [&](SymbolTable::SymbolUse symbolUse, ArrayRef<int>) { 556*6fca03f0SRiver Riddle return isReferencePrefixOf(symbolRefAttr, symbolUse.getSymbolRef()) 557*6fca03f0SRiver Riddle ? WalkResult::interrupt() 558*6fca03f0SRiver Riddle : WalkResult::advance(); 559b3a6ae83SRiver Riddle }); 560*6fca03f0SRiver Riddle }; 561*6fca03f0SRiver Riddle return walkSymbolScopes(symbol, limit, walkFn) == WalkResult::advance(); 562b3a6ae83SRiver Riddle } 563b3a6ae83SRiver Riddle 564b3a6ae83SRiver Riddle /// Return if the given symbol is known to have no uses that are nested within 565b3a6ae83SRiver Riddle /// the given operation 'from'. This does not traverse into any nested symbol 566b3a6ae83SRiver Riddle /// tables, and will also only count uses on 'from' if it does not also define 567ef43b565SRiver Riddle /// a symbol table. This is because we treat the region as the boundary of the 568ef43b565SRiver Riddle /// symbol table, and not the op itself. This function will also return false if 569ef43b565SRiver Riddle /// there are any unknown operations that may potentially be symbol tables. 570b3a6ae83SRiver Riddle bool SymbolTable::symbolKnownUseEmpty(StringRef symbol, Operation *from) { 571*6fca03f0SRiver Riddle return symbolKnownUseEmptyImpl(symbol, from); 572*6fca03f0SRiver Riddle } 573*6fca03f0SRiver Riddle bool SymbolTable::symbolKnownUseEmpty(Operation *symbol, Operation *from) { 574*6fca03f0SRiver Riddle return symbolKnownUseEmptyImpl(symbol, from); 575ac91e673SRiver Riddle } 576ef43b565SRiver Riddle 577*6fca03f0SRiver Riddle //===----------------------------------------------------------------------===// 578*6fca03f0SRiver Riddle // SymbolTable::replaceAllSymbolUses 579*6fca03f0SRiver Riddle 580ef43b565SRiver Riddle /// Rebuild the given attribute container after replacing all references to a 581*6fca03f0SRiver Riddle /// symbol with the updated attribute in 'accesses'. 582*6fca03f0SRiver Riddle static Attribute rebuildAttrAfterRAUW( 583*6fca03f0SRiver Riddle Attribute container, 584*6fca03f0SRiver Riddle ArrayRef<std::pair<SmallVector<int, 1>, SymbolRefAttr>> accesses, 585ef43b565SRiver Riddle unsigned depth) { 586ef43b565SRiver Riddle // Given a range of Attributes, update the ones referred to by the given 587ef43b565SRiver Riddle // access chains to point to the new symbol attribute. 588ef43b565SRiver Riddle auto updateAttrs = [&](auto &&attrRange) { 589ef43b565SRiver Riddle auto attrBegin = std::begin(attrRange); 590ef43b565SRiver Riddle for (unsigned i = 0, e = accesses.size(); i != e;) { 591*6fca03f0SRiver Riddle ArrayRef<int> access = accesses[i].first; 592ef43b565SRiver Riddle Attribute &attr = *std::next(attrBegin, access[depth]); 593ef43b565SRiver Riddle 594ef43b565SRiver Riddle // Check to see if this is a leaf access, i.e. a SymbolRef. 595ef43b565SRiver Riddle if (access.size() == depth + 1) { 596*6fca03f0SRiver Riddle attr = accesses[i].second; 597ef43b565SRiver Riddle ++i; 598ef43b565SRiver Riddle continue; 599ef43b565SRiver Riddle } 600ef43b565SRiver Riddle 601ef43b565SRiver Riddle // Otherwise, this is a container. Collect all of the accesses for this 602ef43b565SRiver Riddle // index and recurse. The recursion here is bounded by the size of the 603ef43b565SRiver Riddle // largest access array. 604*6fca03f0SRiver Riddle auto nestedAccesses = accesses.drop_front(i).take_while([&](auto &it) { 605*6fca03f0SRiver Riddle ArrayRef<int> nextAccess = it.first; 606ef43b565SRiver Riddle return nextAccess.size() > depth + 1 && 607ef43b565SRiver Riddle nextAccess[depth] == access[depth]; 608ef43b565SRiver Riddle }); 609*6fca03f0SRiver Riddle attr = rebuildAttrAfterRAUW(attr, nestedAccesses, depth + 1); 610ef43b565SRiver Riddle 611ef43b565SRiver Riddle // Skip over all of the accesses that refer to the nested container. 612ef43b565SRiver Riddle i += nestedAccesses.size(); 613ef43b565SRiver Riddle } 614ef43b565SRiver Riddle }; 615ef43b565SRiver Riddle 616ef43b565SRiver Riddle if (auto dictAttr = container.dyn_cast<DictionaryAttr>()) { 617ef43b565SRiver Riddle auto newAttrs = llvm::to_vector<4>(dictAttr.getValue()); 618ef43b565SRiver Riddle updateAttrs(make_second_range(newAttrs)); 619ef43b565SRiver Riddle return DictionaryAttr::get(newAttrs, dictAttr.getContext()); 620ef43b565SRiver Riddle } 621ef43b565SRiver Riddle auto newAttrs = llvm::to_vector<4>(container.cast<ArrayAttr>().getValue()); 622ef43b565SRiver Riddle updateAttrs(newAttrs); 623ef43b565SRiver Riddle return ArrayAttr::get(newAttrs, container.getContext()); 624ef43b565SRiver Riddle } 625ef43b565SRiver Riddle 626*6fca03f0SRiver Riddle /// Generates a new symbol reference attribute with a new leaf reference. 627*6fca03f0SRiver Riddle SymbolRefAttr generateNewRefAttr(SymbolRefAttr oldAttr, 628*6fca03f0SRiver Riddle FlatSymbolRefAttr newLeafAttr) { 629*6fca03f0SRiver Riddle if (oldAttr.isa<FlatSymbolRefAttr>()) 630*6fca03f0SRiver Riddle return newLeafAttr; 631*6fca03f0SRiver Riddle auto nestedRefs = llvm::to_vector<2>(oldAttr.getNestedReferences()); 632*6fca03f0SRiver Riddle nestedRefs.back() = newLeafAttr; 633*6fca03f0SRiver Riddle return SymbolRefAttr::get(oldAttr.getRootReference(), nestedRefs, 634*6fca03f0SRiver Riddle oldAttr.getContext()); 635*6fca03f0SRiver Riddle } 636*6fca03f0SRiver Riddle 637*6fca03f0SRiver Riddle /// The implementation of SymbolTable::replaceAllSymbolUses below. 638*6fca03f0SRiver Riddle template <typename SymbolT> 639*6fca03f0SRiver Riddle static LogicalResult replaceAllSymbolUsesImpl(SymbolT symbol, 640*6fca03f0SRiver Riddle StringRef newSymbol, 641*6fca03f0SRiver Riddle Operation *limit) { 642*6fca03f0SRiver Riddle // A collection of operations along with their new attribute dictionary. 643*6fca03f0SRiver Riddle std::vector<std::pair<Operation *, DictionaryAttr>> updatedAttrDicts; 644*6fca03f0SRiver Riddle 645*6fca03f0SRiver Riddle // The current operation being processed. 646*6fca03f0SRiver Riddle Operation *curOp = nullptr; 647*6fca03f0SRiver Riddle 648*6fca03f0SRiver Riddle // The set of access chains into the attribute dictionary of the current 649*6fca03f0SRiver Riddle // operation, as well as the replacement attribute to use. 650*6fca03f0SRiver Riddle SmallVector<std::pair<SmallVector<int, 1>, SymbolRefAttr>, 1> accessChains; 651*6fca03f0SRiver Riddle 652*6fca03f0SRiver Riddle // Generate a new attribute dictionary for the current operation by replacing 653*6fca03f0SRiver Riddle // references to the old symbol. 654*6fca03f0SRiver Riddle auto generateNewAttrDict = [&] { 655*6fca03f0SRiver Riddle auto oldDict = curOp->getAttrList().getDictionary(); 656*6fca03f0SRiver Riddle auto newDict = rebuildAttrAfterRAUW(oldDict, accessChains, /*depth=*/0); 657*6fca03f0SRiver Riddle return newDict.cast<DictionaryAttr>(); 658*6fca03f0SRiver Riddle }; 659*6fca03f0SRiver Riddle 660*6fca03f0SRiver Riddle // Generate a new attribute to replace the given attribute. 661*6fca03f0SRiver Riddle MLIRContext *ctx = limit->getContext(); 662*6fca03f0SRiver Riddle FlatSymbolRefAttr newLeafAttr = FlatSymbolRefAttr::get(newSymbol, ctx); 663*6fca03f0SRiver Riddle auto scopeWalkFn = [&](SymbolRefAttr oldAttr, 664*6fca03f0SRiver Riddle Operation *from) -> Optional<WalkResult> { 665*6fca03f0SRiver Riddle SymbolRefAttr newAttr = generateNewRefAttr(oldAttr, newLeafAttr); 666*6fca03f0SRiver Riddle auto walkFn = [&](SymbolTable::SymbolUse symbolUse, 667*6fca03f0SRiver Riddle ArrayRef<int> accessChain) { 668*6fca03f0SRiver Riddle SymbolRefAttr useRef = symbolUse.getSymbolRef(); 669*6fca03f0SRiver Riddle if (!isReferencePrefixOf(oldAttr, useRef)) 670*6fca03f0SRiver Riddle return WalkResult::advance(); 671*6fca03f0SRiver Riddle 672*6fca03f0SRiver Riddle // If we have a valid match, check to see if this is a proper 673*6fca03f0SRiver Riddle // subreference. If it is, then we will need to generate a different new 674*6fca03f0SRiver Riddle // attribute specifically for this use. 675*6fca03f0SRiver Riddle SymbolRefAttr replacementRef = newAttr; 676*6fca03f0SRiver Riddle if (useRef != oldAttr) { 677*6fca03f0SRiver Riddle if (oldAttr.isa<FlatSymbolRefAttr>()) { 678*6fca03f0SRiver Riddle replacementRef = 679*6fca03f0SRiver Riddle SymbolRefAttr::get(newSymbol, useRef.getNestedReferences(), ctx); 680*6fca03f0SRiver Riddle } else { 681*6fca03f0SRiver Riddle auto nestedRefs = llvm::to_vector<4>(useRef.getNestedReferences()); 682*6fca03f0SRiver Riddle nestedRefs[oldAttr.getNestedReferences().size() - 1] = newLeafAttr; 683*6fca03f0SRiver Riddle replacementRef = 684*6fca03f0SRiver Riddle SymbolRefAttr::get(useRef.getRootReference(), nestedRefs, ctx); 685*6fca03f0SRiver Riddle } 686*6fca03f0SRiver Riddle } 687*6fca03f0SRiver Riddle 688*6fca03f0SRiver Riddle // If there was a previous operation, generate a new attribute dict 689*6fca03f0SRiver Riddle // for it. This means that we've finished processing the current 690*6fca03f0SRiver Riddle // operation, so generate a new dictionary for it. 691*6fca03f0SRiver Riddle if (curOp && symbolUse.getUser() != curOp) { 692*6fca03f0SRiver Riddle updatedAttrDicts.push_back({curOp, generateNewAttrDict()}); 693*6fca03f0SRiver Riddle accessChains.clear(); 694*6fca03f0SRiver Riddle } 695*6fca03f0SRiver Riddle 696*6fca03f0SRiver Riddle // Record this access. 697*6fca03f0SRiver Riddle curOp = symbolUse.getUser(); 698*6fca03f0SRiver Riddle accessChains.push_back({llvm::to_vector<1>(accessChain), replacementRef}); 699*6fca03f0SRiver Riddle return WalkResult::advance(); 700*6fca03f0SRiver Riddle }; 701*6fca03f0SRiver Riddle if (!walkSymbolUses(from, walkFn)) 702*6fca03f0SRiver Riddle return llvm::None; 703*6fca03f0SRiver Riddle 704*6fca03f0SRiver Riddle // Check to see if we have a dangling op that needs to be processed. 705*6fca03f0SRiver Riddle if (curOp) { 706*6fca03f0SRiver Riddle updatedAttrDicts.push_back({curOp, generateNewAttrDict()}); 707*6fca03f0SRiver Riddle curOp = nullptr; 708*6fca03f0SRiver Riddle } 709*6fca03f0SRiver Riddle return WalkResult::advance(); 710*6fca03f0SRiver Riddle }; 711*6fca03f0SRiver Riddle if (!walkSymbolScopes(symbol, limit, scopeWalkFn)) 712*6fca03f0SRiver Riddle return failure(); 713*6fca03f0SRiver Riddle 714*6fca03f0SRiver Riddle // Update the attribute dictionaries as necessary. 715*6fca03f0SRiver Riddle for (auto &it : updatedAttrDicts) 716*6fca03f0SRiver Riddle it.first->setAttrs(it.second); 717*6fca03f0SRiver Riddle return success(); 718*6fca03f0SRiver Riddle } 719*6fca03f0SRiver Riddle 720ef43b565SRiver Riddle /// Attempt to replace all uses of the given symbol 'oldSymbol' with the 721ef43b565SRiver Riddle /// provided symbol 'newSymbol' that are nested within the given operation 722ef43b565SRiver Riddle /// 'from'. This does not traverse into any nested symbol tables, and will 723ef43b565SRiver Riddle /// also only replace uses on 'from' if it does not also define a symbol 724ef43b565SRiver Riddle /// table. This is because we treat the region as the boundary of the symbol 725ef43b565SRiver Riddle /// table, and not the op itself. If there are any unknown operations that may 726ef43b565SRiver Riddle /// potentially be symbol tables, no uses are replaced and failure is returned. 727ef43b565SRiver Riddle LogicalResult SymbolTable::replaceAllSymbolUses(StringRef oldSymbol, 728ef43b565SRiver Riddle StringRef newSymbol, 729ef43b565SRiver Riddle Operation *from) { 730*6fca03f0SRiver Riddle return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from); 731ef43b565SRiver Riddle } 732*6fca03f0SRiver Riddle LogicalResult SymbolTable::replaceAllSymbolUses(Operation *oldSymbol, 733*6fca03f0SRiver Riddle StringRef newSymbol, 734*6fca03f0SRiver Riddle Operation *from) { 735*6fca03f0SRiver Riddle return replaceAllSymbolUsesImpl(oldSymbol, newSymbol, from); 736ef43b565SRiver Riddle } 737