Skip to content

Make it possible to illegalize .asUInt on OpaqueTypes#3344

Merged
jackkoenig merged 2 commits intomainfrom
jackkoenig/opaque-type-asuint
Jun 21, 2023
Merged

Make it possible to illegalize .asUInt on OpaqueTypes#3344
jackkoenig merged 2 commits intomainfrom
jackkoenig/opaque-type-asuint

Conversation

@jackkoenig
Copy link
Contributor

I also split the OpaqueType tests out of RecordSpec since we would like to make OpaqueTypes "opaquer" which ultimately means making them no longer be Records.

Contributor Checklist

  • Did you add Scaladoc to every public function/method?
  • Did you add at least one test demonstrating the PR?
  • Did you delete any extraneous printlns/debugging code?
  • Did you specify the type of improvement?
  • Did you add appropriate documentation in docs/src?
  • Did you request a desired merge strategy?
  • Did you add text to be included in the Release Notes for this change?

Type of Improvement

  • Feature (or new API)

Desired Merge Strategy

  • Squash

Release Notes

Subclasses of OpaqueType can override errorOnAsUInt to make it an elaboration time error if .asUInt is called on an instance of the particular type (including when nested inside of an Aggregate). This closes a large loophole in the OpaqueType API.

Reviewer Checklist (only modified by reviewer)

  • Did you add the appropriate labels? (Select the most appropriate one based on the "Type of Improvement")
  • Did you mark the proper milestone (Bug fix: 3.5.x or 3.6.x depending on impact, API modification or big change: 5.0.0)?
  • Did you review?
  • Did you check whether all relevant Contributor checkboxes have been checked?
  • Did you do one of the following when ready to merge:
    • Squash: You/ the contributor Enable auto-merge (squash), clean up the commit message, and label with Please Merge.
    • Merge: Ensure that contributor has cleaned up their commit history, then merge with Create a merge commit.

@jackkoenig jackkoenig added the Feature New feature, will be included in release notes label Jun 8, 2023
@jackkoenig jackkoenig added this to the 6.0 milestone Jun 8, 2023
*
* Users can override this to increase the "opacity" of their type.
*/
protected def errorOnAsUInt: Boolean = false
Copy link
Contributor

Choose a reason for hiding this comment

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

perhaps they could override it with a string message...? so you could say something like

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 think you lost the second half of that sentence.

We could make the String message customizable, I'm curious what API you have in mind. I think the current error message is pretty good, eg. from the tests (admittedly hard to see since I also moved a bunch, but see the end of OpaqueTypeSpec.scala): "Field '_.bits' of type MaybeNoAsUInt does not support .asUInt.". That Arg.earlyLocalName trick is very much a private API and IMO you wouldn't want to lose that "coordinate" information when overriding the error message.

mwachs5
mwachs5 previously approved these changes Jun 8, 2023
@jackkoenig jackkoenig force-pushed the jackkoenig/opaque-type-asuint branch from 6913848 to 0c41a39 Compare June 13, 2023 01:03
Comment on lines +48 to +70
behavior.of("Empty Aggregates")

they should "have a width of 0" in {
assertKnownWidth(0) {
Wire(Vec(0, UInt(8.W)))
}
assertKnownWidth(0) {
Wire(new EmptyBundle)
}
}

// This is a bug that has existed for basically forever
// This really should be assertKnownWidth(0)
they should "result in a 1-bit UInt when calling .asUInt" in {
assertInferredWidth(1) {
val x = Wire(Vec(0, UInt(8.W))).asUInt
WireInit(x)
}
assertInferredWidth(1) {
val x = Wire(new EmptyBundle).asUInt
WireInit(x)
}
}
Copy link
Contributor Author

@jackkoenig jackkoenig Jun 13, 2023

Choose a reason for hiding this comment

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

My original change resulted in some surprising test failures and exposed some concerning buggy behavior. As shown here, if you call .asUInt on an empty Aggregate, you get 0.U which is 0.U(1.W). Fortunately, when these empty Aggregates are part of larger Aggregates, they are flattened out (as zero-width wires), but in the special case of just .asUInt on a empty Aggregate, this is what happens.

This is definitely a bug, obviously it should hold that x.getWidth == x.asUInt.getWidth, but such width issues are tricky to change. This one derives from calling SeqUtils.asUInt which is the same reason why Cat(Seq()) returns 0.U (which again is 0.U(1.W)).

I think it's reasonable to fix this particular bug while leaving the Cat and other similar cases alone, but such changes are a little sketchy because it can result in width changes for downstream things and thus silently change behavior. In particular, it's scary if generator code is concatenating the result of .asUInt on a Vec that can be parameterized all the way down to size 0, or similarly with a Record or Bundle that could be empty.

Thoughts @aswaterman @azidar @seldridge @mwachs5?

Copy link
Contributor Author

@jackkoenig jackkoenig Jun 13, 2023

Choose a reason for hiding this comment

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

In any case, this PR is not really intended to be concerned with the concerning behavior and just documents and maintains the existing behavior.

Copy link
Member

Choose a reason for hiding this comment

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

obviously it should hold that x.getWidth == x.asUInt.getWidth

I think this is the overriding concern and fixing it is worth the pain.

@jackkoenig jackkoenig requested a review from mwachs5 June 13, 2023 01:09
@jackkoenig jackkoenig dismissed mwachs5’s stale review June 13, 2023 01:10

This PR has changed a little, not functionally but it does highlight some weird behavior.

@jackkoenig jackkoenig mentioned this pull request Jun 14, 2023
14 tasks
@jackkoenig jackkoenig force-pushed the jackkoenig/opaque-type-asuint branch from 0c41a39 to b69fa37 Compare June 21, 2023 20:22
Subclasses of OpaqueType can override errorOnAsUInt to make it an
elaboration time error if .asUInt is called on an instance of the
particular type (including when nested inside of an Aggregate). This
closes a large loophole in the OpaqueType API.
@jackkoenig jackkoenig force-pushed the jackkoenig/opaque-type-asuint branch from b69fa37 to d57ae63 Compare June 21, 2023 20:45
@jackkoenig jackkoenig merged commit b192815 into main Jun 21, 2023
@jackkoenig jackkoenig deleted the jackkoenig/opaque-type-asuint branch June 21, 2023 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature New feature, will be included in release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants