Skip to content

Commit

Permalink
Plugin generation of Bundle elements is now mandatory
Browse files Browse the repository at this point in the history
This required implementing _elementsImpl manually for all HWTuple
classes (which do not have the plugin run on them).
  • Loading branch information
jackkoenig committed May 26, 2022
1 parent a386c31 commit 5810f1c
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 58 deletions.
1 change: 0 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ lazy val chisel = (project in file("."))
.settings(
mimaPreviousArtifacts := Set(),
libraryDependencies += defaultVersions("treadle") % "test",
Test / scalacOptions += "-P:chiselplugin:genBundleElements",
Test / scalacOptions ++= Seq("-language:reflectiveCalls"),
Compile / doc / scalacOptions ++= Seq(
"-diagrams",
Expand Down
2 changes: 1 addition & 1 deletion build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class chisel3CrossModule(val crossScalaVersion: String) extends CommonModule wit
}

override def scalacOptions = T {
super.scalacOptions() ++ Agg(s"-Xplugin:${plugin.jar().path}", "-P:chiselplugin:genBundleElements")
super.scalacOptions() ++ Agg(s"-Xplugin:${plugin.jar().path}")
}

object stdlib extends CommonModule {
Expand Down
60 changes: 11 additions & 49 deletions core/src/main/scala/chisel3/Aggregate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1198,11 +1198,11 @@ package experimental {
* }}}
*/
abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
assert(
_usingPlugin,

private def mustUsePluginMsg: String =
"The Chisel compiler plugin is now required for compiling Chisel code. " +
"Please see https://github.com/chipsalliance/chisel3#build-your-own-chisel-projects."
)
assert(_usingPlugin, mustUsePluginMsg)

override def className: String = this.getClass.getSimpleName match {
case name if name.startsWith("$anon$") => "AnonymousBundle" // fallback for anonymous Bundle case
Expand All @@ -1228,14 +1228,7 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
* assert(uint === "h12345678".U) // This will pass
* }}}
*/
final lazy val elements: SeqMap[String, Data] =
// _elementsImpl is a method, only call it once
_elementsImpl match {
// Those not using plugin-generated _elementsImpl use the old reflective implementation
case oldElements: VectorMap[_, _] => oldElements.asInstanceOf[VectorMap[String, Data]]
// Plugin-generated _elementsImpl are incomplete and need some processing
case rawElements => _processRawElements(rawElements)
}
final lazy val elements: SeqMap[String, Data] = _processRawElements(_elementsImpl)

// The compiler plugin is imperfect at picking out elements statically so we process at runtime
// checking for errors and filtering out mistakes
Expand Down Expand Up @@ -1284,44 +1277,13 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
}: _*)
}

/* The old, reflective implementation of Bundle.elements
* This method is optionally overwritten by the compiler plugin for much better performance
*/
protected def _elementsImpl: Iterable[(String, Any)] = {
val nameMap = LinkedHashMap[String, Data]()
for (m <- getPublicFields(classOf[Bundle])) {
getBundleField(m) match {
case Some(d: Data) =>
requireIsChiselType(d)

if (nameMap contains m.getName) {
require(nameMap(m.getName) eq d)
} else {
nameMap(m.getName) = d
}
case None =>
if (!ignoreSeq) {
m.invoke(this) match {
case s: scala.collection.Seq[Any] if s.nonEmpty =>
s.head match {
// Ignore empty Seq()
case d: Data =>
throwException(
"Public Seq members cannot be used to define Bundle elements " +
s"(found public Seq member '${m.getName}'). " +
"Either use a Vec if all elements are of the same type, or MixedVec if the elements " +
"are of different types. If this Seq member is not intended to construct RTL, mix in the trait " +
"IgnoreSeqInBundle."
)
case _ => // don't care about non-Data Seq
}
case _ => // not a Seq
}
}
}
}
VectorMap(nameMap.toSeq.sortWith { case ((an, a), (bn, b)) => (a._id > b._id) || ((a eq b) && (an > bn)) }: _*)
}
/** This method is implemented by the compiler plugin
*
* @note For some reason, the Scala compiler errors on child classes if this method is made
* virtual. It appears that the way the plugin implements this method is insufficient for
* implementing virtual methods. It is probably better kept concrete for future refactoring.
*/
protected def _elementsImpl: Iterable[(String, Any)] = throwException(mustUsePluginMsg)

/**
* Overridden by [[IgnoreSeqInBundle]] to allow arbitrary Seqs of Chisel elements.
Expand Down
72 changes: 72 additions & 0 deletions core/src/main/scala/chisel3/experimental/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ package object experimental {
// Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
override protected def _usingPlugin: Boolean = true
override protected def _cloneTypeImpl: Bundle = new HWTuple2(chiselTypeClone(_1), chiselTypeClone(_2))
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2
)
}

/** [[Data]] equivalent of Scala's [[Tuple3]]
Expand All @@ -237,6 +241,11 @@ package object experimental {
chiselTypeClone(_2),
chiselTypeClone(_3)
)
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2,
"_3" -> _3
)
}

/** [[Data]] equivalent of Scala's [[Tuple4]]
Expand All @@ -258,6 +267,12 @@ package object experimental {
chiselTypeClone(_3),
chiselTypeClone(_4)
)
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2,
"_3" -> _3,
"_4" -> _4
)
}

/** [[Data]] equivalent of Scala's [[Tuple5]]
Expand All @@ -281,6 +296,13 @@ package object experimental {
chiselTypeClone(_4),
chiselTypeClone(_5)
)
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2,
"_3" -> _3,
"_4" -> _4,
"_5" -> _5
)
}

/** [[Data]] equivalent of Scala's [[Tuple6]]
Expand All @@ -306,6 +328,14 @@ package object experimental {
chiselTypeClone(_5),
chiselTypeClone(_6)
)
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2,
"_3" -> _3,
"_4" -> _4,
"_5" -> _5,
"_6" -> _6
)
}

/** [[Data]] equivalent of Scala's [[Tuple7]]
Expand Down Expand Up @@ -341,6 +371,15 @@ package object experimental {
chiselTypeClone(_6),
chiselTypeClone(_7)
)
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2,
"_3" -> _3,
"_4" -> _4,
"_5" -> _5,
"_6" -> _6,
"_7" -> _7
)
}

/** [[Data]] equivalent of Scala's [[Tuple8]]
Expand Down Expand Up @@ -379,6 +418,16 @@ package object experimental {
chiselTypeClone(_7),
chiselTypeClone(_8)
)
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2,
"_3" -> _3,
"_4" -> _4,
"_5" -> _5,
"_6" -> _6,
"_7" -> _7,
"_8" -> _8
)
}

/** [[Data]] equivalent of Scala's [[Tuple9]]
Expand Down Expand Up @@ -420,6 +469,17 @@ package object experimental {
chiselTypeClone(_8),
chiselTypeClone(_9)
)
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2,
"_3" -> _3,
"_4" -> _4,
"_5" -> _5,
"_6" -> _6,
"_7" -> _7,
"_8" -> _8,
"_9" -> _9
)
}

/** [[Data]] equivalent of Scala's [[Tuple9]]
Expand Down Expand Up @@ -464,5 +524,17 @@ package object experimental {
chiselTypeClone(_9),
chiselTypeClone(_10)
)
override protected def _elementsImpl: Iterable[(String, Any)] = Vector(
"_1" -> _1,
"_2" -> _2,
"_3" -> _3,
"_4" -> _4,
"_5" -> _5,
"_6" -> _6,
"_7" -> _7,
"_8" -> _8,
"_9" -> _9,
"_10" -> _10
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,7 @@ private[plugin] class BundleComponent(val global: Global, arguments: ChiselPlugi
/* Test to see if the bundle found is amenable to having it's elements
* converted to an immediate form that will not require reflection
*/
def isSupportedBundleType: Boolean = {
arguments.genBundleElements && !bundle.mods.hasFlag(Flag.ABSTRACT)
}
def isSupportedBundleType: Boolean = !bundle.mods.hasFlag(Flag.ABSTRACT)

val elementsImplOpt = if (isSupportedBundleType) {
/* extract the true fields from the super classes a given bundle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import scala.reflect.internal.util.NoPosition
import scala.collection.mutable

private[plugin] case class ChiselPluginArguments(
val skipFiles: mutable.HashSet[String] = mutable.HashSet.empty,
var genBundleElements: Boolean = false) {
val skipFiles: mutable.HashSet[String] = mutable.HashSet.empty) {
def useBundlePluginOpt = "useBundlePlugin"
def useBundlePluginFullOpt = s"-P:${ChiselPlugin.name}:$useBundlePluginOpt"
def genBundleElementsOpt = "genBundleElements"
Expand Down Expand Up @@ -62,7 +61,7 @@ class ChiselPlugin(val global: Global) extends Plugin {
override def init(options: List[String], error: String => Unit): Boolean = {
for (option <- options) {
if (option == arguments.useBundlePluginOpt) {
val msg = s"'${arguments.useBundlePluginFullOpt}' is now default behavior, you can stop using the scalacOption."
val msg = s"'${arguments.useBundlePluginFullOpt}' is now default behavior, you can remove the scalacOption."
global.reporter.warning(NoPosition, msg)
} else if (option.startsWith(arguments.skipFilePluginOpt)) {
val filename = option.stripPrefix(arguments.skipFilePluginOpt)
Expand All @@ -71,7 +70,8 @@ class ChiselPlugin(val global: Global) extends Plugin {
val msg = s"Option -P:${ChiselPlugin.name}:$option should only be used for internal chisel3 compiler purposes!"
global.reporter.warning(NoPosition, msg)
} else if (option == arguments.genBundleElementsOpt) {
arguments.genBundleElements = true
val msg = s"'${arguments.genBundleElementsOpt}' is now default behavior, you can remove the scalacOption."
global.reporter.warning(NoPosition, msg)
} else {
error(s"Option not understood: '$option'")
}
Expand Down

0 comments on commit 5810f1c

Please sign in to comment.