CIRCT  20.0.0git
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 
15 #include "circt/Dialect/SV/SVOps.h"
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 
25 using namespace circt;
26 using namespace circt::sv;
27 
28 //===----------------------------------------------------------------------===//
29 // Dialect specification.
30 //===----------------------------------------------------------------------===//
31 
32 void 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.
67 static 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.
73 StringRef
74 circt::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 
111 static bool isValidVerilogCharacterFirst(char ch) {
112  return llvm::isAlpha(ch) || ch == '_';
113 }
114 
115 static 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.
122 StringRef 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) {
143  if (isValidVerilogCharacter(ch))
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.
161 bool 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) {
167  if (!isValidVerilogCharacter(ch))
168  return false;
169  }
170 
171  return reservedWords->contains(caseInsensitiveKeywords ? name.lower()
172  : name) == 0;
173 }
static bool isValidVerilogCharacterFirst(char ch)
Definition: SVDialect.cpp:111
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)
Definition: SVDialect.cpp:115
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.
Definition: DebugAnalysis.h:21
Return a StringSet that contains all of the reserved names (e.g.
Definition: SVDialect.cpp:53
static void * call()
Definition: SVDialect.cpp:54