1927b7074SRiver Riddle //===- SymbolTable.cpp - MLIR Symbol Table Class --------------------------===// 2927b7074SRiver Riddle // 3927b7074SRiver Riddle // Copyright 2019 The MLIR Authors. 4927b7074SRiver Riddle // 5927b7074SRiver Riddle // Licensed under the Apache License, Version 2.0 (the "License"); 6927b7074SRiver Riddle // you may not use this file except in compliance with the License. 7927b7074SRiver Riddle // You may obtain a copy of the License at 8927b7074SRiver Riddle // 9927b7074SRiver Riddle // http://www.apache.org/licenses/LICENSE-2.0 10927b7074SRiver Riddle // 11927b7074SRiver Riddle // Unless required by applicable law or agreed to in writing, software 12927b7074SRiver Riddle // distributed under the License is distributed on an "AS IS" BASIS, 13927b7074SRiver Riddle // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14927b7074SRiver Riddle // See the License for the specific language governing permissions and 15927b7074SRiver Riddle // limitations under the License. 16927b7074SRiver Riddle // ============================================================================= 17927b7074SRiver Riddle 18927b7074SRiver Riddle #include "mlir/IR/SymbolTable.h" 19ee8e8b55SRiver Riddle #include "llvm/ADT/SmallString.h" 20927b7074SRiver Riddle 21927b7074SRiver Riddle using namespace mlir; 22927b7074SRiver Riddle 23ee8e8b55SRiver Riddle /// Build a symbol table with the symbols within the given operation. 24ee8e8b55SRiver Riddle SymbolTable::SymbolTable(Operation *op) : context(op->getContext()) { 25ee8e8b55SRiver Riddle assert(op->hasTrait<OpTrait::SymbolTable>() && 26ee8e8b55SRiver Riddle "expected operation to have SymbolTable trait"); 27ee8e8b55SRiver Riddle assert(op->getNumRegions() == 1 && 28ee8e8b55SRiver Riddle "expected operation to have a single region"); 29ee8e8b55SRiver Riddle 30ee8e8b55SRiver Riddle for (auto &block : op->getRegion(0)) { 31ee8e8b55SRiver Riddle for (auto &op : block) { 32ee8e8b55SRiver Riddle auto nameAttr = op.getAttrOfType<StringAttr>(getSymbolAttrName()); 33ee8e8b55SRiver Riddle if (!nameAttr) 34ee8e8b55SRiver Riddle continue; 35ee8e8b55SRiver Riddle 36ee8e8b55SRiver Riddle auto inserted = symbolTable.insert({nameAttr.getValue(), &op}); 378c47e2edSRiver Riddle (void)inserted; 388c47e2edSRiver Riddle assert(inserted.second && 39ee8e8b55SRiver Riddle "expected region to contain uniquely named symbol operations"); 40ee8e8b55SRiver Riddle } 418c47e2edSRiver Riddle } 428c47e2edSRiver Riddle } 438c47e2edSRiver Riddle 44927b7074SRiver Riddle /// Look up a symbol with the specified name, returning null if no such name 45927b7074SRiver Riddle /// exists. Names never include the @ on them. 46ee8e8b55SRiver Riddle Operation *SymbolTable::lookup(StringRef name) const { 47e7d594bbSRiver Riddle return symbolTable.lookup(name); 48927b7074SRiver Riddle } 49927b7074SRiver Riddle 50927b7074SRiver Riddle /// Erase the given symbol from the table. 51ee8e8b55SRiver Riddle void SymbolTable::erase(Operation *symbol) { 52ee8e8b55SRiver Riddle auto nameAttr = symbol->getAttrOfType<StringAttr>(getSymbolAttrName()); 53ee8e8b55SRiver Riddle assert(nameAttr && "expected valid 'name' attribute"); 54ee8e8b55SRiver Riddle 55ee8e8b55SRiver Riddle auto it = symbolTable.find(nameAttr.getValue()); 56927b7074SRiver Riddle if (it != symbolTable.end() && it->second == symbol) 57927b7074SRiver Riddle symbolTable.erase(it); 58927b7074SRiver Riddle } 59927b7074SRiver Riddle 60927b7074SRiver Riddle /// Insert a new symbol into the table, and rename it as necessary to avoid 61927b7074SRiver Riddle /// collisions. 62ee8e8b55SRiver Riddle void SymbolTable::insert(Operation *symbol) { 63ee8e8b55SRiver Riddle auto nameAttr = symbol->getAttrOfType<StringAttr>(getSymbolAttrName()); 64ee8e8b55SRiver Riddle assert(nameAttr && "expected valid 'name' attribute"); 65ee8e8b55SRiver Riddle 66927b7074SRiver Riddle // Add this symbol to the symbol table, uniquing the name if a conflict is 67927b7074SRiver Riddle // detected. 68ee8e8b55SRiver Riddle if (symbolTable.insert({nameAttr.getValue(), symbol}).second) 69927b7074SRiver Riddle return; 70927b7074SRiver Riddle 71ee8e8b55SRiver Riddle // If a conflict was detected, then the symbol will not have been added to 72927b7074SRiver Riddle // the symbol table. Try suffixes until we get to a unique name that works. 73ee8e8b55SRiver Riddle SmallString<128> nameBuffer(nameAttr.getValue()); 74927b7074SRiver Riddle unsigned originalLength = nameBuffer.size(); 75927b7074SRiver Riddle 76ee8e8b55SRiver Riddle // Iteratively try suffixes until we find one that isn't used. 77927b7074SRiver Riddle do { 78927b7074SRiver Riddle nameBuffer.resize(originalLength); 79927b7074SRiver Riddle nameBuffer += '_'; 80927b7074SRiver Riddle nameBuffer += std::to_string(uniquingCounter++); 81e7d594bbSRiver Riddle } while (!symbolTable.insert({nameBuffer, symbol}).second); 82ee8e8b55SRiver Riddle symbol->setAttr(getSymbolAttrName(), StringAttr::get(nameBuffer, context)); 83ee8e8b55SRiver Riddle } 84ee8e8b55SRiver Riddle 85*8cb405a8SRiver Riddle /// Returns the operation registered with the given symbol name with the 86*8cb405a8SRiver Riddle /// regions of 'symbolTableOp'. 'symbolTableOp' is required to be an operation 87*8cb405a8SRiver Riddle /// with the 'OpTrait::SymbolTable' trait. Returns nullptr if no valid symbol 88*8cb405a8SRiver Riddle /// was found. 89*8cb405a8SRiver Riddle Operation *SymbolTable::lookupSymbolIn(Operation *symbolTableOp, 90*8cb405a8SRiver Riddle StringRef symbol) { 91*8cb405a8SRiver Riddle assert(symbolTableOp->hasTrait<OpTrait::SymbolTable>()); 92*8cb405a8SRiver Riddle 93*8cb405a8SRiver Riddle // Look for a symbol with the given name. 94*8cb405a8SRiver Riddle for (auto &block : symbolTableOp->getRegion(0)) { 95*8cb405a8SRiver Riddle for (auto &op : block) { 96*8cb405a8SRiver Riddle auto nameAttr = op.template getAttrOfType<StringAttr>( 97*8cb405a8SRiver Riddle mlir::SymbolTable::getSymbolAttrName()); 98*8cb405a8SRiver Riddle if (nameAttr && nameAttr.getValue() == symbol) 99*8cb405a8SRiver Riddle return &op; 100*8cb405a8SRiver Riddle } 101*8cb405a8SRiver Riddle } 102*8cb405a8SRiver Riddle return nullptr; 103*8cb405a8SRiver Riddle } 104*8cb405a8SRiver Riddle 105*8cb405a8SRiver Riddle /// Returns the operation registered with the given symbol name within the 106*8cb405a8SRiver Riddle /// closes parent operation with the 'OpTrait::SymbolTable' trait. Returns 107*8cb405a8SRiver Riddle /// nullptr if no valid symbol was found. 108*8cb405a8SRiver Riddle Operation *SymbolTable::lookupNearestSymbolFrom(Operation *from, 109*8cb405a8SRiver Riddle StringRef symbol) { 110*8cb405a8SRiver Riddle while (from && !from->hasTrait<OpTrait::SymbolTable>()) 111*8cb405a8SRiver Riddle from = from->getParentOp(); 112*8cb405a8SRiver Riddle return from ? lookupSymbolIn(from, symbol) : nullptr; 113*8cb405a8SRiver Riddle } 114*8cb405a8SRiver Riddle 115ee8e8b55SRiver Riddle //===----------------------------------------------------------------------===// 116ee8e8b55SRiver Riddle // SymbolTable Trait Types 117ee8e8b55SRiver Riddle //===----------------------------------------------------------------------===// 118ee8e8b55SRiver Riddle 119ee8e8b55SRiver Riddle LogicalResult OpTrait::impl::verifySymbolTable(Operation *op) { 120ee8e8b55SRiver Riddle if (op->getNumRegions() != 1) 121ee8e8b55SRiver Riddle return op->emitOpError() 122ee8e8b55SRiver Riddle << "Operations with a 'SymbolTable' must have exactly one region"; 123ee8e8b55SRiver Riddle 124ee8e8b55SRiver Riddle // Check that all symboles are uniquely named within child regions. 125ee8e8b55SRiver Riddle llvm::StringMap<Location> nameToOrigLoc; 126ee8e8b55SRiver Riddle for (auto &block : op->getRegion(0)) { 127ee8e8b55SRiver Riddle for (auto &op : block) { 128ee8e8b55SRiver Riddle // Check for a symbol name attribute. 129ee8e8b55SRiver Riddle auto nameAttr = 130ee8e8b55SRiver Riddle op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName()); 131ee8e8b55SRiver Riddle if (!nameAttr) 132ee8e8b55SRiver Riddle continue; 133ee8e8b55SRiver Riddle 134ee8e8b55SRiver Riddle // Try to insert this symbol into the table. 135ee8e8b55SRiver Riddle auto it = nameToOrigLoc.try_emplace(nameAttr.getValue(), op.getLoc()); 136ee8e8b55SRiver Riddle if (!it.second) 137ee8e8b55SRiver Riddle return op.emitError() 138ee8e8b55SRiver Riddle .append("redefinition of symbol named '", nameAttr.getValue(), "'") 139ee8e8b55SRiver Riddle .attachNote(it.first->second) 140ee8e8b55SRiver Riddle .append("see existing symbol definition here"); 141ee8e8b55SRiver Riddle } 142ee8e8b55SRiver Riddle } 143ee8e8b55SRiver Riddle return success(); 144927b7074SRiver Riddle } 145