19 #include "mlir/IR/Threading.h"
20 #include "llvm/ADT/TypeSwitch.h"
22 using namespace circt;
25 using namespace ExportVerilog;
32 for (
auto &name : reservedNames)
42 StringRef NameCollisionResolver::getLegalName(StringRef originalName) {
44 options.caseInsensitiveKeywords);
51 void FieldNameResolver::setRenamedFieldName(StringAttr fieldName,
52 StringAttr newFieldName) {
53 renamedFieldNames[fieldName] = newFieldName;
54 nextGeneratedNameIDs.insert({newFieldName, 0});
57 StringAttr FieldNameResolver::getRenamedFieldName(StringAttr fieldName) {
58 auto it = renamedFieldNames.find(fieldName);
59 if (it != renamedFieldNames.end())
64 !
sv::isNameValid(fieldName.getValue(), options.caseInsensitiveKeywords) ||
65 nextGeneratedNameIDs.contains(fieldName.getValue());
67 if (!hasToBeRenamed) {
68 setRenamedFieldName(fieldName, fieldName);
72 StringRef newFieldName =
74 options.caseInsensitiveKeywords);
76 auto newFieldNameAttr =
StringAttr::get(fieldName.getContext(), newFieldName);
78 setRenamedFieldName(fieldName, newFieldNameAttr);
79 return newFieldNameAttr;
82 std::string FieldNameResolver::getEnumFieldName(hw::EnumFieldAttr attr) {
83 auto aliasType = dyn_cast<hw::TypeAliasType>(attr.getType().getValue());
85 return attr.getField().getValue().str();
87 auto fieldStr = attr.getField().getValue().str();
88 if (
auto prefix = globalNames.getEnumPrefix(aliasType))
89 return (prefix.getValue() +
"_" + fieldStr).str();
100 namespace ExportVerilog {
120 void legalizeInterfaceNames(InterfaceOp interface);
121 void legalizeFunctionNames(FuncOp func);
124 void gatherEnumPrefixes(mlir::ModuleOp topLevel);
150 if (
auto hwModule = dyn_cast<hw::HWModuleOp>(*module))
151 for (
auto param : hwModule.getParameters())
153 module, cast<ParamDeclAttr>(param).getName()));
155 auto *
ctxt = module.getContext();
159 auto ports = module.getPortList();
160 SmallVector<Attribute> newNames(ports.size());
161 bool updated =
false;
162 bool isFuncOp = isa<FuncOp>(module);
163 for (
auto [idx, port] : llvm::enumerate(ports)) {
164 auto verilogName = port.attrs.get(verilogNameAttr);
167 if (isFuncOp && port.attrs.get(FuncOp::getExplicitlyReturnedAttrName())) {
175 newNames[idx] = newName;
176 if (verilogName != newName)
180 auto oldName = ports[idx].name;
183 if (newName != oldName) {
190 module.setPortAttrs(verilogNameAttr, newNames);
192 SmallVector<std::pair<Operation *, StringAttr>> nameEntries;
195 module.walk([&](Operation *op) {
198 if (
auto name = op->getAttrOfType<StringAttr>(verilogNameAttr)) {
199 nameResolver.insertUsedName(
200 op->getAttrOfType<StringAttr>(verilogNameAttr));
202 hw::InstanceOp, sv::InterfaceInstanceOp, sv::GenerateOp>(
205 nameEntries.emplace_back(
207 }
else if (
auto forOp = dyn_cast<ForOp>(op)) {
208 nameEntries.emplace_back(op, forOp.getInductionVarNameAttr());
209 }
else if (isa<AssertOp, AssumeOp, CoverOp, AssertConcurrentOp,
210 AssumeConcurrentOp, CoverConcurrentOp, AssertPropertyOp,
211 AssumePropertyOp, CoverPropertyOp, verif::AssertOp,
212 verif::CoverOp, verif::AssumeOp>(op)) {
214 if (
auto labelAttr = op->getAttrOfType<StringAttr>(
"label"))
215 nameEntries.emplace_back(op, labelAttr);
219 StringRef defaultName =
220 llvm::TypeSwitch<Operation *, StringRef>(op)
221 .Case<AssertOp, AssertConcurrentOp, AssertPropertyOp,
222 verif::AssertOp>([](auto) { return
"assert"; })
223 .Case<CoverOp, CoverConcurrentOp, CoverPropertyOp,
224 verif::CoverOp>([](
auto) {
return "cover"; })
225 .Case<AssumeOp, AssumeConcurrentOp, AssumePropertyOp,
226 verif::AssumeOp>([](
auto) {
return "assume"; });
227 nameEntries.emplace_back(
234 for (
auto [op, nameAttr] : nameEntries) {
235 auto newName = nameResolver.getLegalName(nameAttr);
236 assert(!newName.empty() &&
"must have a valid name");
238 op->setAttr(verilogNameAttr, nameAttr.getValue() == newName
246 GlobalNameResolver::GlobalNameResolver(mlir::ModuleOp topLevel,
248 : globalNameResolver(options), options(options) {
253 for (
auto &op : *topLevel.getBody()) {
256 if (isa<HWModuleExternOp>(op) || isa<HWModuleGeneratedOp>(op)) {
259 op.emitError(
"name \"")
260 << name <<
"\" is not allowed in Verilog output";
262 }
else if (
auto reservedNamesOp = dyn_cast<sv::ReserveNamesOp>(op)) {
263 for (StringAttr name :
264 reservedNamesOp.getReservedNames().getAsRange<StringAttr>()) {
272 for (
auto &op : *topLevel.getBody()) {
273 if (
auto module = dyn_cast<HWModuleOp>(op)) {
280 if (
auto interface = dyn_cast<InterfaceOp>(op)) {
287 mlir::parallelForEach(
288 topLevel.getContext(), topLevel.getOps<HWEmittableModuleLike>(),
290 legalizeModuleLocalNames(module, options, globalNameTable);
299 auto *ctx = topLevel.getContext();
302 auto enumType = dyn_cast<hw::EnumType>(typeDecl.getType());
318 MLIRContext *
ctxt = module.getContext();
321 StringRef oldName = module.getName();
323 if (newName != oldName)
328 for (
auto param : module.getParameters()) {
329 auto paramAttr = cast<ParamDeclAttr>(param);
330 auto newName = nameResolver.
getLegalName(paramAttr.getName());
331 if (newName != paramAttr.getName().getValue())
337 MLIRContext *
ctxt = interface.getContext();
340 if (newName != interface.getName())
345 for (
auto &op : *interface.getBodyBlock()) {
346 if (isa<InterfaceSignalOp, InterfaceModportOp>(op)) {
347 auto name = SymbolTable::getSymbolName(&op).getValue();
356 MLIRContext *
ctxt = func.getContext();
357 if (
auto verilogName = func.getVerilogName()) {
362 if (newName != func.getName()) {
assert(baseType &&"element must be base type")
static void legalizeModuleLocalNames(HWEmittableModuleLike 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 legalizeFunctionNames(FuncOp func)
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...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
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.