CIRCT 20.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
17
18#include "mlir/IR/DialectImplementation.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/StringExtras.h"
21#include "llvm/ADT/StringSet.h"
22#include "llvm/ADT/TypeSwitch.h"
23#include "llvm/Support/ManagedStatic.h"
24
25using namespace circt;
26using namespace circt::sv;
27
28//===----------------------------------------------------------------------===//
29// Dialect specification.
30//===----------------------------------------------------------------------===//
31
32void SVDialect::initialize() {
33 // Register types and attributes.
34 registerTypes();
35 registerAttributes();
36
37 // Register operations.
38 addOperations<
39#define GET_OP_LIST
40#include "circt/Dialect/SV/SV.cpp.inc"
41 >();
42}
43
44#define GET_ATTRDEF_CLASSES
45#include "circt/Dialect/SV/SVDialect.cpp.inc"
46
47//===----------------------------------------------------------------------===//
48// Name conflict resolution
49//===----------------------------------------------------------------------===//
50
51/// Return a StringSet that contains all of the reserved names (e.g. Verilog
52/// keywords) that we need to avoid for fear of name conflicts.
54 static void *call() {
55 auto set = std::make_unique<StringSet<>>();
56 static const char *const reservedWords[] = {
57#include "ReservedWords.def"
58 };
59 for (auto *word : reservedWords)
60 set->insert(word);
61 return set.release();
62 }
63};
64
65/// A StringSet that contains all of the reserved names (e.g., Verilog and VHDL
66/// keywords) that we need to avoid to prevent naming conflicts.
67static llvm::ManagedStatic<StringSet<>, ReservedWordsCreator> reservedWords;
68
69/// Given string \p origName, generate a new name if it conflicts with any
70/// keyword or any other name in the set \p recordNames. Use the int \p
71/// nextGeneratedNameID as a counter for suffix. Update the \p recordNames with
72/// the generated name and return the StringRef.
73StringRef
74circt::sv::resolveKeywordConflict(StringRef origName,
75 llvm::StringMap<size_t> &nextGeneratedNameIDs,
76 bool caseInsensitiveKeywords) {
77 // Get the list of reserved words we need to avoid. We could prepopulate this
78 // into the used words cache, but it is large and immutable, so we just query
79 // it when needed.
80
81 // Fast path: name is valid
82 if (!reservedWords->contains(caseInsensitiveKeywords ? origName.lower()
83 : origName)) {
84 auto itAndInserted = nextGeneratedNameIDs.insert({origName, 0});
85 if (itAndInserted.second)
86 return itAndInserted.first->getKey();
87 }
88
89 // We need to mutate the name, get the copy ready.
90 SmallString<16> nameBuffer(origName.begin(), origName.end());
91 nameBuffer.push_back('_');
92 auto baseSize = nameBuffer.size();
93 auto &nextGeneratedNameID = nextGeneratedNameIDs[origName];
94
95 while (1) {
96 // We need to auto-unique it.
97 auto suffix = llvm::utostr(nextGeneratedNameID++);
98 nameBuffer.append(suffix.begin(), suffix.end());
99
100 // The name may be unique. No keywords have an underscore followed by a
101 // number, so don't check that again.
102 auto itAndInserted = nextGeneratedNameIDs.insert({nameBuffer, 0});
103 if (itAndInserted.second)
104 return itAndInserted.first->getKey();
105
106 // Chop off the suffix and try again until we get a unique name..
107 nameBuffer.resize(baseSize);
108 }
109}
110
111static bool isValidVerilogCharacterFirst(char ch) {
112 return llvm::isAlpha(ch) || ch == '_';
113}
114
115static bool isValidVerilogCharacter(char ch) {
116 return isValidVerilogCharacterFirst(ch) || llvm::isDigit(ch) || ch == '$';
117}
118
119/// Legalize the specified name for use in SV output. Auto-uniquifies the name
120/// through \c resolveKeywordConflict if required. If the name is empty, a
121/// unique temp name is created.
122StringRef circt::sv::legalizeName(StringRef name,
123 llvm::StringMap<size_t> &nextGeneratedNameIDs,
124 bool caseInsensitiveKeywords) {
125
126 // Fastest path: empty name.
127 if (name.empty())
128 return resolveKeywordConflict("_GEN", nextGeneratedNameIDs,
129 caseInsensitiveKeywords);
130
131 // Check that the name is valid as the semi-fast path.
132 if (llvm::all_of(name, isValidVerilogCharacter) &&
133 isValidVerilogCharacterFirst(name.front()))
134 return resolveKeywordConflict(name, nextGeneratedNameIDs,
135 caseInsensitiveKeywords);
136
137 // The name consists of at least one invalid character. Escape it.
138 SmallString<16> tmpName;
139 if (!isValidVerilogCharacterFirst(name.front()) && name.front() != ' ' &&
140 name.front() != '.')
141 tmpName += '_';
142 for (char ch : name) {
144 tmpName += ch;
145 else if (ch == ' ' || ch == '.')
146 tmpName += '_';
147 else {
148 tmpName += llvm::utohexstr((unsigned char)ch);
149 }
150 }
151
152 // Make sure the new valid name does not conflict with any existing names.
153 return resolveKeywordConflict(tmpName, nextGeneratedNameIDs,
154 caseInsensitiveKeywords);
155}
156
157/// Check if a name is valid for use in SV output by only containing characters
158/// allowed in SV identifiers.
159///
160/// Call \c legalizeName() to obtain a legalized version of the name.
161bool circt::sv::isNameValid(StringRef name, bool caseInsensitiveKeywords) {
162 if (name.empty())
163 return false;
164 if (!isValidVerilogCharacterFirst(name.front()))
165 return false;
166 for (char ch : name) {
168 return false;
169 }
170
171 return reservedWords->contains(caseInsensitiveKeywords ? name.lower()
172 : name) == 0;
173}
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:67
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:53
static void * call()
Definition SVDialect.cpp:54