CIRCT  19.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 CIRCT_SUPPORT_NAMESPACE_H
15 #define CIRCT_SUPPORT_NAMESPACE_H
16 
17 #include "circt/Support/LLVM.h"
18 #include "circt/Support/SymCache.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/StringSet.h"
21 #include "llvm/ADT/Twine.h"
22 
23 namespace circt {
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;
37  Namespace(Namespace &&other) : nextIndex(std::move(other.nextIndex)) {}
38 
39  Namespace &operator=(const Namespace &other) = default;
41  nextIndex = std::move(other.nextIndex);
42  return *this;
43  }
44 
45  /// SymbolCache initializer; initialize from every key that is convertible to
46  /// a StringAttr in the SymbolCache.
47  void add(SymbolCache &symCache) {
48  for (auto &&[attr, _] : symCache)
49  if (auto strAttr = dyn_cast<StringAttr>(attr))
50  nextIndex.insert({strAttr.getValue(), 0});
51  }
52 
53  /// Empty the namespace.
54  void clear() { nextIndex.clear(); }
55 
56  /// Return a unique name, derived from the input `name`, and add the new name
57  /// to the internal namespace. There are two possible outcomes for the
58  /// returned name:
59  ///
60  /// 1. The original name is returned.
61  /// 2. The name is given a `_<n>` suffix where `<n>` is a number starting from
62  /// `0` and incrementing by one each time (`_0`, ...).
63  StringRef newName(const Twine &name) {
64  // Special case the situation where there is no name collision to avoid
65  // messing with the SmallString allocation below.
66  llvm::SmallString<64> tryName;
67  auto inserted = nextIndex.insert({name.toStringRef(tryName), 0});
68  if (inserted.second)
69  return inserted.first->getKey();
70 
71  // Try different suffixes until we get a collision-free one.
72  if (tryName.empty())
73  name.toVector(tryName); // toStringRef may leave tryName unfilled
74 
75  // Indexes less than nextIndex[tryName] are lready used, so skip them.
76  // Indexes larger than nextIndex[tryName] may be used in another name.
77  size_t &i = nextIndex[tryName];
78  tryName.push_back('_');
79  size_t baseLength = tryName.size();
80  do {
81  tryName.resize(baseLength);
82  Twine(i++).toVector(tryName); // append integer to tryName
83  inserted = nextIndex.insert({tryName, 0});
84  } while (!inserted.second);
85 
86  return inserted.first->getKey();
87  }
88 
89  /// Return a unique name, derived from the input `name` and ensure the
90  /// returned name has the input `suffix`. Also add the new name to the
91  /// internal namespace.
92  /// There are two possible outcomes for the returned name:
93  /// 1. The original name + `_<suffix>` is returned.
94  /// 2. The name is given a suffix `_<n>_<suffix>` where `<n>` is a number
95  /// starting from `0` and incrementing by one each time.
96  StringRef newName(const Twine &name, const Twine &suffix) {
97  // Special case the situation where there is no name collision to avoid
98  // messing with the SmallString allocation below.
99  llvm::SmallString<64> tryName;
100  auto inserted = nextIndex.insert(
101  {name.concat("_").concat(suffix).toStringRef(tryName), 0});
102  if (inserted.second)
103  return inserted.first->getKey();
104 
105  // Try different suffixes until we get a collision-free one.
106  tryName.clear();
107  name.toVector(tryName); // toStringRef may leave tryName unfilled
108  tryName.push_back('_');
109  size_t baseLength = tryName.size();
110 
111  // Get the initial number to start from. Since `:` is not a valid character
112  // in a verilog identifier, we use it separate the name and suffix.
113  // Next number for name+suffix is stored with key `name_:suffix`.
114  tryName.push_back(':');
115  suffix.toVector(tryName);
116 
117  // Indexes less than nextIndex[tryName] are already used, so skip them.
118  // Indexes larger than nextIndex[tryName] may be used in another name.
119  size_t &i = nextIndex[tryName];
120  do {
121  tryName.resize(baseLength);
122  Twine(i++).toVector(tryName); // append integer to tryName
123  tryName.push_back('_');
124  suffix.toVector(tryName);
125  inserted = nextIndex.insert({tryName, 0});
126  } while (!inserted.second);
127 
128  return inserted.first->getKey();
129  }
130 
131 protected:
132  // The "next index" that will be tried when trying to unique a string within a
133  // namespace. It follows that all values less than the "next index" value are
134  // already used.
135  llvm::StringMap<size_t> nextIndex;
136 };
137 
138 } // namespace circt
139 
140 #endif // CIRCT_SUPPORT_NAMESPACE_H
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
Definition: CalyxOps.cpp:539
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition: Namespace.h:29
Namespace & operator=(const Namespace &other)=default
void clear()
Empty the namespace.
Definition: Namespace.h:54
Namespace & operator=(Namespace &&other)
Definition: Namespace.h:40
llvm::StringMap< size_t > nextIndex
Definition: Namespace.h:135
void add(SymbolCache &symCache)
SymbolCache initializer; initialize from every key that is convertible to a StringAttr in the SymbolC...
Definition: Namespace.h:47
StringRef newName(const Twine &name, const Twine &suffix)
Return a unique name, derived from the input name and ensure the returned name has the input suffix.
Definition: Namespace.h:96
Namespace(Namespace &&other)
Definition: Namespace.h:37
Namespace(const Namespace &other)=default
StringRef newName(const Twine &name)
Return a unique name, derived from the input name, and add the new name to the internal namespace.
Definition: Namespace.h:63
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
Definition: SymCache.h:85
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21