19#include "mlir/IR/Threading.h"
20#include "llvm/ADT/TypeSwitch.h"
25using namespace ExportVerilog;
36std::optional<std::pair<Operation *, StringAttr>>
38 Type type = field.getType().getValue();
39 while (
auto alias = dyn_cast<TypeAliasType>(type)) {
43 type = alias.getInnerType();
64 StringAttr newFieldName) {
79 if (!hasToBeRenamed) {
84 StringRef newFieldName =
88 auto newFieldNameAttr = StringAttr::get(fieldName.getContext(), newFieldName);
91 return newFieldNameAttr;
95 Operation *currentPackage) {
97 auto [package, name] = *field;
98 if (package != currentPackage)
99 return (
getSymOpName(package) +
"::" + name.getValue()).str();
100 return name.getValue().str();
103 auto aliasType = dyn_cast<hw::TypeAliasType>(attr.getType().getValue());
105 return attr.getField().getValue().str();
107 auto fieldStr = attr.getField().getValue().str();
109 return (prefix.getValue() +
"_" + fieldStr).str();
120namespace ExportVerilog {
140 void legalizeInterfaceNames(InterfaceOp interface);
141 void legalizePackageNames(PackageOp package);
142 void legalizeFunctionNames(FuncOp func);
145 void gatherEnumPrefixes(mlir::ModuleOp topLevel);
171 if (
auto hwModule = dyn_cast<hw::HWModuleOp>(*module))
172 for (
auto param : hwModule.getParameters())
174 module, cast<ParamDeclAttr>(param).getName()));
176 auto *ctxt =
module.getContext();
178 auto verilogNameAttr = StringAttr::get(ctxt,
"hw.verilogName");
180 auto ports =
module.getPortList();
181 SmallVector<Attribute> newNames(ports.size());
182 bool updated =
false;
183 bool isFuncOp = isa<FuncOp>(module);
184 for (
auto [idx, port] : llvm::enumerate(ports)) {
185 auto verilogName = port.attrs.get(verilogNameAttr);
188 if (isFuncOp && port.attrs.get(FuncOp::getExplicitlyReturnedAttrName())) {
190 newNames[idx] = StringAttr::get(ctxt,
getSymOpName(module));
194 auto newName = StringAttr::get(
195 ctxt, nameResolver.
getLegalName(cast<StringAttr>(verilogName)));
196 newNames[idx] = newName;
197 if (verilogName != newName)
201 auto oldName = ports[idx].name;
204 if (newName != oldName) {
205 newNames[idx] = StringAttr::get(ctxt, newName);
211 module.setPortAttrs(verilogNameAttr, newNames);
213 SmallVector<std::pair<Operation *, StringAttr>> nameEntries;
216 module.walk([&](Operation *op) {
219 if (auto name = op->getAttrOfType<StringAttr>(verilogNameAttr)) {
220 nameResolver.insertUsedName(
221 op->getAttrOfType<StringAttr>(verilogNameAttr));
223 hw::InstanceOp, sv::InterfaceInstanceOp, sv::GenerateOp>(
226 nameEntries.emplace_back(
227 op, StringAttr::get(op->getContext(),
getSymOpName(op)));
228 }
else if (
auto forOp = dyn_cast<ForOp>(op)) {
229 nameEntries.emplace_back(op, forOp.getInductionVarNameAttr());
230 }
else if (
auto genForOp = dyn_cast<GenerateForOp>(op)) {
231 nameEntries.emplace_back(op, genForOp.getInductionVarNameAttr());
232 }
else if (isa<AssertOp, AssumeOp, CoverOp, AssertConcurrentOp,
233 AssumeConcurrentOp, CoverConcurrentOp, AssertPropertyOp,
234 AssumePropertyOp, CoverPropertyOp, verif::AssertOp,
235 verif::CoverOp, verif::AssumeOp>(op)) {
237 if (
auto labelAttr = op->getAttrOfType<StringAttr>(
"label"))
238 nameEntries.emplace_back(op, labelAttr);
239 else if (options.enforceVerifLabels) {
242 StringRef defaultName =
243 llvm::TypeSwitch<Operation *, StringRef>(op)
244 .Case<AssertOp, AssertConcurrentOp, AssertPropertyOp,
245 verif::AssertOp>([](
auto) {
return "assert"; })
246 .Case<CoverOp, CoverConcurrentOp, CoverPropertyOp,
247 verif::CoverOp>([](
auto) {
return "cover"; })
248 .Case<AssumeOp, AssumeConcurrentOp, AssumePropertyOp,
249 verif::AssumeOp>([](
auto) {
return "assume"; });
250 nameEntries.emplace_back(
251 op, StringAttr::get(op->getContext(), defaultName));
257 for (
auto [op, nameAttr] : nameEntries) {
258 auto newName = nameResolver.getLegalName(nameAttr);
259 assert(!newName.empty() &&
"must have a valid name");
261 op->setAttr(verilogNameAttr, nameAttr.getValue() == newName
263 : StringAttr::
get(ctxt, newName));
271 : globalNameResolver(options), options(options) {
276 for (
auto &op : *topLevel.getBody()) {
279 if (isa<HWModuleExternOp>(op) || isa<HWModuleGeneratedOp>(op)) {
282 op.emitError(
"name \"")
283 << name <<
"\" is not allowed in Verilog output";
285 }
else if (
auto reservedNamesOp = dyn_cast<sv::ReserveNamesOp>(op)) {
286 for (StringAttr name :
287 reservedNamesOp.getReservedNames().getAsRange<StringAttr>()) {
295 for (
auto &op : *topLevel.getBody()) {
296 if (
auto module = dyn_cast<HWModuleOp>(op)) {
303 if (
auto interface = dyn_cast<InterfaceOp>(op)) {
308 if (
auto package = dyn_cast<PackageOp>(op))
313 mlir::parallelForEach(
314 topLevel.getContext(), topLevel.getOps<HWEmittableModuleLike>(),
316 legalizeModuleLocalNames(module, options, globalNameTable);
324 auto *ctx = package.getContext();
326 package->setAttr(
"hw.verilogName", StringAttr::get(ctx, name));
333 auto preferredName = decl.getPreferredName();
335 if (name != preferredName)
336 decl.setVerilogNameAttr(StringAttr::get(ctx, name));
339 auto enumType = dyn_cast<hw::EnumType>(decl.getType());
342 for (
auto field : enumType.getFields().getAsRange<StringAttr>()) {
344 (decl.getPreferredName() +
"_" + field.getValue()).str());
346 package, StringAttr::get(ctx, name)};
353 auto *ctx = topLevel.getContext();
356 auto enumType = dyn_cast<hw::EnumType>(typeDecl.getType());
363 StringAttr::get(ctx, typeDecl.getPreferredName());
372 MLIRContext *ctxt =
module.getContext();
375 StringRef oldName =
module.getName();
377 if (newName != oldName)
378 module->setAttr("verilogName", StringAttr::get(ctxt, newName));
382 for (
auto param :
module.getParameters()) {
383 auto paramAttr = cast<ParamDeclAttr>(param);
384 auto newName = nameResolver.
getLegalName(paramAttr.getName());
385 if (newName != paramAttr.getName().getValue())
391 MLIRContext *ctxt = interface.getContext();
392 auto verilogNameAttr = StringAttr::get(ctxt,
"hw.verilogName");
394 if (newName != interface.getName())
395 interface->setAttr(verilogNameAttr, StringAttr::get(ctxt, newName));
399 for (
auto &op : *interface.getBodyBlock()) {
400 if (isa<InterfaceSignalOp, InterfaceModportOp>(op)) {
401 auto name = SymbolTable::getSymbolName(&op).getValue();
404 op.setAttr(verilogNameAttr, StringAttr::get(ctxt, newName));
410 MLIRContext *ctxt = func.getContext();
411 if (
auto verilogName = func.getVerilogName()) {
416 if (newName != func.getName()) {
417 func.setVerilogName(StringAttr::get(ctxt, newName));
assert(baseType &&"element must be base type")
static StringRef legalizeName(StringRef name, llvm::StringMap< size_t > &nextGeneratedNameIDs)
Legalize the given name such that it only consists of valid identifier characters in Verilog and does...
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 legalizePackageNames(PackageOp package)
GlobalNameResolver(mlir::ModuleOp topLevel, const LoweringOptions &options)
Construct a GlobalNameResolver and perform name legalization of the module/interfaces,...
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.
DenseMap< StringAttr, StringAttr > renamedFieldNames
Those contain entries for field names and types respectively.
StringAttr getRenamedFieldName(StringAttr fieldName)
const LoweringOptions & options
void setRenamedFieldName(StringAttr fieldName, StringAttr newFieldName)
const GlobalNameTable & globalNames
std::string getEnumFieldName(hw::EnumFieldAttr attr, Operation *currentPackage=nullptr)
Returns the field name for an enum field of a given enum field attr.
llvm::StringMap< size_t > nextGeneratedNameIDs
A map from used names to numeric suffix used as uniquification agent when resolving conflicts.
llvm::StringMap< size_t > nextGeneratedNameIDs
A map from used names to numeric suffix used as uniquification agent when resolving conflicts.
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,...
const LoweringOptions & options
Handle to LoweringOptions.
Options which control the emission from CIRCT to Verilog.
bool caseInsensitiveKeywords
If true, then unique names that collide with keywords case insensitively.