-
Notifications
You must be signed in to change notification settings - Fork 602
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
Refactor Annotations #767
Refactor Annotations #767
Conversation
This still uses LegacyAnnotations and so also serves to test the LegacyAnnotation support in Firrtl
This allows us to delay creation of Annotations till elaboration is complete. Also update all annotation-related code.
TODO
|
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.
Looks sane, I had some thoughts about naming APIs.
What's the rationale for LazyAnnotation? Is lazy simply an implementation detail that users don't need to care about, or does it affect the behavior of the API?
@@ -129,6 +133,11 @@ private[chisel3] trait HasId extends InstanceId { | |||
case Some(p) => p.name | |||
case None => throwException(s"$instanceName doesn't have a parent") | |||
} | |||
// TODO Should this be public? |
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.
For Testers, we do need an API to get the FIRRTL name of a Chisel object. How that should be done (through DataMirror maybe?) and specifics (name qualified up to which level? Top? User-defined root?) are questions though.
/** Holds the implementation of toNamed for Data and MemBase */ | ||
private[chisel3] trait NamedComponent extends HasId { | ||
/** Returns a FIRRTL ComponentName that references this object | ||
* @note Should not be called until circuit elaboration is complete |
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.
Perhaps not a now thing, but can we relax when this can be called? For example, it should be possible to get the name of any bound wire, assuming it's properly named (instead of T_, which is kind of meaningless anyways) - though we might need to ensure that these names can't be mangled in the future. Going up the module chain also presents difficulties in this case, you never know when an enclosing module might not have a proper name.
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 making it possible to eagerly access the names of things is desirable but it's a non-trivial undertaking. We would need to ensure that querying the name of something does not impact the result. For example:
class NamingTop extends RawModule {
val w = Wire(UInt(8.W)).suggestName("foo")
w.getName // ???
val foo = IO(Input(UInt(8.W)))
w := foo
}
Currently, w
gets the name foo_1
because ports always win. We would need to be sure that calling getName
did not accidentally change this.
Doing this with reflection also sounds... dangerous. Perhaps we could make @chiselName
disable the reflection-based naming and make eager-naming a feature of using @chiselName
?
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 still can't say I'm a fan of an API that depends so much on mutable state where access can be unsafe. Are there other possible APIs, like ChiselAnnotation.toFirrtl taking in a object that can remap a component to a name?
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.
What is the difference between putting the code here in NamedComponent
vs. in ChiselAnnotation
? In either case, getting a Firrtl Named
from a Chisel object relies on mutable state in that object that isn't set until the end of elaboration. This PR is not changing anything about that aspect of Chisel's implementation.
Lazy seems like "we're abusing this Scala language feature because we're too lazy [heh] to write the plumbing properly" and not balancing the usability / learnability concerns with the implementation effort, probably partially because we're Scala power users and kind of feel that users are also at a similar level. I think the general convention for lazy evaluation is not that it gives you a different result because of execution order, but it gives you the same result with different performance characteristics. In other words, with few exceptions (for example, infinite lists), lazy is supposed to give the same result as the non-lazy version, which is not the case here. For this PR in particular, I think Lazy is meant to be a way to get the target name, right? Can we not leave the serialization of the annotation (which is where the name is needed) to the FIRRTL emit stage, passing in a Chisel Data/Module/... reference at the annotation stage? My experience is that the |
I agree this is kind of an abuse of the term "lazy". It would probably be better to be more explicit and call it something like I designed this to require the minimum amount of boiler plate for annotation writers. Using a reference to the Chisel object is possible, but in my opinion it leads to a worse overall API. I'll lay out the two ways I have thought of to do it that way:
// Consider some Annotation with associated information
case class MyAnnotation(target: ComponentName, info: Map[String, Int]) extends SingleTargetAnno[ComponentName] {
def duplicate(n: ComponentName) = this.copy(target = n)
}
// I could duplicate the datastructure to also support a Chisel Data
case class MyAnnotation2(target: Data, info: Map[String, Int]) {
// I would also have to call out what other annotation it should correspond to,
// and AFAIK it's impossible to have static type safety that this class corresponds to the other one
def companionAnno = classOf[MyAnnotation]
}
This one is probably better but has some potential issues. I could open up the Named in Firrtl (it's currently sealed) to allow Chisel types to extend it. If we want any type safety, we'd have My main issue with 2. is that there's a bit of magic going on behind the scenes. I suspect that people could run into subtle issues trying to match on Chisel types in Firrtl transformations (which would actually work so long as you didn't serialize between Chisel and Firrtl!) The proposal on this PR is the least magical and most explicit way to do it. Sure, |
Use a Chisel-specific RunFirrtlTransform API to preserve behavior of old ChiselAnnotation (now called ChiselLegacyAnnotation)
Updated this with a more explicit I also add RunFirrtlTransform to preserve behavior of Driver.execute instantiating Firrtl transforms associated with a given Annotation. |
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.
Two comments
object identify { | ||
def apply(component: InstanceId, value: String): Unit = { | ||
val anno = IdentityChiselAnnotation(component, value) | ||
annotate(anno) |
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.
Why is annotate called twice?
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.
Mistakenly left an old API, fixed
/** Holds the implementation of toNamed for Data and MemBase */ | ||
private[chisel3] trait NamedComponent extends HasId { | ||
/** Returns a FIRRTL ComponentName that references this object | ||
* @note Should not be called until circuit elaboration is complete |
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 still can't say I'm a fan of an API that depends so much on mutable state where access can be unsafe. Are there other possible APIs, like ChiselAnnotation.toFirrtl taking in a object that can remap a component to a name?
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.
looks good, current understanding is that order-dependent stuff will fail noisily if invoked improperly.
retest this please |
Can any one reproduce the failure I'm seeing on Jenkins ( |
[info] DontTouchSpec:
[info] Dead code
[info] - should be removed by default *** FAILED ***
[info] "module HasDeadCodeChild( // @[:@3.2]
[info] input [31:0] io_a, // @[:@6.4]
[info] output [31:0] io_b, // @[:@6.4]
[info] output [31:0] io_c_0, // @[:@6.4]
[info] output [31:0] io_c_1 // @[:@6.4]
[info] );
[info] assign io_b = io_a;
[info] assign io_c_0 = 32'h0;
[info] assign io_c_1 = 32'h0;
[info] endmodule
[info] module HasDeadCode( // @[:@12.2]
[info] input clock, // @[:@13.4]
[info] input reset, // @[:@14.4]
[info] input [31:0] io_a, // @[:@15.4]
[info] output [31:0] io_b // @[:@15.4]
[info] );
[info] wire [31:0] inst_io_a; // @[DontTouchSpec.scala 27:20:@17.4]
[info] wire [31:0] inst_io_b; // @[DontTouchSpec.scala 27:20:@17.4]
[info] wire [31:0] inst_io_c_0; // @[DontTouchSpec.scala 27:20:@17.4]
[info] wire [31:0] inst_io_c_1; // @[DontTouchSpec.scala 27:20:@17.4]
[info] wire [32:0] _T_10; // @[DontTouchSpec.scala 30:28:@22.4]
[info] wire [31:0] _T_11; // @[DontTouchSpec.scala 30:28:@23.4]
[info] wire [31:0] dead; // @[:@24.4]
[info] HasDeadCodeChild inst ( // @[DontTouchSpec.scala 27:20:@17.4]
[info] .io_a(inst_io_a),
[info] .io_b(inst_io_b),
[info] .io_c_0(inst_io_c_0),
[info] .io_c_1(inst_io_c_1)
[info] );
[info] assign _T_10 = io_a + 32'h1; // @[DontTouchSpec.scala 30:28:@22.4
]
[info] assign _T_11 = _T_10[31:0]; // @[DontTouchSpec.scala 30:28:@23.4]
[info] assign dead = _T_11; // @[:@24.4]
[info] assign io_b = inst_io_b;
[info] assign inst_io_a = io_a;
[info] endmodule
[info] " included substring "io_c_0" (DontTouchSpec.scala:45)
[info] - should NOT be removed if marked dontTouch
[info] Dont touch
[info] - should only work on bound hardware
…On Wed, Feb 28, 2018 at 12:03 PM, Jack Koenig ***@***.***> wrote:
Can any one reproduce the failure I'm seeing on Jenkins (DontTouchSpec
failing)? I can't seem to reproduce it.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#767 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AGh1wNuwmVO7YYgOs7ZpuYdrp4NywW6eks5tZbETgaJpZM4RvCx2>
.
|
Well, ensuring the tests each had their own test directory fixed the problem 🤷♀️. Anyway for rocket-chip bumping reasons, I'm going to merge #788 first. Then I'll merge this. |
* Update in light of annotations refactor. Fix for chipsalliance/firrtl#721 and chipsalliance/chisel#767. * Respond to review comments - simplify annotations.
* Update in light of annotations refactor. Fix for chipsalliance/firrtl#721 and #767. * Respond to review comments - simplify annotations.
This makes it much easier to write annotations. As an example, check out identity annotation from the tests:
This is a companion to chipsalliance/firrtl#721
Type of change
Impact
Development Phase
Release Notes
ChiselAnnotation
in favor ofLazyAnnotation
.Module.annotate
in favor ofobject annotate
.toNamed
toInstanceId
so that we can easily generate Firrtl references to Chisel objects.