The goal of this PR is to parse in FIRRTL debug source locations for module ports, and maintain them through the pipeline, eventually printing the locations as part of the port list. To accomplish this whole pipeline support, changes were required to the FIRRTL and HW dialects. The changes to HW modules motivated changes to the MSFT dialect to ensure that the generic module functionality still worked for both dialects. The port locations give better error messages when emitting a diagnostic on a block argument value.
The first design point is that I decided to support port locations on FIRRTL `FExtModuleOp`s. With regular modules, we can attach port locations to all the block arguments. For `FExtModuleOp`s we require a `portLocations` attribute of type `ArrayAttr<LocationAttr>` to track the port locations. To keep things simple, I decided to add the `portLocation` attribute to all kinds of FIRRTL modules. For regular `FModuleOp`s, we copy these locations into the block argument values and add a verifier to ensure that these are kept in sync.
The FIRRTL parser was storing the Module's location in each of the block arguments, despite having code for parsing port specific location information. It was modified to stop overriding the port's parsed location.
Port location information was added to the `FModuleLike` op interface.
Some internal FIRRTL helpers were refactored to have only common functionality, with `FModuleOp` handling the specifics of owning a region after calling the generic helpers.
The FIRRTL MLIR module printer was modified to print the debug locations when the `--mlir-print-debuginfo` option is specified. There appears to be a problem in the printer's support for debuginfo, and it will create attribute aliases for all locations even if it does not end up printing the location. To get around this, we query the OpPrinterFlags directly, which will be populated by the command line options. The downside of this approach is that if someone is programmatically modifying the printer's OpPrinterOptions, we will not respect those settings. I don't think this will be an issue in practice, but it would be nice to fix this upstream.
The FIRRTL IR module parser was modified to read in an optional source location when parsing the port list. If no location is found, it uses a location pointing to the MLIR file.
Dedup was modified to properly combine the location information of modules and their block arguments.
LowerTypes was modified to spread the port location information to each lowered port.
LowerToHW was modified to properly transfer the location information during lowering.
In the HW dialect, I continued the design point to allow port location information to be tracked by `hw.module.extern`, which required adding two attributes for tracking locations; an `argLocs` and a `resultLocs` attribute was added to HW modules.
Similar to the FIRRTL dialect many HW module helpers were updated to support these new attributes.
The HW pass StripDebugInfoWithPred now strips location information from the port location attributes.
The HW pass FlattenIO was modified to spread the locations to flattened ports the same way as LowerTypes, as well as fix the block locations which were removed by signature conversion.
HWArithToHWPass restores the block argument locations after SignatureConversion deletes them
ExportVerilog was updated to allow the printing of location attributes directly, instead of taking a set of operations. Some printer bugs were fixed here especially around consecutive 0-width ports, and some better alignment. See `test/Conversion/ExportVerilog/port-decl-sharing.mlir` for some tests. @dtzSiFive Will you please take a look at these changes, I see sometimes we are using nbsp and other times space literals and I don't know the difference.
ExportVerilog now always prints the closing `);` on a newline when there is a non-empty port-list. This was needed to support trailing location comments. Technically, we could still print it on the same line when location information is not emitted for the last port in the list, but I didn't consider it worth the effort. As an example:
```verilog
// Was:
module Foo(
output [3:0] if_0);
// Now:
module Foo(
output [3:0] if_0 // foo.scala:10:20
);
```
The MSFT and SystemC dialects has to be updated to support these new attributes. The MSFT module was updated to support the same form of location attributes as HW modules. SystemC modules are, for now, using the common functionality but throwing away the attributes. This way, we could maintain a common set of code for creating, parsing, printing, updating modules.
Added a verifier to the MSFTModuleOp that made sure that the location attributes matched the block argument attributes
The ESI ESIPortsPass was updated to spread the locations of `ChannelTypes` to the ready/valid ports it lowers them to.
MSFTPartition pass now preserves the location information.
The python bindings were updated to attach these new attributes to `HWModuleOp`s. These location always default to `unkown`, for the time being. Since `LocationAttr`s are not represented in the upstream MLIR API, we had to create the attribute by calling out to the MLIR parser.