-
Notifications
You must be signed in to change notification settings - Fork 309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[InstanceChoice] Add the instance choice specialization pass to firtool #7933
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, please update capi as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The roughly sister pass of this is SpecializeLayers
and that went a slightly different direction than adding an option. Instead that puts the information directly onto the CircuitOp
via a mandatory attribute.
While I can't recall the exact reasons for this design point, consistency between the two approaches may be good.
@youngar or @rwy7: Do you have any thoughts about the above?
include/circt/Firtool/Firtool.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please have the PR reflect any changes to this file in the corresponding area of the C-API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to figure out the corresponding type for ArrayRef
in C-API, any idea ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any uses of ArrayRef
for the C-API. This may need to get funneled through an ArrayAttr
.
if (it == selected.end()) { | ||
inst.emitError("missing specialization for option ") | ||
target = inst.getDefaultTargetAttr(); | ||
inst->emitWarning("missing specialization for option ") | ||
<< inst.getOptionNameAttr(); | ||
failed = true; | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize that this all-or-nothing behavior is originally how this worked.
However, it seems odd to force a user to specialize everything or nothing as opposed to just specializing what the user requested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the current implementation, the user need not specialize everything, it would be lowered to the default target, if nothing is specified for an instance choice. The user can specify only the choices that are relevant, and the rest can be lowered to the default target.
test/firtool/instchoice.fir
Outdated
@@ -26,6 +28,8 @@ circuit Foo: | |||
; CHECK-SAME: @FPGA -> @FPGATarget, | |||
; CHECK-SAME: @ASIC -> @ASICTarget | |||
; CHECK-SAME: } (in clock: !firrtl.clock) | |||
; ASIC: hw.instance "inst" @ASICTarget(clock: %clock: !seq.clock) -> () | |||
; DEFAULT: hw.instance "inst" @DefaultTarget(clock: %clock: !seq.clock) -> () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 Making the default behavior be "replace instance choices with the default" also seems slightly odd. It seems like the default should be "do nothing". I realize that instance choice is unusable right now unless specialization of every option is run, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it depends on how we define it, the default target, for an instance choice can be defined as the target when no option is specified. Also, if nothing is done here, when should the instance choice be handled in the pipeline ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If no default is specified, then the instance choice gets lowered to how the FIRRTL ABI defines this lowering. (This is not specified right now. However, I have one such ABI PR'd here: chipsalliance/firrtl-spec#155.)
The underlying problem is that instance choice was only handled for this narrow, internal use case of CIRCT choosing a value for all instance choices as opposed to the more general user request for Verilog elaboration-time selection. 🥲
The motivation here is more about aligning this with how layers are enabled and disabled, e.g., --enable-layer=Verification
specializes away the Verification
layer, but it leaves any other layers in place. It would seem better to have instance choice specialization work the same way, e.g., --specialize-instance-choice=Performance=ASIC
would not affect any other instance choice in the circuit.
We do want to move in this direction. However, we don't have to move there right now with this PR.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this makes more sense, but i'm assuming you meant to write:
--specialize-instance-choice=Platform=ASIC
To specify which target is being specialized?
Also, not to derail this (and i see there was some discussion of this in the spec PR) but it is useful to be able to specialize different instances of the same instance_choice
to write miter-style circuits for testing the choices themselves (esp. when they are used in part of a larger circuit under test). I guess here it might just be fine to do the specialization at VCS-compile time though. For this reason i also like that default be explicitly named (as also discussed in the spec PR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in the short run, we'd need a flag to achieve the effect of specializing all modules to their default and just provide that when we're passing in circuits that contain instance choices for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this makes more sense, but i'm assuming you meant to write:
--specialize-instance-choice=Platform=ASIC
To specify which target is being specialized?
Yes!
it is useful to be able to specialize different instances of the same instance_choice to write miter-style circuits for testing the choices themselves (esp. when they are used in part of a larger circuit under test)
Per-instance specialization currently works. It does create a blow-up in the number of options. This is an intentional choice that complicates the design. E.g., consider instance choice used in a multicore design to replace a core with a model. The designer needs to decide what swapping flexibility they want to have. If they want to have complete flexibility to swap every core arbitrarily in an n-core design, that would have to be n-different options. They likely don't want that and will choose to have one instance choice which swaps all of the cores except one.
I'd prefer to not support arbitrary per-instance after-the-fact specialization as that amounts to mandated module duplication which then has interactions with must-dedup and designer expectations around deduplication. I'm more comfortable with this if CIRCT-mandated deduplication (must-dedup) is removed.
So in the short run, we'd need a flag to achieve the effect of specializing all modules to their default and just provide that when we're passing in circuits that contain instance choices for now?
I'm good with either:
- All instance choice specializations are specified up front.
- There is a catch-all
-specialize-to-default-if-no-override
which will, after applying selected choices, will then convert everything to the default choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After more thought, i think strictness of (1) is probably desirable to avoid accidental footguns? We can always add the flag later. I'll defer to you and @prithayan on this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've decided to go with the option 1, unless all the instance choice specializations are specified, the pass will error out.
Once the lowering of instance choice through the pipeline to verilog is supported, we can get rid of the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if you went with (1) how do you specialize to Default
?
97e1d40
to
10b0ec9
Compare
@@ -89,12 +85,24 @@ struct SpecializeOptionPass | |||
}); | |||
}); | |||
|
|||
bool analysisPreserved = numInstances == 0; | |||
circuit->walk([&](OptionOp optionOp) { | |||
optionOp->erase(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seldridge , @uenoku , just wanted to make sure, this makes sense right ?
The OptionOp
wouldn't be useful for any other passes downstream, even if we ignore an InstanceChoiceOp
, when it is not specialized, and left in IR after this pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would only be safe for options that were specialized. If any InstanceChoiceOp
is left in, e.g., if the circuit is partially instance-choice specialized, then this would create an invalid symbol reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that makes sense. But since, there are no other passes that can handle the OptionOp
maybe its okay to delete them. And this pass also errors out on partially specified instance choice. WDYT ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the other passes are supposed to handle these things, just it's not implemented, yet. 🫠 The concern is more about if this pass is guaranteed to specialize away everything (which we eventually don't want), then it's fine. However, if it is going to leave anything in, then it shouldn't delete everything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, for now, this pass currently doesn't leave any InstanceChoiceOp
, it should error out if a choice is not selected. So, it should be fine to delete it.
But the first pass that needs to handle OptionOp
is LowerToHW
, there is no HW
counterpart for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep... just showing something end-to-end would be cool. FWIW, I am totally fine with LowerToHW
erroring with "unsupported operation". That's all part of getting a feature turned on incrementally. 😉
f57693f
to
393da2d
Compare
PR is ready for another review, @uenoku , @seldridge please take a look if you get a chance.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Some comments/nits throughout.
Can the PR add a test of the error behavior if the specialization is not fully specified?
393da2d
to
5034c95
Compare
Thanks for the review and discussion everyone. I'm planning to split this into a separate PR for the parser changes and will merge them as two commits. |
5034c95
to
383b91b
Compare
👍 Always feel empowered to slice things up into smaller commit chunks. 💯 |
This PR adds the instance choice specialization pass to the
firtool
pipeline.Add optional arguments to
firtool
to select the specialization option for the instance choice.Then update the pass to use the default module, when no options are specified.
Update lit tests to check for valid instance choice lowering.