CIRCT  19.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...
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
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