MLIR 22.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
23namespace 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.
29class Namespace {
30public:
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.
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
156protected:
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
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
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 & operator=(const Namespace &other)=default
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
Namespace & operator=(Namespace &&other)
Definition Namespace.h:41
void add(llvm::StringRef name)
Definition Namespace.h:63
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
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
Include the generated interface declarations.