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