CIRCT 24.0.0git
Loading...
Searching...
No Matches
SVDialect.cpp
Go to the documentation of this file.
1//===- SVDialect.cpp - Implement the SV dialect ---------------------------===//
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 implements the SV dialect.
10//
11//===----------------------------------------------------------------------===//
12
18
19#include "mlir/IR/DialectImplementation.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/ADT/StringSet.h"
23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/Support/ManagedStatic.h"
25
26using namespace circt;
27using namespace circt::sv;
28
29//===----------------------------------------------------------------------===//
30// Dialect specification.
31//===----------------------------------------------------------------------===//
32
33namespace {
34/// Reject NetType or VarType on output direction module ports. Handle types
35/// are only meaningful as an input direction block argument; a module result
36/// is always a pure SSA value.
37struct SVHandleModulePortTypeInterface : public hw::HWModulePortTypeInterface {
39
40 LogicalResult
41 verifyHWModulePortType(function_ref<InFlightDiagnostic()> emitError,
43 Type type) const override {
44 if (direction == hw::ModulePort::Output) {
45 if (isa<NetType>(type))
46 return emitError()
47 << "sv.net handles are not supported on output ports";
48 if (isa<VarType>(type))
49 return emitError()
50 << "sv.var handles are not supported on output ports";
51 }
52 return success();
53 }
54};
55} // namespace
56
57void SVDialect::initialize() {
58 // Register types and attributes.
59 registerTypes();
60 registerAttributes();
61
62 // Register operations.
63 addOperations<
64#define GET_OP_LIST
65#include "circt/Dialect/SV/SV.cpp.inc"
66 >();
67
68 // Register interface implementations.
69 addInterfaces<SVHandleModulePortTypeInterface>();
70}
71
72#define GET_ATTRDEF_CLASSES
73#include "circt/Dialect/SV/SVDialect.cpp.inc"
74
75//===----------------------------------------------------------------------===//
76// Name conflict resolution
77//===----------------------------------------------------------------------===//
78
79/// Return a StringSet that contains all of the reserved names (e.g. Verilog
80/// keywords) that we need to avoid for fear of name conflicts.
82 static void *call() {
83 auto set = std::make_unique<StringSet<>>();
84 static const char *const reservedWords[] = {
85#include "ReservedWords.def"
86 };
87 for (auto *word : reservedWords)
88 set->insert(word);
89 return set.release();
90 }
91};
92
93/// A StringSet that contains all of the reserved names (e.g., Verilog and VHDL
94/// keywords) that we need to avoid to prevent naming conflicts.
95static llvm::ManagedStatic<StringSet<>, ReservedWordsCreator> reservedWords;
96
97/// Given string \p origName, generate a new name if it conflicts with any
98/// keyword or any other name in the set \p recordNames. Use the int \p
99/// nextGeneratedNameID as a counter for suffix. Update the \p recordNames with
100/// the generated name and return the StringRef.
101StringRef
102circt::sv::resolveKeywordConflict(StringRef origName,
103 llvm::StringMap<size_t> &nextGeneratedNameIDs,
104 bool caseInsensitiveKeywords) {
105 // Get the list of reserved words we need to avoid. We could prepopulate this
106 // into the used words cache, but it is large and immutable, so we just query
107 // it when needed.
108
109 // Fast path: name is valid
110 if (!reservedWords->contains(caseInsensitiveKeywords ? origName.lower()
111 : origName)) {
112 auto itAndInserted = nextGeneratedNameIDs.insert({origName, 0});
113 if (itAndInserted.second)
114 return itAndInserted.first->getKey();
115 }
116
117 // We need to mutate the name, get the copy ready.
118 SmallString<16> nameBuffer(origName.begin(), origName.end());
119 nameBuffer.push_back('_');
120 auto baseSize = nameBuffer.size();
121 auto &nextGeneratedNameID = nextGeneratedNameIDs[origName];
122
123 while (1) {
124 // We need to auto-unique it.
125 auto suffix = llvm::utostr(nextGeneratedNameID++);
126 nameBuffer.append(suffix.begin(), suffix.end());
127
128 // The name may be unique. No keywords have an underscore followed by a
129 // number, so don't check that again.
130 auto itAndInserted = nextGeneratedNameIDs.insert({nameBuffer, 0});
131 if (itAndInserted.second)
132 return itAndInserted.first->getKey();
133
134 // Chop off the suffix and try again until we get a unique name..
135 nameBuffer.resize(baseSize);
136 }
137}
138
139static bool isValidVerilogCharacterFirst(char ch) {
140 return llvm::isAlpha(ch) || ch == '_';
141}
142
143static bool isValidVerilogCharacter(char ch) {
144 return isValidVerilogCharacterFirst(ch) || llvm::isDigit(ch) || ch == '$';
145}
146
147/// Legalize the specified name for use in SV output. Auto-uniquifies the name
148/// through \c resolveKeywordConflict if required. If the name is empty, a
149/// unique temp name is created.
150StringRef circt::sv::legalizeName(StringRef name,
151 llvm::StringMap<size_t> &nextGeneratedNameIDs,
152 bool caseInsensitiveKeywords) {
153
154 // Fastest path: empty name.
155 if (name.empty())
156 return resolveKeywordConflict("_GEN", nextGeneratedNameIDs,
157 caseInsensitiveKeywords);
158
159 // Check that the name is valid as the semi-fast path.
160 if (llvm::all_of(name, isValidVerilogCharacter) &&
161 isValidVerilogCharacterFirst(name.front()))
162 return resolveKeywordConflict(name, nextGeneratedNameIDs,
163 caseInsensitiveKeywords);
164
165 // The name consists of at least one invalid character. Escape it.
166 SmallString<16> tmpName;
167 if (!isValidVerilogCharacterFirst(name.front()) && name.front() != ' ' &&
168 name.front() != '.')
169 tmpName += '_';
170 for (char ch : name) {
172 tmpName += ch;
173 else if (ch == ' ' || ch == '.')
174 tmpName += '_';
175 else {
176 tmpName += llvm::utohexstr((unsigned char)ch);
177 }
178 }
179
180 // Make sure the new valid name does not conflict with any existing names.
181 return resolveKeywordConflict(tmpName, nextGeneratedNameIDs,
182 caseInsensitiveKeywords);
183}
184
185/// Check if a name is valid for use in SV output by only containing characters
186/// allowed in SV identifiers.
187///
188/// Call \c legalizeName() to obtain a legalized version of the name.
189bool circt::sv::isNameValid(StringRef name, bool caseInsensitiveKeywords) {
190 if (name.empty())
191 return false;
192 if (name.front() == '\\') {
193 // Check if the name is a valid escaped name.
194 if (name.size() < 2)
195 return false;
196 for (auto ch : name.drop_front()) {
197 bool isValidChar = llvm::isPrint(ch) && !llvm::isSpace(ch);
198 if (!isValidChar)
199 return false;
200 }
201 } else {
202 if (!isValidVerilogCharacterFirst(name.front()))
203 return false;
204 for (char ch : name) {
206 return false;
207 }
208 }
209
210 return reservedWords->contains(caseInsensitiveKeywords ? name.lower()
211 : name) == 0;
212}
return success()
static bool isValidVerilogCharacterFirst(char ch)
static llvm::ManagedStatic< StringSet<>, ReservedWordsCreator > reservedWords
A StringSet that contains all of the reserved names (e.g., Verilog and VHDL keywords) that we need to...
Definition SVDialect.cpp:95
static bool isValidVerilogCharacter(char ch)
llvm::StringRef resolveKeywordConflict(llvm::StringRef origName, llvm::StringMap< size_t > &nextGeneratedNameIDs, bool caseInsensitiveKeywords)
Given string origName, generate a new name if it conflicts with any keyword or any other name in the ...
StringRef legalizeName(llvm::StringRef name, llvm::StringMap< size_t > &nextGeneratedNameIDs, bool caseInsensitiveKeywords)
Legalize the specified name for use in SV output.
bool isNameValid(llvm::StringRef name, bool caseInsensitiveKeywords)
Check if a name is valid for use in SV output by only containing characters allowed in SV identifiers...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Return a StringSet that contains all of the reserved names (e.g.
Definition SVDialect.cpp:81
static void * call()
Definition SVDialect.cpp:82
HWModulePortTypeInterface(mlir::Dialect *dialect)
Definition HWTypes.h:40