From 3bea6167159737b379f37031c3beef27337be06d Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 12 Mar 2021 15:33:58 -0800 Subject: [PATCH] [plugin] Disable BundleComponent by default, add option to enable --- build.sbt | 2 ++ .../internal/plugin/BundleComponent.scala | 15 +++++++++++-- .../internal/plugin/ChiselPlugin.scala | 21 ++++++++++++++++++- .../scala/chiselTests/AutoClonetypeSpec.scala | 21 +++++++++++++++++-- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index 5c051ff5e02..42fcece38b2 100644 --- a/build.sbt +++ b/build.sbt @@ -179,6 +179,8 @@ lazy val chisel = (project in file(".")). mimaPreviousArtifacts := Set(), libraryDependencies += defaultVersions("treadle") % "test", scalacOptions in Test ++= Seq("-language:reflectiveCalls"), + // Only used in Test for 3.4.x, used in Compile in 3.5 + scalacOptions in Test += "-P:chiselplugin:useBundlePlugin", scalacOptions in Compile in doc ++= Seq( "-diagrams", "-groups", diff --git a/plugin/src/main/scala-2.12/chisel3/internal/plugin/BundleComponent.scala b/plugin/src/main/scala-2.12/chisel3/internal/plugin/BundleComponent.scala index 0711e08c54f..96851e955b0 100644 --- a/plugin/src/main/scala-2.12/chisel3/internal/plugin/BundleComponent.scala +++ b/plugin/src/main/scala-2.12/chisel3/internal/plugin/BundleComponent.scala @@ -10,7 +10,9 @@ import scala.tools.nsc.symtab.Flags import scala.tools.nsc.transform.TypingTransformers // TODO This component could also implement val elements in Bundles -private[plugin] class BundleComponent(val global: Global) extends PluginComponent with TypingTransformers { +private[plugin] class BundleComponent(val global: Global, arguments: ChiselPluginArguments) + extends PluginComponent + with TypingTransformers { import global._ val phaseName: String = "chiselbundlephase" @@ -23,8 +25,17 @@ private[plugin] class BundleComponent(val global: Global) extends PluginComponen // This plugin doesn't work on Scala 2.11 nor Scala 3. Rather than complicate the sbt build flow, // instead we just check the version and if its an early Scala version, the plugin does nothing val scalaVersion = scala.util.Properties.versionNumberString.split('.') - if (scalaVersion(0).toInt == 2 && scalaVersion(1).toInt >= 12) { + val scalaVersionOk = scalaVersion(0).toInt == 2 && scalaVersion(1).toInt >= 12 + if (scalaVersionOk && arguments.useBundlePlugin) { unit.body = new MyTypingTransformer(unit).transform(unit.body) + } else { + val reason = if (!scalaVersionOk) { + s"invalid Scala version '${scala.util.Properties.versionNumberString}'" + } else { + s"not enabled via '${arguments.useBundlePluginFullOpt}'" + } + // Enable this with scalacOption '-Ylog:chiselbundlephase' + global.log(s"Skipping BundleComponent on account of $reason.") } } } diff --git a/plugin/src/main/scala-2.12/chisel3/internal/plugin/ChiselPlugin.scala b/plugin/src/main/scala-2.12/chisel3/internal/plugin/ChiselPlugin.scala index d5eb21cc26a..a0651e1d290 100644 --- a/plugin/src/main/scala-2.12/chisel3/internal/plugin/ChiselPlugin.scala +++ b/plugin/src/main/scala-2.12/chisel3/internal/plugin/ChiselPlugin.scala @@ -6,13 +6,32 @@ import scala.tools.nsc import nsc.Global import nsc.plugins.{Plugin, PluginComponent} +private[plugin] case class ChiselPluginArguments(var useBundlePlugin: Boolean = false) { + def useBundlePluginOpt = "useBundlePlugin" + def useBundlePluginFullOpt = s"-P:chiselplugin:$useBundlePluginOpt" +} + // The plugin to be run by the Scala compiler during compilation of Chisel code class ChiselPlugin(val global: Global) extends Plugin { val name = "chiselplugin" val description = "Plugin for Chisel 3 Hardware Description Language" + private val arguments = ChiselPluginArguments() val components: List[PluginComponent] = List[PluginComponent]( new ChiselComponent(global), - new BundleComponent(global) + new BundleComponent(global, arguments) ) + + override def init(options: List[String], error: String => Unit): Boolean = { + for (option <- options) { + if (option == arguments.useBundlePluginOpt) { + arguments.useBundlePlugin = true + } else { + error(s"Option not understood: '$option'") + } + } + true + } + + } diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala index a3da109a9d9..a6e5562a395 100644 --- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala +++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala @@ -4,6 +4,7 @@ package chiselTests import chisel3._ import chisel3.testers.TestUtils +import chisel3.util.QueueIO class BundleWithIntArg(val i: Int) extends Bundle { val out = UInt(i.W) @@ -65,6 +66,11 @@ class NestedAnonymousBundle extends Bundle { // Not necessarily good style (and not necessarily recommended), but allowed to preserve compatibility. class BundleWithArgumentField(val x: Data, val y: Data) extends Bundle +// Needs to be top-level so that reflective autoclonetype works +class InheritingBundle extends QueueIO(UInt(8.W), 8) { + val error = Output(Bool()) +} + // TODO all `.suggestNames` are due to https://github.com/chipsalliance/chisel3/issues/1802 class AutoClonetypeSpec extends ChiselFlatSpec with Utils { val usingPlugin: Boolean = TestUtils.usingPlugin @@ -253,10 +259,21 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils { elaborate(new MyModule(3)) } + behavior of "Compiler Plugin Autoclonetype" + + // Necessary test for 3.4.x, but we will break this (for non-plugin users) in 3.5 + it should "NOT break code that extends chisel3.util Bundles (whether they use the plugin or not)" in { + class MyModule extends MultiIOModule { + val io = IO(new InheritingBundle) + io.deq <> io.enq + io.count := 0.U + io.error := true.B + } + elaborate(new MyModule) + } + // New tests from the plugin if (usingPlugin) { - behavior of "Compiler Plugin Autoclonetype" - it should "support Bundles with non-val parameters" in { class MyBundle(i: Int) extends Bundle { val foo = UInt(i.W)