diff options
| author | Jack Koenig | 2021-02-11 18:12:48 -0800 |
|---|---|---|
| committer | Jack Koenig | 2021-03-12 16:16:45 -0800 |
| commit | 1494231212425fd09f915d819102ca5cdef0dfcf (patch) | |
| tree | 2828c723f881775bff0978592e07d3d52d78d4a9 /core/src/main | |
| parent | e80e9a3ba775efd2121b17a39b6d712e1cf8fac2 (diff) | |
[plugin] Implement autoclonetype in the compiler plugin
Diffstat (limited to 'core/src/main')
| -rw-r--r-- | core/src/main/scala/chisel3/Aggregate.scala | 56 | ||||
| -rw-r--r-- | core/src/main/scala/chisel3/internal/Builder.scala | 8 |
2 files changed, 50 insertions, 14 deletions
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index 6942313e..30276230 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -798,6 +798,13 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { case _ => None } + /** Indicates if a concrete Bundle class was compiled using the compiler plugin + * + * Used for optimizing Chisel's performance and testing Chisel itself + * @note This should not be used in user code! + */ + protected def _usingPlugin: Boolean = false + // Memoize the outer instance for autoclonetype, especially where this is context-dependent // (like the outer module or enclosing Bundles). private var _outerInst: Option[Object] = None @@ -808,7 +815,33 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { private val _containingModule: Option[BaseModule] = Builder.currentModule private val _containingBundles: Seq[Bundle] = Builder.updateBundleStack(this) - override def cloneType : this.type = { + private def checkClone(clone: Bundle): Unit = { + for ((name, field) <- elements) { + if (clone.elements(name) eq field) { + throw new AutoClonetypeException( + s"Automatically cloned $clone has field '$name' aliased with base $this." + + " In the future, this will be solved automatically by the compiler plugin." + + " For now, ensure Chisel types used in the Bundle definition are passed through constructor arguments," + + " or wrapped in Input(...), Output(...), or Flipped(...) if appropriate." + + " As a last resort, you can override cloneType manually." + ) + } + } + + } + + override def cloneType: this.type = { + val clone = _cloneTypeImpl.asInstanceOf[this.type] + checkClone(clone) + clone + } + + /** Implementation of cloneType using runtime reflection. This should _never_ be overridden or called in user-code + * + * @note This is overridden by the compiler plugin (it is never called when using the plugin) + */ + protected def _cloneTypeImpl: Bundle = { + assert(Builder.allowReflectiveAutoCloneType, "reflective autoclonetype is disallowed, this should only happen in testing") // This attempts to infer constructor and arguments to clone this Bundle subtype without // requiring the user explicitly overriding cloneType. import scala.language.existentials @@ -816,24 +849,19 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { val clazz = this.getClass - def autoClonetypeError(desc: String): Nothing = { - throw new AutoClonetypeException(s"Unable to automatically infer cloneType on $clazz: $desc") - } + def autoClonetypeError(desc: String): Nothing = + throw new AutoClonetypeException( + s"Unable to automatically infer cloneType on $clazz. " + + "cloneType is now implemented by the Chisel compiler plugin so please ensure you are using it in your build. " + + "If you cannot use the compiler plugin or you are using it and you still see this message, please file an issue and let us know. " + + s"For those not using the plugin, here is the 'runtime reflection' cloneType error message: $desc" + ) def validateClone(clone: Bundle, equivDiagnostic: String): Unit = { if (!clone.typeEquivalent(this)) { autoClonetypeError(s"Automatically cloned $clone not type-equivalent to base $this. " + equivDiagnostic) } - - for ((name, field) <- elements) { - if (clone.elements(name) eq field) { - autoClonetypeError(s"Automatically cloned $clone has field $name aliased with base $this." + - " In the future, this can be solved by wrapping the field in Field(...)," + - " see https://github.com/freechipsproject/chisel3/pull/909." + - " For now, ensure Chisel types used in the Bundle definition are passed through constructor arguments," + - " or wrapped in Input(...), Output(...), or Flipped(...) if appropriate.") - } - } + checkClone(clone) } val mirror = runtimeMirror(clazz.getClassLoader) diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index e95384cd..b1016a2e 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -311,6 +311,8 @@ private[chisel3] class DynamicContext(val annotationSeq: AnnotationSeq) { val components = ArrayBuffer[Component]() val annotations = ArrayBuffer[ChiselAnnotation]() var currentModule: Option[BaseModule] = None + // This is only used for testing, it can be removed if the plugin becomes mandatory + var allowReflectiveAutoCloneType = true /** Contains a mapping from a elaborated module to their aspect * Set by [[ModuleAspect]] @@ -530,6 +532,12 @@ private[chisel3] object Builder extends LazyLogging { dynamicContext.currentReset = newReset } + // This should only be used for testing + def allowReflectiveAutoCloneType: Boolean = dynamicContext.allowReflectiveAutoCloneType + def allowReflectiveAutoCloneType_=(value: Boolean): Unit = { + dynamicContext.allowReflectiveAutoCloneType = value + } + def forcedClock: Clock = currentClock.getOrElse( throwException("Error: No implicit clock.") ) |
