19 #include "mlir/IR/Threading.h"
20 #include "llvm/ADT/TypeSwitch.h"
22 using namespace circt;
25 using namespace ExportVerilog;
33 StringRef NameCollisionResolver::getLegalName(StringRef originalName) {
35 options.caseInsensitiveKeywords);
42 void FieldNameResolver::setRenamedFieldName(StringAttr fieldName,
43 StringAttr newFieldName) {
44 renamedFieldNames[fieldName] = newFieldName;
45 nextGeneratedNameIDs.insert({newFieldName, 0});
48 StringAttr FieldNameResolver::getRenamedFieldName(StringAttr fieldName) {
49 auto it = renamedFieldNames.find(fieldName);
50 if (it != renamedFieldNames.end())
55 !
sv::isNameValid(fieldName.getValue(), options.caseInsensitiveKeywords) ||
56 nextGeneratedNameIDs.contains(fieldName.getValue());
58 if (!hasToBeRenamed) {
59 setRenamedFieldName(fieldName, fieldName);
63 StringRef newFieldName =
65 options.caseInsensitiveKeywords);
67 auto newFieldNameAttr =
StringAttr::get(fieldName.getContext(), newFieldName);
69 setRenamedFieldName(fieldName, newFieldNameAttr);
70 return newFieldNameAttr;
73 std::string FieldNameResolver::getEnumFieldName(hw::EnumFieldAttr attr) {
74 auto aliasType = attr.getType().getValue().dyn_cast<hw::TypeAliasType>();
76 return attr.getField().getValue().str();
78 auto fieldStr = attr.getField().getValue().str();
79 if (
auto prefix = globalNames.getEnumPrefix(aliasType))
80 return (prefix.getValue() +
"_" + fieldStr).str();
91 namespace ExportVerilog {
111 void legalizeInterfaceNames(InterfaceOp interface);
114 void gatherEnumPrefixes(mlir::ModuleOp topLevel);
138 for (
auto param : module.getParameters())
140 module, param.cast<ParamDeclAttr>().getName()));
142 auto *ctxt = module.getContext();
146 auto ports = module.getPortList();
147 SmallVector<Attribute> newNames(ports.size());
148 bool updated =
false;
149 for (
auto [idx, port] : llvm::enumerate(ports)) {
150 auto verilogName = port.attrs.get(verilogNameAttr);
153 ctxt, nameResolver.
getLegalName(verilogName.cast<StringAttr>()));
154 newNames[idx] = newName;
155 if (verilogName != newName)
159 auto oldName = ports[idx].name;
162 if (newName != oldName) {
169 module.setPortAttrs(verilogNameAttr, newNames);
171 SmallVector<std::pair<Operation *, StringAttr>> nameEntries;
174 module.walk([&](Operation *op) {
175 if (!isa<HWModuleOp>(op)) {
177 if (
auto name = op->getAttrOfType<StringAttr>(verilogNameAttr)) {
178 nameResolver.insertUsedName(
179 op->getAttrOfType<StringAttr>(verilogNameAttr));
181 hw::InstanceOp, sv::InterfaceInstanceOp, sv::GenerateOp>(
184 nameEntries.emplace_back(
186 }
else if (
auto forOp = dyn_cast<ForOp>(op)) {
187 nameEntries.emplace_back(op, forOp.getInductionVarNameAttr());
188 }
else if (isa<AssertOp, AssumeOp, CoverOp, AssertConcurrentOp,
189 AssumeConcurrentOp, CoverConcurrentOp, verif::AssertOp,
190 verif::CoverOp, verif::AssumeOp>(op)) {
192 if (
auto labelAttr = op->getAttrOfType<StringAttr>(
"label"))
193 nameEntries.emplace_back(op, labelAttr);
197 StringRef defaultName =
198 llvm::TypeSwitch<Operation *, StringRef>(op)
199 .Case<AssertOp, AssertConcurrentOp, verif::AssertOp>(
200 [](auto) { return
"assert"; })
201 .Case<CoverOp, CoverConcurrentOp, verif::CoverOp>(
202 [](
auto) {
return "cover"; })
203 .Case<AssumeOp, AssumeConcurrentOp, verif::AssumeOp>(
204 [](
auto) {
return "assume"; });
205 nameEntries.emplace_back(
212 for (
auto [op, nameAttr] : nameEntries) {
213 auto newName = nameResolver.getLegalName(nameAttr);
214 assert(!newName.empty() &&
"must have a valid name");
216 op->setAttr(verilogNameAttr, nameAttr.getValue() == newName
224 GlobalNameResolver::GlobalNameResolver(mlir::ModuleOp topLevel,
226 : globalNameResolver(options), options(options) {
231 for (
auto &op : *topLevel.getBody()) {
234 if (isa<HWModuleExternOp>(op) || isa<HWModuleGeneratedOp>(op)) {
237 op.emitError(
"name \"")
238 << name <<
"\" is not allowed in Verilog output";
244 for (
auto &op : *topLevel.getBody()) {
245 if (
auto module = dyn_cast<HWModuleOp>(op)) {
252 if (
auto interface = dyn_cast<InterfaceOp>(op)) {
259 mlir::parallelForEach(
260 topLevel.getContext(), topLevel.getOps<
HWModuleOp>(), [&](
auto module) {
261 legalizeModuleLocalNames(module, options, globalNameTable);
270 auto *ctx = topLevel.getContext();
273 auto enumType = typeDecl.getType().dyn_cast<hw::EnumType>();
289 MLIRContext *ctxt = module.getContext();
292 StringRef oldName = module.getName();
294 if (newName != oldName)
299 for (
auto param : module.getParameters()) {
300 auto paramAttr = param.cast<ParamDeclAttr>();
301 auto newName = nameResolver.
getLegalName(paramAttr.getName());
302 if (newName != paramAttr.getName().getValue())
308 MLIRContext *ctxt = interface.getContext();
311 if (newName != interface.getName())
316 for (
auto &op : *interface.getBodyBlock()) {
317 if (isa<InterfaceSignalOp, InterfaceModportOp>(op)) {
318 auto name = SymbolTable::getSymbolName(&op).getValue();
assert(baseType &&"element must be base type")
static void legalizeModuleLocalNames(HWModuleOp module, const LoweringOptions &options, const GlobalNameTable &globalNameTable)
This class keeps track of modules and interfaces that need to be renamed, as well as module ports,...
GlobalNameTable globalNameTable
This keeps track of globally visible names like module parameters.
void legalizeModuleNames(HWModuleOp module)
Check to see if the port names of the specified module conflict with keywords or themselves.
GlobalNameTable takeGlobalNameTable()
void operator=(const GlobalNameResolver &)=delete
const LoweringOptions & options
void gatherEnumPrefixes(mlir::ModuleOp topLevel)
GlobalNameResolver(const GlobalNameResolver &)=delete
NameCollisionResolver globalNameResolver
Set of globally visible names, to ensure uniqueness.
void legalizeInterfaceNames(InterfaceOp interface)
GlobalNameTable legalizeGlobalNames(ModuleOp topLevel, const LoweringOptions &options)
Rewrite module names and interfaces to not conflict with each other or with Verilog keywords.
StringRef getSymOpName(Operation *symOp)
Return the verilog name of the operations that can define a symbol.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
StringAttr getVerilogModuleNameAttr(Operation *module)
Returns the verilog module name attribute or symbol name of any module-like operations.
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...
void insertUsedName(StringRef name)
Insert a string as an already-used name.
StringRef getLegalName(StringRef originalName)
Given a name that may have collisions or invalid symbols, return a replacement name to use,...
Options which control the emission from CIRCT to Verilog.
bool enforceVerifLabels
If true, verification statements like assert, assume, and cover will always be emitted with a label.
bool caseInsensitiveKeywords
If true, then unique names that collide with keywords case insensitively.