19#include "mlir/IR/Threading.h"
20#include "llvm/ADT/TypeSwitch.h"
26using namespace ExportVerilog;
37std::optional<std::pair<Operation *, StringAttr>>
39 Type type = field.getType().getValue();
40 while (
auto alias = dyn_cast<TypeAliasType>(type)) {
44 type = alias.getInnerType();
65 StringAttr newFieldName) {
80 if (!hasToBeRenamed) {
85 StringRef newFieldName =
89 auto newFieldNameAttr = StringAttr::get(fieldName.getContext(), newFieldName);
92 return newFieldNameAttr;
96 Operation *currentPackage) {
98 auto [package, name] = *field;
99 if (package != currentPackage)
100 return (
getSymOpName(package) +
"::" + name.getValue()).str();
101 return name.getValue().str();
104 auto aliasType = dyn_cast<hw::TypeAliasType>(attr.getType().getValue());
106 return attr.getField().getValue().str();
108 auto fieldStr = attr.getField().getValue().str();
110 return (prefix.getValue() +
"_" + fieldStr).str();
121namespace ExportVerilog {
141 void legalizeInterfaceNames(InterfaceOp interface);
142 template <
typename Package>
143 void legalizePackageNames(Package package);
144 void legalizeFunctionNames(FuncOp func);
147 void gatherEnumPrefixes(mlir::ModuleOp topLevel);
173 if (
auto hwModule = dyn_cast<hw::HWModuleOp>(*module))
174 for (
auto param : hwModule.getParameters())
176 module, cast<ParamDeclAttr>(param).getName()));
178 auto *ctxt =
module.getContext();
180 auto verilogNameAttr = StringAttr::get(ctxt,
"hw.verilogName");
182 auto ports =
module.getPortList();
183 SmallVector<Attribute> newNames(ports.size());
184 bool updated =
false;
185 bool isFuncOp = isa<FuncOp>(module);
186 for (
auto [idx, port] : llvm::enumerate(ports)) {
187 auto verilogName = port.attrs.get(verilogNameAttr);
190 if (isFuncOp && port.attrs.get(FuncOp::getExplicitlyReturnedAttrName())) {
192 newNames[idx] = StringAttr::get(ctxt,
getSymOpName(module));
196 auto newName = StringAttr::get(
197 ctxt, nameResolver.
getLegalName(cast<StringAttr>(verilogName)));
198 newNames[idx] = newName;
199 if (verilogName != newName)
203 auto oldName = ports[idx].name;
206 if (newName != oldName) {
207 newNames[idx] = StringAttr::get(ctxt, newName);
213 module.setPortAttrs(verilogNameAttr, newNames);
215 SmallVector<std::pair<Operation *, StringAttr>> nameEntries;
218 module.walk([&](Operation *op) {
221 if (auto name = op->getAttrOfType<StringAttr>(verilogNameAttr)) {
222 nameResolver.insertUsedName(
223 op->getAttrOfType<StringAttr>(verilogNameAttr));
225 LocalParamOp, hw::InstanceOp, sv::InterfaceInstanceOp,
226 sv::GenerateOp>(op)) {
228 nameEntries.emplace_back(
229 op, StringAttr::get(op->getContext(),
getSymOpName(op)));
230 }
else if (
auto forOp = dyn_cast<ForOp>(op)) {
231 nameEntries.emplace_back(op, forOp.getInductionVarNameAttr());
232 }
else if (
auto genForOp = dyn_cast<GenerateForOp>(op)) {
233 nameEntries.emplace_back(op, genForOp.getInductionVarNameAttr());
234 }
else if (isa<AssertOp, AssumeOp, CoverOp, AssertConcurrentOp,
235 AssumeConcurrentOp, CoverConcurrentOp, AssertPropertyOp,
236 AssumePropertyOp, CoverPropertyOp, verif::AssertOp,
237 verif::CoverOp, verif::AssumeOp>(op)) {
239 if (
auto labelAttr = op->getAttrOfType<StringAttr>(
"label"))
240 nameEntries.emplace_back(op, labelAttr);
241 else if (options.enforceVerifLabels) {
244 StringRef defaultName =
245 llvm::TypeSwitch<Operation *, StringRef>(op)
246 .Case<AssertOp, AssertConcurrentOp, AssertPropertyOp,
247 verif::AssertOp>([](
auto) {
return "assert"; })
248 .Case<CoverOp, CoverConcurrentOp, CoverPropertyOp,
249 verif::CoverOp>([](
auto) {
return "cover"; })
250 .Case<AssumeOp, AssumeConcurrentOp, AssumePropertyOp,
251 verif::AssumeOp>([](
auto) {
return "assume"; });
252 nameEntries.emplace_back(
253 op, StringAttr::get(op->getContext(), defaultName));
259 for (
auto [op, nameAttr] : nameEntries) {
260 auto newName = nameResolver.getLegalName(nameAttr);
261 assert(!newName.empty() &&
"must have a valid name");
263 op->setAttr(verilogNameAttr, nameAttr.getValue() == newName
265 : StringAttr::
get(ctxt, newName));
273 : globalNameResolver(options), options(options) {
279 for (
auto &op : *topLevel.getBody()) {
282 if (isa<HWModuleExternOp, HWModuleGeneratedOp, PackageExternOp>(op)) {
283 auto name = isa<PackageExternOp>(op) ?
getSymOpName(&op)
286 op.emitError(
"name \"")
287 << name <<
"\" is not allowed in Verilog output";
289 }
else if (
auto reservedNamesOp = dyn_cast<sv::ReserveNamesOp>(op)) {
290 for (StringAttr name :
291 reservedNamesOp.getReservedNames().getAsRange<StringAttr>()) {
299 for (
auto &op : *topLevel.getBody()) {
300 if (
auto module = dyn_cast<HWModuleOp>(op)) {
307 if (
auto interface = dyn_cast<InterfaceOp>(op)) {
312 if (
auto package = dyn_cast<PackageOp>(op))
314 else if (
auto package = dyn_cast<PackageExternOp>(op))
319 mlir::parallelForEach(
320 topLevel.getContext(), topLevel.getOps<HWEmittableModuleLike>(),
322 legalizeModuleLocalNames(module, options, globalNameTable);
329template <
typename Package>
331 auto *ctx = package.getContext();
332 if constexpr (!std::is_same_v<Package, PackageExternOp>) {
334 package->setAttr(
"hw.verilogName", StringAttr::get(ctx, name));
341 for (
hw::TypedeclOp decl : package.template getOps<hw::TypedeclOp>()) {
342 auto preferredName = decl.getPreferredName();
344 if (name != preferredName)
345 decl.setVerilogNameAttr(StringAttr::get(ctx, name));
347 for (
hw::TypedeclOp decl : package.template getOps<hw::TypedeclOp>()) {
348 auto enumType = dyn_cast<hw::EnumType>(decl.getType());
351 for (
auto field : enumType.getFields().getAsRange<StringAttr>()) {
353 (decl.getPreferredName() +
"_" + field.getValue()).str());
355 package, StringAttr::get(ctx, name)};
362 auto *ctx = topLevel.getContext();
365 auto enumType = dyn_cast<hw::EnumType>(typeDecl.getType());
372 StringAttr::get(ctx, typeDecl.getPreferredName());
381 MLIRContext *ctxt =
module.getContext();
384 StringRef oldName =
module.getName();
386 if (newName != oldName)
387 module->setAttr("verilogName", StringAttr::get(ctxt, newName));
391 for (
auto param :
module.getParameters()) {
392 auto paramAttr = cast<ParamDeclAttr>(param);
393 auto newName = nameResolver.
getLegalName(paramAttr.getName());
394 if (newName != paramAttr.getName().getValue())
400 MLIRContext *ctxt = interface.getContext();
401 auto verilogNameAttr = StringAttr::get(ctxt,
"hw.verilogName");
403 if (newName != interface.getName())
404 interface->setAttr(verilogNameAttr, StringAttr::get(ctxt, newName));
408 for (
auto &op : *interface.getBodyBlock()) {
409 if (isa<InterfaceSignalOp, InterfaceModportOp>(op)) {
410 auto name = SymbolTable::getSymbolName(&op).getValue();
413 op.setAttr(verilogNameAttr, StringAttr::get(ctxt, newName));
419 MLIRContext *ctxt = func.getContext();
420 if (
auto verilogName = func.getVerilogName()) {
425 if (newName != func.getName()) {
426 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()
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
void legalizePackageNames(Package package)
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.
StringRef getVerilogModuleName(Operation *module)
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.