summaryrefslogtreecommitdiff
path: root/plugin/src/main/scala-2.12
diff options
context:
space:
mode:
authorJack Koenig2020-09-15 11:28:12 -0700
committerGitHub2020-09-15 11:28:12 -0700
commitb4f2b7acb2ea69dac116efed3ff873356d14b015 (patch)
tree47adece2457e61808d3ba779c56c7b4154e0114c /plugin/src/main/scala-2.12
parent69e27b2fd9e02d4e3a024eec0cafce5b4b46c10a (diff)
Improve performance of ChiselPlugin (#1590)
Use caching to reduce number of expensive lookups
Diffstat (limited to 'plugin/src/main/scala-2.12')
-rw-r--r--plugin/src/main/scala-2.12/chisel3/internal/plugin/ChiselPlugin.scala87
1 files changed, 54 insertions, 33 deletions
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 2197430c..6e4f3ece 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
@@ -9,6 +9,8 @@ import nsc.plugins.PluginComponent
import scala.reflect.internal.Flags
import scala.tools.nsc.transform.TypingTransformers
+import scala.collection.mutable
+
// The plugin to be run by the Scala compiler during compilation of Chisel code
class ChiselPlugin(val global: Global) extends Plugin {
val name = "chiselplugin"
@@ -37,11 +39,12 @@ class ChiselComponent(val global: Global) extends PluginComponent with TypingTra
class MyTypingTransformer(unit: CompilationUnit)
extends TypingTransformer(unit) {
- // Determines if the chisel plugin should match on this type
- def shouldMatch(q: Type, bases: Seq[Tree]): Boolean = {
+ private def shouldMatchGen(bases: Tree*): ValDef => Boolean = {
+ val cache = mutable.HashMap.empty[Type, Boolean]
+ val baseTypes = bases.map(inferType)
- // If subtype of Data or BaseModule, its a match!
- def terminate(t: Type): Boolean = bases.exists { base => t <:< inferType(base) }
+ // If subtype of one of the base types, it's a match!
+ def terminate(t: Type): Boolean = baseTypes.exists(t <:< _)
// Recurse through subtype hierarchy finding containers
// Seen is only updated when we recurse into type parameters, thus it is typically small
@@ -68,21 +71,31 @@ class ChiselComponent(val global: Global) extends PluginComponent with TypingTra
!(t.matchesPattern(inferType(tq"Iterable[_]")) || t.matchesPattern(inferType(tq"Option[_]")))
}
- // First check if a match, then check early exit, then recurse
- if(terminate(q)){
- true
- } else if(earlyExit(q)) {
- false
- } else {
- recShouldMatch(q, Set.empty)
+ // Return function so that it captures the cache
+ { p: ValDef =>
+ val q = inferType(p.tpt)
+ cache.getOrElseUpdate(q, {
+ // First check if a match, then check early exit, then recurse
+ if(terminate(q)){
+ true
+ } else if(earlyExit(q)) {
+ false
+ } else {
+ recShouldMatch(q, Set.empty)
+ }
+ })
}
}
+ private val shouldMatchData : ValDef => Boolean = shouldMatchGen(tq"chisel3.Data")
+ private val shouldMatchDataOrMem : ValDef => Boolean = shouldMatchGen(tq"chisel3.Data", tq"chisel3.MemBase[_]")
+ private val shouldMatchModule : ValDef => Boolean = shouldMatchGen(tq"chisel3.experimental.BaseModule")
+
// Given a type tree, infer the type and return it
- def inferType(t: Tree): Type = localTyper.typed(t, nsc.Mode.TYPEmode).tpe
+ private def inferType(t: Tree): Type = localTyper.typed(t, nsc.Mode.TYPEmode).tpe
// Indicates whether a ValDef is properly formed to get name
- def okVal(dd: ValDef, bases: Tree*): Boolean = {
+ private def okVal(dd: ValDef): Boolean = {
// These were found through trial and error
def okFlags(mods: Modifiers): Boolean = {
@@ -102,35 +115,43 @@ class ChiselComponent(val global: Global) extends PluginComponent with TypingTra
case Literal(Constant(null)) => true
case _ => false
}
- okFlags(dd.mods) && shouldMatch(inferType(dd.tpt), bases) && !isNull && dd.rhs != EmptyTree
+
+ okFlags(dd.mods) && !isNull && dd.rhs != EmptyTree
}
// Whether this val is directly enclosed by a Bundle type
- def inBundle(dd: ValDef): Boolean = {
+ private def inBundle(dd: ValDef): Boolean = {
dd.symbol.logicallyEnclosingMember.thisType <:< inferType(tq"chisel3.Bundle")
}
// Method called by the compiler to modify source tree
override def transform(tree: Tree): Tree = tree match {
+ // Check if a subtree is a candidate
+ case dd @ ValDef(mods, name, tpt, rhs) if okVal(dd) =>
// If a Data and in a Bundle, just get the name but not a prefix
- case dd @ ValDef(mods, name, tpt, rhs) if okVal(dd, tq"chisel3.Data") && inBundle(dd) =>
- val TermName(str: String) = name
- val newRHS = transform(rhs)
- val named = q"chisel3.internal.plugin.autoNameRecursively($str, $newRHS)"
- treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
- // If a Data or a Memory, get the name and a prefix
- case dd @ ValDef(mods, name, tpt, rhs) if okVal(dd, tq"chisel3.Data", tq"chisel3.MemBase[_]") =>
- val TermName(str: String) = name
- val newRHS = transform(rhs)
- val prefixed = q"chisel3.experimental.prefix.apply[$tpt](name=$str)(f=$newRHS)"
- val named = q"chisel3.internal.plugin.autoNameRecursively($str, $prefixed)"
- treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
- // If an instance, just get a name but no prefix
- case dd @ ValDef(mods, name, tpt, rhs) if okVal(dd, tq"chisel3.experimental.BaseModule") =>
- val TermName(str: String) = name
- val newRHS = transform(rhs)
- val named = q"chisel3.internal.plugin.autoNameRecursively($str, $newRHS)"
- treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
+ if (shouldMatchData(dd) && inBundle(dd)) {
+ val TermName(str: String) = name
+ val newRHS = transform(rhs) // chisel3.internal.plugin.autoNameRecursively
+ val named = q"chisel3.internal.plugin.autoNameRecursively($str, $newRHS)"
+ treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
+ }
+ // If a Data or a Memory, get the name and a prefix
+ else if (shouldMatchDataOrMem(dd)) {
+ val TermName(str: String) = name
+ val newRHS = transform(rhs)
+ val prefixed = q"chisel3.experimental.prefix.apply[$tpt](name=$str)(f=$newRHS)"
+ val named = q"chisel3.internal.plugin.autoNameRecursively($str, $prefixed)"
+ treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
+ // If an instance, just get a name but no prefix
+ } else if (shouldMatchModule(dd)) {
+ val TermName(str: String) = name
+ val newRHS = transform(rhs)
+ val named = q"chisel3.internal.plugin.autoNameRecursively($str, $newRHS)"
+ treeCopy.ValDef(dd, mods, name, tpt, localTyper typed named)
+ } else {
+ // Otherwise, continue
+ super.transform(tree)
+ }
// Otherwise, continue
case _ => super.transform(tree)
}