MLIR  21.0.0git
Namespace.h
Go to the documentation of this file.
1 //===- Namespace.h - Utilities for generating names -------------*- C++ -*-===//
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 // This file provides utilities for generating new names that do not conflict
10 // with existing names.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_SUPPORT_NAMESPACE_H
15 #define MLIR_SUPPORT_NAMESPACE_H
16 
17 #include "mlir/IR/BuiltinOps.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/StringSet.h"
21 #include "llvm/ADT/Twine.h"
22 
23 namespace mlir {
24 
25 /// A namespace that is used to store existing names and generate new names in
26 /// some scope within the IR. This exists to work around limitations of
27 /// SymbolTables. This acts as a base class providing facilities common to all
28 /// namespaces implementations.
29 class Namespace {
30 public:
32  // This fills an entry for an empty string beforehand so that `newName`
33  // doesn't return an empty string.
34  nextIndex.insert({"", 0});
35  }
36  Namespace(const Namespace &other) = default;
38  : nextIndex(std::move(other.nextIndex)), locked(other.locked) {}
39 
40  Namespace &operator=(const Namespace &other) = default;
42  nextIndex = std::move(other.nextIndex);
43  locked = other.locked;
44  return *this;
45  }
46 
47  void add(mlir::ModuleOp module) {
48  assert(module->getNumRegions() == 1);
49  for (auto &op : module.getBody(0)->getOperations())
50  if (auto symbol = op.getAttrOfType<mlir::StringAttr>(
52  nextIndex.insert({symbol.getValue(), 0});
53  }
54 
55  /// SymbolCache initializer; initialize from every key that is convertible to
56  /// a StringAttr in the SymbolCache.
57  void add(SymbolCache &symCache) {
58  for (auto &&[attr, _] : symCache)
59  if (auto strAttr = dyn_cast<mlir::StringAttr>(attr))
60  nextIndex.insert({strAttr.getValue(), 0});
61  }
62 
63  void add(llvm::StringRef name) { nextIndex.insert({name, 0}); }
64 
65  /// Removes a symbol from the namespace. Returns true if the symbol was
66  /// removed, false if the symbol was not found.
67  /// This is only allowed to be called _before_ any call to newName.
68  bool erase(llvm::StringRef symbol) {
69  assert(!locked && "Cannot erase names from a locked namespace");
70  return nextIndex.erase(symbol);
71  }
72 
73  /// Empty the namespace.
74  void clear() {
75  nextIndex.clear();
76  locked = false;
77  }
78 
79  /// Return a unique name, derived from the input `name`, and add the new name
80  /// to the internal namespace. There are two possible outcomes for the
81  /// returned name:
82  ///
83  /// 1. The original name is returned.
84  /// 2. The name is given a `_<n>` suffix where `<n>` is a number starting from
85  /// `0` and incrementing by one each time (`_0`, ...).
86  llvm::StringRef newName(const llvm::Twine &name) {
87  locked = true;
88  // Special case the situation where there is no name collision to avoid
89  // messing with the SmallString allocation below.
90  llvm::SmallString<64> tryName;
91  auto inserted = nextIndex.insert({name.toStringRef(tryName), 0});
92  if (inserted.second)
93  return inserted.first->getKey();
94 
95  // Try different suffixes until we get a collision-free one.
96  if (tryName.empty())
97  name.toVector(tryName); // toStringRef may leave tryName unfilled
98 
99  // Indexes less than nextIndex[tryName] are lready used, so skip them.
100  // Indexes larger than nextIndex[tryName] may be used in another name.
101  size_t &i = nextIndex[tryName];
102  tryName.push_back('_');
103  size_t baseLength = tryName.size();
104  do {
105  tryName.resize(baseLength);
106  llvm::Twine(i++).toVector(tryName); // append integer to tryName
107  inserted = nextIndex.insert({tryName, 0});
108  } while (!inserted.second);
109 
110  return inserted.first->getKey();
111  }
112 
113  /// Return a unique name, derived from the input `name` and ensure the
114  /// returned name has the input `suffix`. Also add the new name to the
115  /// internal namespace.
116  /// There are two possible outcomes for the returned name:
117  /// 1. The original name + `_<suffix>` is returned.
118  /// 2. The name is given a suffix `_<n>_<suffix>` where `<n>` is a number
119  /// starting from `0` and incrementing by one each time.
120  llvm::StringRef newName(const llvm::Twine &name, const llvm::Twine &suffix) {
121  locked = true;
122  // Special case the situation where there is no name collision to avoid
123  // messing with the SmallString allocation below.
124  llvm::SmallString<64> tryName;
125  auto inserted = nextIndex.insert(
126  {name.concat("_").concat(suffix).toStringRef(tryName), 0});
127  if (inserted.second)
128  return inserted.first->getKey();
129 
130  // Try different suffixes until we get a collision-free one.
131  tryName.clear();
132  name.toVector(tryName); // toStringRef may leave tryName unfilled
133  tryName.push_back('_');
134  size_t baseLength = tryName.size();
135 
136  // Get the initial number to start from. Since `:` is not a valid character
137  // in a verilog identifier, we use it separate the name and suffix.
138  // Next number for name+suffix is stored with key `name_:suffix`.
139  tryName.push_back(':');
140  suffix.toVector(tryName);
141 
142  // Indexes less than nextIndex[tryName] are already used, so skip them.
143  // Indexes larger than nextIndex[tryName] may be used in another name.
144  size_t &i = nextIndex[tryName];
145  do {
146  tryName.resize(baseLength);
147  llvm::Twine(i++).toVector(tryName); // append integer to tryName
148  tryName.push_back('_');
149  suffix.toVector(tryName);
150  inserted = nextIndex.insert({tryName, 0});
151  } while (!inserted.second);
152 
153  return inserted.first->getKey();
154  }
155 
156 protected:
157  // The "next index" that will be tried when trying to unique a string within a
158  // namespace. It follows that all values less than the "next index" value are
159  // already used.
160  llvm::StringMap<size_t> nextIndex;
161 
162  // When true, no names can be erased from the namespace. This is to prevent
163  // erasing names after they have been used, thus leaving users of the
164  // namespace in an inconsistent state.
165  bool locked = false;
166 };
167 
168 } // namespace mlir
169 
170 #endif // MLIR_SUPPORT_NAMESPACE_H
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition: Namespace.h:29
llvm::StringMap< size_t > nextIndex
Definition: Namespace.h:160
void add(SymbolCache &symCache)
SymbolCache initializer; initialize from every key that is convertible to a StringAttr in the SymbolC...
Definition: Namespace.h:57
llvm::StringRef newName(const llvm::Twine &name, const llvm::Twine &suffix)
Return a unique name, derived from the input name and ensure the returned name has the input suffix.
Definition: Namespace.h:120
Namespace(Namespace &&other)
Definition: Namespace.h:37
bool erase(llvm::StringRef symbol)
Removes a symbol from the namespace.
Definition: Namespace.h:68
void add(mlir::ModuleOp module)
Definition: Namespace.h:47
void add(llvm::StringRef name)
Definition: Namespace.h:63
Namespace & operator=(const Namespace &other)=default
void clear()
Empty the namespace.
Definition: Namespace.h:74
llvm::StringRef newName(const llvm::Twine &name)
Return a unique name, derived from the input name, and add the new name to the internal namespace.
Definition: Namespace.h:86
Namespace(const Namespace &other)=default
Namespace & operator=(Namespace &&other)
Definition: Namespace.h:41
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
Definition: SymCache.h:85
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition: SymbolTable.h:76
SmallVector< AffineExpr, 4 > concat(ArrayRef< AffineExpr > a, ArrayRef< AffineExpr > b)
Return the vector that is the concatenation of a and b.
Definition: LinalgOps.cpp:2352
Include the generated interface declarations.