Skip to content

Conversation

@tmckay-sifive
Copy link
Contributor

@tmckay-sifive tmckay-sifive commented Nov 13, 2025

A second attempt of #9131. Changes from the first PR were made in order to support parametrized black boxes. Because parameters can affect the port interface of a module, we need two ops:

  1. sv.verbatim.source to represent the shared verbatim definition of a module
  2. sv.verbatim.module to represent a particular parametrization of that module that can be instantiated

The pipeline is largely the same:

  • BlackBoxInlineAnno and BlackBoxPathAnno are converted to VerbatimBlackBoxAnno by BlackBoxReader for consumption by LowerToHW.
  • LowerToHW will lower firrtl.extmodules with a VerbatimBlackBoxAnno to a sv.verbatim.source (only one per file) and a sv.verbatim.module.

@tmckay-sifive tmckay-sifive marked this pull request as ready for review November 13, 2025 23:00
Comment on lines +215 to +217
def SVVerbatimSourceOp
: SVOp<"verbatim.source", [Symbol, HasParent<"mlir::ModuleOp">,
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this seems weird to put this in SVTypeDecl.td. Usually these would go in an SVStructure.td.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found no SVStructure.td file and thought it would be most appropriate alongside the existing op definitions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extreme nit: This is over 80 column. 😉

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice adherence to 80 column!

Comment on lines +41 to +43
// Duplicated extmodule definitions to the same output file. This can
// happen when generators produce definitions of an inline black box
// under each of multiple deduping scopes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test looks fantastic!

Copy link
Member

@seldridge seldridge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Ping me when you want a merge if you haven't, yet, gained commit access.

Comment on lines +215 to +217
def SVVerbatimSourceOp
: SVOp<"verbatim.source", [Symbol, HasParent<"mlir::ModuleOp">,
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extreme nit: This is over 80 column. 😉

Comment on lines +220 to +222
The "sv.verbatim.source" operation represents verbatim verilog definition for
a module which may have parameters. Concrete parametrizations and their ports
are represented by a `hw.module.extern`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

80-column. 😉

Comment on lines +281 to +282
portAttrs.push_back(port.attrs ? port.attrs : $_builder.getDictionaryAttr({}));
portLocs.push_back(port.loc ? static_cast<Location>(port.loc) : $_builder.getUnknownLoc());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

80 column.

Comment on lines +380 to +381
auto it = verbatimSourcesByFileName.find(fileName);
return it != verbatimSourcesByFileName.end() ? it->second : nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work instead?

Suggested change
auto it = verbatimSourcesByFileName.find(fileName);
return it != verbatimSourcesByFileName.end() ? it->second : nullptr;
return verbatimSourcesByFileName.return(fileName);

Ditto throughout.

void registerVerbatimSource(StringRef fileName,
sv::SVVerbatimSourceOp verbatimOp) {
llvm::sys::SmartScopedLock<true> lock(verbatimSourcesMutex);
verbatimSourcesByFileName[fileName] = verbatimOp;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could overwrite. Is that fine?

Also, is it legal for verbatimOp to be null here?

The latter would usually be handled with an assert if it is some assumption that isn't supposed to be violated generally.

Comment on lines +1207 to +1211
StringRef verilogName;
if (auto defName = oldModule.getDefname())
verilogName = defName.value();
else
verilogName = oldModule.getName();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely, I think #9233 will clean this up.

Comment on lines +1371 to +1378
/*builder=*/builder,
/*location=*/oldModule.getLoc(),
/*name=*/builder.getStringAttr(oldModule.getName()),
/*ports=*/ports,
/*source=*/FlatSymbolRefAttr::get(verbatimSource),
/*parameters=*/parameters ? parameters : builder.getArrayAttr({}),
/*verilogName=*/verilogName.empty() ? StringAttr{}
: builder.getStringAttr(verilogName));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nicely readable to me! Thanks!

Comment on lines +182 to +183
llvm::MapVector<Operation *, SmallVector<StringAttr>>
verbatimExtmoduleToFiles;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider llvm::MapVector<Operation *, SmallVector<StringRef>>.

This is a micro-optimization, but should be lower overhead so long as you can guarantee that the backing string will not go out of scope!. I think this is safe as the backing thing here should be a StringAttr for some Operation which can't go out of scope. (Famous last words...)

Comment on lines +132 to +135
if parameters is not None:
attributes["parameters"] = parameters
else:
attributes["parameters"] = ArrayAttr.get([])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this could be pre-allocated as [] and then appended to.

@seldridge seldridge merged commit f63ea4d into llvm:main Nov 18, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants